Index: Source/core/layout/PendingSelection.cpp |
diff --git a/Source/core/layout/PendingSelection.cpp b/Source/core/layout/PendingSelection.cpp |
index e466c4875fc6602cefe0ba3e7f2a831d9900dcf5..6686a1033137fc52de3e9da9e78f27a0fd967d01 100644 |
--- a/Source/core/layout/PendingSelection.cpp |
+++ b/Source/core/layout/PendingSelection.cpp |
@@ -27,6 +27,7 @@ |
#include "core/editing/VisiblePosition.h" |
#include "core/editing/VisibleUnits.h" |
#include "core/html/HTMLTextFormControlElement.h" |
+#include "core/layout/LayoutView.h" |
namespace blink { |
@@ -105,11 +106,66 @@ VisibleSelection PendingSelection::calcVisibleSelectionAlgorithm() const |
return VisibleSelection(visibleStart, visibleEnd); |
} |
-VisibleSelection PendingSelection::calcVisibleSelection() const |
+template <typename Strategy> |
+void PendingSelection::commitAlgorithm(LayoutView& layoutView) |
+{ |
+ using PositionType = typename Strategy::PositionType; |
+ |
+ if (!hasPendingSelection()) |
+ return; |
+ ASSERT(!layoutView.needsLayout()); |
+ |
+ // Skip if pending VisibilePositions became invalid before we reach here. |
+ if (!isInDocument(layoutView.document())) { |
+ clear(); |
+ return; |
+ } |
+ |
+ // Construct a new VisibleSolution, since m_selection is not necessarily |
+ // valid, and the following steps assume a valid selection. |
+ // See <https://bugs.webkit.org/show_bug.cgi?id=69563> and |
+ // <rdar://problem/10232866>. |
+ VisibleSelection selection = calcVisibleSelectionAlgorithm<Strategy>(); |
+ clear(); |
+ |
+ if (!selection.isRange()) { |
+ layoutView.clearSelection(); |
+ return; |
+ } |
+ |
+ // Use the rightmost candidate for the start of the selection, and the |
+ // leftmost candidate for the end of the selection. Example: foo <a>bar</a>. |
+ // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. |
+ // If we pass [foo, 3] as the start of the selection, the selection painting |
+ // code will think that content on the line containing 'foo' is selected |
+ // and will fill the gap before 'bar'. |
+ PositionType startPos = Strategy::selectionStart(selection); |
+ PositionType candidate = mostForwardCaretPosition(startPos); |
+ if (isVisuallyEquivalentCandidate(candidate)) |
+ startPos = candidate; |
+ PositionType endPos = Strategy::selectionEnd(selection); |
+ candidate = mostBackwardCaretPosition(endPos); |
+ if (isVisuallyEquivalentCandidate(candidate)) |
+ endPos = candidate; |
+ |
+ // We can get into a state where the selection endpoints map to the same |
+ // |VisiblePosition| when a selection is deleted because we don't yet notify |
+ // the |FrameSelection| of text removal. |
+ if (startPos.isNull() || endPos.isNull() || Strategy::selectionVisibleStart(selection).deepEquivalent() == Strategy::selectionVisibleEnd(selection).deepEquivalent()) |
+ return; |
+ LayoutObject* startLayoutObject = startPos.anchorNode()->layoutObject(); |
+ LayoutObject* endLayoutObject = endPos.anchorNode()->layoutObject(); |
+ if (!startLayoutObject || !endLayoutObject) |
+ return; |
+ ASSERT(layoutView == startLayoutObject->view() && layoutView == endLayoutObject->view()); |
+ layoutView.setSelection(startLayoutObject, startPos.computeEditingOffset(), endLayoutObject, endPos.computeEditingOffset()); |
+} |
+ |
+void PendingSelection::commit(LayoutView& layoutView) |
{ |
if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
- return calcVisibleSelectionAlgorithm<VisibleSelection::InComposedTree>(); |
- return calcVisibleSelectionAlgorithm<VisibleSelection::InDOMTree>(); |
+ return commitAlgorithm<VisibleSelection::InComposedTree>(layoutView); |
+ commitAlgorithm<VisibleSelection::InDOMTree>(layoutView); |
} |
DEFINE_TRACE(PendingSelection) |