Index: third_party/WebKit/Source/core/editing/SelectionController.cpp |
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp |
index 7dfe9e618ad029cffd4d2e19734b020071e4ecb8..2f38f947937933a8b4b28ec8bedb4bb4cda567c6 100644 |
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp |
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp |
@@ -66,9 +66,10 @@ DEFINE_TRACE(SelectionController) |
namespace { |
-void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection) |
+template <typename Strategy> |
+void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelectionTemplate<Strategy>& newSelection) |
{ |
- if (equalSelectionsInDOMTree(selection.selection(), newSelection)) |
+ if (selection.visibleSelection<Strategy>() == newSelection) |
return; |
selection.setSelection(newSelection); |
} |
@@ -95,20 +96,6 @@ VisibleSelectionTemplate<Strategy> expandSelectionToRespectUserSelectAll(Node* t |
return newSelection; |
} |
-// TODO(yosin) |expandSelectionToRespectUserSelectAll()| with |VisibleSelection| |
-// should be removed once we have full version of |VisibleSelectionTemplate|. |
-static VisibleSelectionTemplate<EditingStrategy> expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) |
-{ |
- return expandSelectionToRespectUserSelectAll(targetNode, VisibleSelectionTemplate<EditingStrategy>(selection)); |
-} |
- |
-bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGranularity granularity) |
-{ |
- if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
- return selection.expandUsingGranularityInComposedTree(granularity); |
- return selection.expandUsingGranularity(granularity); |
-} |
- |
template <typename Strategy> |
static int textDistance(const PositionAlgorithm<Strategy>& start, const PositionAlgorithm<Strategy>& end) |
{ |
@@ -152,12 +139,12 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
} |
const PositionWithAffinity eventPos = innerNode->layoutObject()->positionForPoint(event.localPoint()); |
- VisiblePositionTemplate<Strategy> visiblePos = createVisiblePosition(fromPositionInDOMTree<Strategy>(eventPos.position()), eventPos.affinity()); |
+ VisiblePositionTemplate<Strategy> visiblePos = createVisiblePosition(fromPositionInDOMTree<Strategy>(eventPos)); |
if (visiblePos.isNull()) |
visiblePos = createVisiblePosition(PositionAlgorithm<Strategy>::firstPositionInOrBeforeNode(innerNode)); |
PositionAlgorithm<Strategy> pos = visiblePos.deepEquivalent(); |
- VisibleSelectionTemplate<Strategy> newSelection(selection().selection()); |
+ VisibleSelectionTemplate<Strategy> newSelection = selection().visibleSelection<Strategy>(); |
TextGranularity granularity = CharacterGranularity; |
if (extendSelection && newSelection.isCaretOrRange()) { |
@@ -171,8 +158,8 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) { |
if (pos.isNotNull()) { |
- // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection |
- // was created right-to-left |
+ // See <rdar://problem/3668157> REGRESSION (Mail): shift-click |
+ // deselects when selection was created right-to-left |
const PositionAlgorithm<Strategy> start = newSelection.start(); |
const PositionAlgorithm<Strategy> end = newSelection.end(); |
int distanceToStart = textDistance(start, pos); |
@@ -209,15 +196,15 @@ void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu |
if (!target) |
return; |
- const PositionWithAffinity rawTargetPosition = selection().selection().positionRespectingEditingBoundary(hitTestResult.localPoint(), target); |
- const VisiblePositionTemplate<Strategy> targetPosition = createVisiblePosition(fromPositionInDOMTree<Strategy>(rawTargetPosition.position()), rawTargetPosition.affinity()); |
+ PositionWithAffinity rawTargetPosition = selection().selection().positionRespectingEditingBoundary(hitTestResult.localPoint(), target); |
+ VisiblePositionTemplate<Strategy> targetPosition = createVisiblePosition(fromPositionInDOMTree<Strategy>(rawTargetPosition)); |
// Don't modify the selection if we're not on a node. |
if (targetPosition.isNull()) |
return; |
// Restart the selection if this is the first mouse move. This work is usually |
// done in handleMousePressEvent, but not if the mouse press was on an existing selection. |
- VisibleSelectionTemplate<Strategy> newSelection(selection().selection()); |
+ VisibleSelectionTemplate<Strategy> newSelection = selection().visibleSelection<Strategy>(); |
// Special case to limit selection to the containing block for SVG text. |
// FIXME: Isn't there a better non-SVG-specific way to do this? |
@@ -301,25 +288,26 @@ bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node |
return true; |
} |
+template <typename Strategy> |
void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
{ |
Node* innerNode = result.innerNode(); |
- VisibleSelection newSelection; |
+ VisibleSelectionTemplate<Strategy> newSelection; |
if (!innerNode || !innerNode->layoutObject()) |
return; |
- VisiblePosition pos = createVisiblePosition(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
+ const VisiblePositionTemplate<Strategy> pos = createVisiblePosition(fromPositionInDOMTree<Strategy>(innerNode->layoutObject()->positionForPoint(result.localPoint()))); |
if (pos.isNotNull()) { |
- newSelection = VisibleSelection(pos); |
- expandSelectionUsingGranularity(newSelection, WordGranularity); |
+ newSelection = VisibleSelectionTemplate<Strategy>(pos); |
+ newSelection.expandUsingGranularity(WordGranularity); |
} |
#if OS(ANDROID) |
// If node is not editable and doesn't have text except space, tab or |
// line break, do not select that 'empty' area. |
if (!innerNode->hasEditableStyle()) { |
- const EphemeralRangeInComposedTree range = EphemeralRangeInComposedTree(newSelection.startInComposedTree(), newSelection.endInComposedTree()); |
+ EphemeralRangeTemplate<Strategy> range = EphemeralRangeTemplate<Strategy>(newSelection.start(), newSelection.end()); |
String str = plainText(range, TextIteratorDefaultBehavior); |
if (str.isEmpty() || str.simplifyWhiteSpace().containsOnlyWhitespace()) |
return; |
@@ -332,23 +320,24 @@ void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult |
updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
} |
+template <typename Strategy> |
void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
{ |
Node* innerNode = result.innerNode(); |
- VisibleSelection newSelection; |
+ VisibleSelectionTemplate<Strategy> newSelection; |
if (!innerNode || !innerNode->layoutObject()) |
return; |
- VisiblePosition pos = createVisiblePosition(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
+ VisiblePositionTemplate<Strategy> pos = createVisiblePosition(fromPositionInDOMTree<Strategy>(innerNode->layoutObject()->positionForPoint(result.localPoint()))); |
if (pos.isNotNull()) { |
- const Position markerPosition = pos.deepEquivalent().parentAnchoredEquivalent(); |
- DocumentMarkerVector markers = innerNode->document().markers().markersInRange(EphemeralRange(markerPosition), DocumentMarker::MisspellingMarkers()); |
+ const PositionAlgorithm<Strategy> markerPosition = pos.deepEquivalent().parentAnchoredEquivalent(); |
+ DocumentMarkerVector markers = innerNode->document().markers().markersInRange(EphemeralRange(toPositionInDOMTree(markerPosition)), DocumentMarker::MisspellingMarkers()); |
if (markers.size() == 1) { |
Node* containerNode = markerPosition.computeContainerNode(); |
- const Position start(containerNode, markers[0]->startOffset()); |
- const Position end(containerNode, markers[0]->endOffset()); |
- newSelection = VisibleSelection(start, end); |
+ const PositionAlgorithm<Strategy> start(containerNode, markers[0]->startOffset()); |
+ const PositionAlgorithm<Strategy> end(containerNode, markers[0]->endOffset()); |
+ newSelection = VisibleSelectionTemplate<Strategy>(start, end); |
} |
} |
@@ -363,20 +352,25 @@ void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHi |
if (!m_mouseDownMayStartSelect) |
return; |
- selectClosestWordFromHitTestResult(result.hitTestResult(), |
- (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhitespace::DontAppend); |
+ AppendTrailingWhitespace appendTrailingWhitespace = (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhitespace::DontAppend; |
+ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return selectClosestWordFromHitTestResult<EditingInComposedTreeStrategy>(result.hitTestResult(), appendTrailingWhitespace); |
+ selectClosestWordFromHitTestResult<EditingStrategy>(result.hitTestResult(), appendTrailingWhitespace); |
} |
+template <typename Strategy> |
void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result) |
{ |
if (!m_mouseDownMayStartSelect) |
return; |
- selectClosestMisspellingFromHitTestResult(result.hitTestResult(), |
+ selectClosestMisspellingFromHitTestResult<Strategy>(result.hitTestResult(), |
(result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhitespace::DontAppend); |
} |
+template <typename Strategy> |
void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) |
{ |
if (!result.hitTestResult().isLiveLink()) |
@@ -387,11 +381,11 @@ void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEvent |
if (!innerNode || !innerNode->layoutObject() || !m_mouseDownMayStartSelect) |
return; |
- VisibleSelection newSelection; |
+ VisibleSelectionTemplate<Strategy> newSelection; |
Element* URLElement = result.hitTestResult().URLElement(); |
- VisiblePosition pos = createVisiblePosition(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
+ const VisiblePositionTemplate<Strategy> pos = createVisiblePosition(fromPositionInDOMTree<Strategy>(innerNode->layoutObject()->positionForPoint(result.localPoint()))); |
if (pos.isNotNull() && pos.deepEquivalent().anchorNode()->isDescendantOf(URLElement)) |
- newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); |
+ newSelection = VisibleSelectionTemplate<Strategy>::selectionFromContentsOfNode(URLElement); |
updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
} |
@@ -416,7 +410,8 @@ bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH |
return true; |
} |
-bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) |
+template <typename Strategy> |
+bool SelectionController::handleMousePressEventTripleClickAlgorithm(const MouseEventWithHitTestResults& event) |
{ |
TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick"); |
@@ -427,16 +422,23 @@ bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH |
if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
return false; |
- VisibleSelection newSelection; |
- VisiblePosition pos = createVisiblePosition(innerNode->layoutObject()->positionForPoint(event.localPoint())); |
+ VisibleSelectionTemplate<Strategy> newSelection; |
+ const VisiblePositionTemplate<Strategy> pos = createVisiblePosition(fromPositionInDOMTree<Strategy>(innerNode->layoutObject()->positionForPoint(event.localPoint()))); |
if (pos.isNotNull()) { |
- newSelection = VisibleSelection(pos); |
- expandSelectionUsingGranularity(newSelection, ParagraphGranularity); |
+ newSelection = VisibleSelectionTemplate<Strategy>(pos); |
+ newSelection.expandUsingGranularity(ParagraphGranularity); |
} |
return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
} |
+bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) |
+{ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return handleMousePressEventTripleClickAlgorithm<EditingInComposedTreeStrategy>(event); |
+ return handleMousePressEventTripleClickAlgorithm<EditingStrategy>(event); |
+} |
+ |
bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) |
{ |
if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
@@ -486,7 +488,8 @@ void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe |
updateSelectionForMouseDragAlgorithm<EditingStrategy>(hitTestResult, mousePressNode, dragStartPos, lastKnownMousePosition); |
} |
-bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event, const LayoutPoint& dragStartPos) |
+template <typename Strategy> |
+bool SelectionController::handleMouseReleaseEventAlgorithm(const MouseEventWithHitTestResults& event, const LayoutPoint& dragStartPos) |
{ |
bool handled = false; |
m_mouseDownMayStartSelect = false; |
@@ -498,12 +501,12 @@ bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes |
&& dragStartPos == event.event().position() |
&& selection().isRange() |
&& event.event().button() != RightButton) { |
- VisibleSelection newSelection; |
+ VisibleSelectionTemplate<Strategy> newSelection; |
Node* node = event.innerNode(); |
bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled(); |
if (node && node->layoutObject() && (caretBrowsing || node->hasEditableStyle())) { |
- VisiblePosition pos = createVisiblePosition(node->layoutObject()->positionForPoint(event.localPoint())); |
- newSelection = VisibleSelection(pos); |
+ const VisiblePositionTemplate<Strategy> pos = createVisiblePosition(fromPositionInDOMTree<Strategy>(node->layoutObject()->positionForPoint(event.localPoint()))); |
+ newSelection = VisibleSelectionTemplate<Strategy>(pos); |
} |
setSelectionIfNeeded(selection(), newSelection); |
@@ -523,6 +526,12 @@ bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes |
return handled; |
} |
+bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event, const LayoutPoint& dragStartPos) |
+{ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return handleMouseReleaseEventAlgorithm<EditingInComposedTreeStrategy>(event, dragStartPos); |
+ return handleMouseReleaseEventAlgorithm<EditingStrategy>(event, dragStartPos); |
+} |
bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent) |
{ |
@@ -555,7 +564,8 @@ bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& m |
return false; |
} |
-bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const HitTestResult& hitTestResult) |
+template <typename Strategy> |
+bool SelectionController::handleGestureLongPressAlgorithm(const PlatformGestureEvent& gestureEvent, const HitTestResult& hitTestResult) |
{ |
if (hitTestResult.isLiveLink()) |
return false; |
@@ -577,10 +587,15 @@ bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges |
if (!innerNodeIsSelectable) |
return false; |
- selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace::DontAppend); |
- if (!selection().isRange()) |
- return false; |
- return true; |
+ selectClosestWordFromHitTestResult<Strategy>(hitTestResult, AppendTrailingWhitespace::DontAppend); |
+ return selection().isRange(); |
+} |
+ |
+bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const HitTestResult& hitTestResult) |
+{ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return handleGestureLongPressAlgorithm<EditingInComposedTreeStrategy>(gestureEvent, hitTestResult); |
+ return handleGestureLongPressAlgorithm<EditingStrategy>(gestureEvent, hitTestResult); |
} |
void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResults& mev, const LayoutPoint& position) |
@@ -595,13 +610,22 @@ void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult |
m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection |
- if (mev.hitTestResult().isMisspelled()) |
- selectClosestMisspellingFromMouseEvent(mev); |
- else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
- selectClosestWordOrLinkFromMouseEvent(mev); |
+ if (mev.hitTestResult().isMisspelled()) { |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return selectClosestMisspellingFromMouseEvent<EditingInComposedTreeStrategy>(mev); |
+ return selectClosestMisspellingFromMouseEvent<EditingStrategy>(mev); |
+ } |
+ |
+ if (!m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
+ return; |
+ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return selectClosestWordOrLinkFromMouseEvent<EditingInComposedTreeStrategy>(mev); |
+ selectClosestWordOrLinkFromMouseEvent<EditingStrategy>(mev); |
} |
-void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitTestResults& mev) |
+template <typename Strategy> |
+void SelectionController::passMousePressEventToSubframeAlgorithm(const MouseEventWithHitTestResults& mev) |
{ |
// If we're clicking into a frame that is selected, the frame will appear |
// greyed out even though we're clicking on the selection. This looks |
@@ -611,12 +635,19 @@ void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitT |
if (!selection().contains(p)) |
return; |
- VisiblePosition visiblePos = createVisiblePosition( |
- mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())); |
- VisibleSelection newSelection(visiblePos); |
+ const VisiblePositionTemplate<Strategy> visiblePos = createVisiblePosition( |
+ fromPositionInDOMTree<Strategy>(mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint()))); |
+ VisibleSelectionTemplate<Strategy> newSelection(visiblePos); |
selection().setSelection(newSelection); |
} |
+void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitTestResults& mev) |
+{ |
+ if (RuntimeEnabledFeatures::selectionForComposedTreeEnabled()) |
+ return passMousePressEventToSubframeAlgorithm<EditingInComposedTreeStrategy>(mev); |
+ passMousePressEventToSubframeAlgorithm<EditingStrategy>(mev); |
+} |
+ |
void SelectionController::initializeSelectionState() |
{ |
m_selectionState = SelectionState::HaveNotStartedSelection; |