Chromium Code Reviews| Index: Source/core/editing/SelectionController.cpp |
| diff --git a/Source/core/editing/SelectionController.cpp b/Source/core/editing/SelectionController.cpp |
| index 2f0bae1eded7d0d971e29a4e87a384c8ab1e67bf..14c6122831fdf06e2f4435b74c166d534557f663 100644 |
| --- a/Source/core/editing/SelectionController.cpp |
| +++ b/Source/core/editing/SelectionController.cpp |
| @@ -46,31 +46,17 @@ |
| #include "platform/RuntimeEnabledFeatures.h" |
| namespace blink { |
| -PassOwnPtrWillBeRawPtr<SelectionController> SelectionController::create(LocalFrame& frame) |
| -{ |
| - return adoptPtrWillBeNoop(new SelectionController(frame)); |
| -} |
| -SelectionController::SelectionController(LocalFrame& frame) |
| - : m_frame(&frame) |
| - , m_mouseDownMayStartSelect(false) |
| - , m_mouseDownWasSingleClickInSelection(false) |
| - , m_selectionInitiationState(HaveNotStartedSelection) |
| -{ |
| -} |
| +namespace { |
| -DEFINE_TRACE(SelectionController) |
| +void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection) |
| { |
| - visitor->trace(m_frame); |
| -} |
| - |
| -static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection) |
| -{ |
| - if (selection.selection() != newSelection) |
| - selection.setSelection(newSelection); |
| + if (selection.selection() == newSelection) |
| + return; |
| + selection.setSelection(newSelection); |
| } |
| -static inline bool dispatchSelectStart(Node* node) |
| +bool dispatchSelectStart(Node* node) |
| { |
| if (!node || !node->layoutObject()) |
| return true; |
| @@ -94,164 +80,33 @@ VisibleSelection expandSelectionToRespectUserSelectAllAlgorithm(Node* targetNode |
| return newSelection; |
| } |
| -static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) |
| +VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) |
| { |
| return expandSelectionToRespectUserSelectAllAlgorithm<VisibleSelection::InDOMTree>(targetNode, selection); |
| } |
| -static bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGranularity granularity) |
| +bool expandSelectionUsingGranularity(VisibleSelection& selection, TextGranularity granularity) |
| { |
| return selection.expandUsingGranularity(granularity); |
| } |
| -bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity) |
| -{ |
| - if (Position::nodeIsUserSelectNone(targetNode)) |
| - return false; |
| - |
| - if (!dispatchSelectStart(targetNode)) |
| - return false; |
| - |
| - if (selection.isRange()) { |
| - m_selectionInitiationState = ExtendedSelection; |
| - } else { |
| - granularity = CharacterGranularity; |
| - m_selectionInitiationState = PlacedCaret; |
| - } |
| - |
| - m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity); |
| - |
| - return true; |
| -} |
| - |
| -void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
| -{ |
| - Node* innerNode = result.innerNode(); |
| - VisibleSelection newSelection; |
| - |
| - if (innerNode && innerNode->layoutObject()) { |
| - VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| - if (pos.isNotNull()) { |
| - newSelection = VisibleSelection(pos); |
| - expandSelectionUsingGranularity(newSelection, WordGranularity); |
| - } |
| - |
| - if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange()) |
| - newSelection.appendTrailingWhitespace(); |
| - |
| - updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| - } |
| -} |
| - |
| -void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
| -{ |
| - Node* innerNode = result.innerNode(); |
| - VisibleSelection newSelection; |
| - |
| - if (innerNode && innerNode->layoutObject()) { |
| - VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| - Position start = pos.deepEquivalent(); |
| - Position end = pos.deepEquivalent(); |
| - if (pos.isNotNull()) { |
| - DocumentMarkerVector markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); |
| - if (markers.size() == 1) { |
| - start.moveToOffset(markers[0]->startOffset()); |
| - end.moveToOffset(markers[0]->endOffset()); |
| - newSelection = VisibleSelection(start, end); |
| - } |
| - } |
| - |
| - if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange()) |
| - newSelection.appendTrailingWhitespace(); |
| - |
| - updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| - } |
| -} |
| - |
| -void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) |
| +int textDistance(const Position& start, const Position& end) |
|
yosin_UTC9
2015/06/22 05:31:11
textDistance() is also templatized in ToT. Could y
Miyoung Shin(c)
2015/06/24 07:43:27
Ok.
|
| { |
| - if (m_mouseDownMayStartSelect) { |
| - selectClosestWordFromHitTestResult(result.hitTestResult(), |
| - (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); |
| - } |
| -} |
| - |
| -void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result) |
| -{ |
| - if (m_mouseDownMayStartSelect) { |
| - selectClosestMisspellingFromHitTestResult(result.hitTestResult(), |
| - (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); |
| - } |
| -} |
| - |
| -void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) |
| -{ |
| - if (!result.hitTestResult().isLiveLink()) |
| - return selectClosestWordFromMouseEvent(result); |
| - |
| - Node* innerNode = result.innerNode(); |
| - |
| - if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) { |
| - VisibleSelection newSelection; |
| - Element* URLElement = result.hitTestResult().URLElement(); |
| - VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| - if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement)) |
| - newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); |
| - |
| - updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| - } |
| + return TextIterator::rangeLength(start, end, true); |
| } |
| -bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) |
| +bool canMouseDownStartSelect(Node* node) |
| { |
| - TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick"); |
| + if (!node || !node->layoutObject()) |
| + return true; |
| - if (event.event().button() != LeftButton) |
| + if (!node->canStartSelection()) |
| return false; |
| - if (m_frame->selection().isRange()) { |
| - // A double-click when range is already selected |
| - // should not change the selection. So, do not call |
| - // selectClosestWordFromMouseEvent, but do set |
| - // m_beganSelectingText to prevent handleMouseReleaseEvent |
| - // from setting caret selection. |
| - m_selectionInitiationState = ExtendedSelection; |
| - } else { |
| - selectClosestWordFromMouseEvent(event); |
| - } |
| return true; |
| } |
| -bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) |
| -{ |
| - TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick"); |
| - |
| - if (event.event().button() != LeftButton) |
| - return false; |
| - |
| - Node* innerNode = event.innerNode(); |
| - if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| - return false; |
| - |
| - VisibleSelection newSelection; |
| - VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localPoint())); |
| - if (pos.isNotNull()) { |
| - newSelection = VisibleSelection(pos); |
| - expandSelectionUsingGranularity(newSelection, ParagraphGranularity); |
| - } |
| - |
| - return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
| -} |
| - |
| -static int textDistance(const Position& start, const Position& end) |
| -{ |
| - return TextIterator::rangeLength(start, end, true); |
| -} |
| - |
| -bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) |
| -{ |
| - return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree>(event); |
| -} |
| +} // namespace |
| template <typename Strategy> |
| bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseEventWithHitTestResults& event) |
| @@ -271,7 +126,7 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
| // existing selection so we can allow for text dragging. |
| if (FrameView* view = m_frame->view()) { |
| LayoutPoint vPoint = view->rootFrameToContents(event.event().position()); |
| - if (!extendSelection && m_frame->selection().contains(vPoint)) { |
| + if (!extendSelection && selection().contains(vPoint)) { |
| m_mouseDownWasSingleClickInSelection = true; |
| return false; |
| } |
| @@ -282,7 +137,7 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
| visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM); |
| PositionType pos = Strategy::toPositionType(visiblePos.deepEquivalent()); |
| - VisibleSelection newSelection = m_frame->selection().selection(); |
| + VisibleSelection newSelection = selection().selection(); |
| TextGranularity granularity = CharacterGranularity; |
| if (extendSelection && newSelection.isCaretOrRange()) { |
| @@ -311,9 +166,9 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
| newSelection.setExtent(pos); |
| } |
| - if (m_frame->selection().granularity() != CharacterGranularity) { |
| - granularity = m_frame->selection().granularity(); |
| - expandSelectionUsingGranularity(newSelection, m_frame->selection().granularity()); |
| + if (selection().granularity() != CharacterGranularity) { |
| + granularity = selection().granularity(); |
| + expandSelectionUsingGranularity(newSelection, selection().granularity()); |
| } |
| } else { |
| newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos)); |
| @@ -324,57 +179,6 @@ bool SelectionController::handleMousePressEventSingleClickAlgorithm(const MouseE |
| return false; |
| } |
| -static inline bool canMouseDownStartSelect(Node* node) |
| -{ |
| - if (!node || !node->layoutObject()) |
| - return true; |
| - |
| - if (!node->canStartSelection()) |
| - return false; |
| - |
| - return true; |
| -} |
| - |
| -void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResults& event) |
| -{ |
| - // If we got the event back, that must mean it wasn't prevented, |
| - // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
| - m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !event.scrollbar(); |
| - m_mouseDownWasSingleClickInSelection = false; |
| -} |
| - |
| -void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node* mousePressNode, const IntPoint& lastKnownMousePosition) |
| -{ |
| - if (m_selectionInitiationState != ExtendedSelection) { |
| - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); |
| - HitTestResult result(request, mouseDownPos); |
| - m_frame->document()->layoutView()->hitTest(result); |
| - |
| - updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownMousePosition); |
| - } |
| - updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStartPos, lastKnownMousePosition); |
| -} |
| - |
| -void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| -{ |
| - FrameView* view = m_frame->view(); |
| - if (!view) |
| - return; |
| - LayoutView* layoutObject = m_frame->contentLayoutObject(); |
| - if (!layoutObject) |
| - return; |
| - |
| - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move); |
| - HitTestResult result(request, view->rootFrameToContents(lastKnownMousePosition)); |
| - layoutObject->hitTest(result); |
| - updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownMousePosition); |
| -} |
| - |
| -void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| -{ |
| - updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestResult, mousePressNode, dragStartPos, lastKnownMousePosition); |
| -} |
| - |
| template <typename Strategy> |
| void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResult& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| { |
| @@ -387,14 +191,14 @@ void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu |
| if (!target) |
| return; |
| - VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target); |
| + VisiblePosition targetPosition = selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target); |
| // 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. |
| - VisibleSelection newSelection = m_frame->selection().selection(); |
| + VisibleSelection newSelection = selection().selection(); |
| // 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? |
| @@ -407,12 +211,12 @@ void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu |
| } |
| } |
| - if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target)) |
| + if (m_selectionState == SelectionState::HaveNotStartedSelection && !dispatchSelectStart(target)) |
| return; |
| - if (m_selectionInitiationState != ExtendedSelection) { |
| + if (m_selectionState != SelectionState::ExtendedSelection) { |
| // Always extend selection here because it's caused by a mouse drag |
| - m_selectionInitiationState = ExtendedSelection; |
| + m_selectionState = SelectionState::ExtendedSelection; |
| newSelection = VisibleSelection(targetPosition); |
| } |
| @@ -442,13 +246,220 @@ void SelectionController::updateSelectionForMouseDragAlgorithm(const HitTestResu |
| newSelection.setExtent(targetPosition); |
| } |
| - if (m_frame->selection().granularity() != CharacterGranularity) |
| - expandSelectionUsingGranularity(newSelection, m_frame->selection().granularity()); |
| + if (selection().granularity() != CharacterGranularity) |
| + expandSelectionUsingGranularity(newSelection, selection().granularity()); |
| - m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(), |
| + selection().setNonDirectionalSelectionIfNeeded(newSelection, selection().granularity(), |
| FrameSelection::AdjustEndpointsAtBidiBoundary); |
| } |
| +PassOwnPtrWillBeRawPtr<SelectionController> SelectionController::create(LocalFrame& frame) |
|
yosin_UTC9
2015/06/22 05:31:10
Let's keep original source code location for them
Miyoung Shin(c)
2015/06/24 07:43:27
when picking up template codes, it looks like thes
|
| +{ |
| + return adoptPtrWillBeNoop(new SelectionController(frame)); |
| +} |
| + |
| +SelectionController::SelectionController(LocalFrame& frame) |
| + : m_frame(&frame) |
| + , m_mouseDownMayStartSelect(false) |
| + , m_mouseDownWasSingleClickInSelection(false) |
| + , m_selectionState(SelectionState::HaveNotStartedSelection) |
| +{ |
| +} |
| + |
| +DEFINE_TRACE(SelectionController) |
| +{ |
| + visitor->trace(m_frame); |
| +} |
| + |
| +bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& visibleSelection, TextGranularity granularity) |
| +{ |
| + if (Position::nodeIsUserSelectNone(targetNode)) |
| + return false; |
| + |
| + if (!dispatchSelectStart(targetNode)) |
| + return false; |
| + |
| + if (visibleSelection.isRange()) { |
| + m_selectionState = SelectionState::ExtendedSelection; |
| + } else { |
| + granularity = CharacterGranularity; |
| + m_selectionState = SelectionState::PlacedCaret; |
| + } |
| + |
| + selection().setNonDirectionalSelectionIfNeeded(visibleSelection, granularity); |
| + |
| + return true; |
| +} |
| + |
| +void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
| +{ |
| + Node* innerNode = result.innerNode(); |
| + VisibleSelection newSelection; |
| + |
| + if (!innerNode || !innerNode->layoutObject()) |
| + return; |
| + |
| + VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| + if (pos.isNotNull()) { |
| + newSelection = VisibleSelection(pos); |
| + expandSelectionUsingGranularity(newSelection, WordGranularity); |
| + } |
| + |
| + if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && newSelection.isRange()) |
| + newSelection.appendTrailingWhitespace(); |
| + |
| + updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| +} |
| + |
| +void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace) |
| +{ |
| + Node* innerNode = result.innerNode(); |
| + VisibleSelection newSelection; |
| + |
| + if (!innerNode || !innerNode->layoutObject()) |
| + return; |
| + |
| + VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| + Position start = pos.deepEquivalent(); |
| + Position end = pos.deepEquivalent(); |
| + if (pos.isNotNull()) { |
| + DocumentMarkerVector markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); |
| + if (markers.size() == 1) { |
| + start.moveToOffset(markers[0]->startOffset()); |
| + end.moveToOffset(markers[0]->endOffset()); |
| + newSelection = VisibleSelection(start, end); |
| + } |
| + } |
| + |
| + if (appendTrailingWhitespace == AppendTrailingWhitespace::ShouldAppend && newSelection.isRange()) |
| + newSelection.appendTrailingWhitespace(); |
| + |
| + updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| +} |
| + |
| +void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) |
| +{ |
| + if (!m_mouseDownMayStartSelect) |
| + return; |
| + |
| + selectClosestWordFromHitTestResult(result.hitTestResult(), |
| + (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhitespace::DontAppend); |
| +} |
| + |
| +void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result) |
| +{ |
| + if (!m_mouseDownMayStartSelect) |
| + return; |
| + |
| + selectClosestMisspellingFromHitTestResult(result.hitTestResult(), |
| + (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? AppendTrailingWhitespace::ShouldAppend : AppendTrailingWhitespace::DontAppend); |
| +} |
| + |
| +void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) |
| +{ |
| + if (!result.hitTestResult().isLiveLink()) |
| + return selectClosestWordFromMouseEvent(result); |
| + |
| + Node* innerNode = result.innerNode(); |
| + |
| + if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| + return; |
| + |
| + VisibleSelection newSelection; |
| + Element* URLElement = result.hitTestResult().URLElement(); |
| + VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.localPoint())); |
| + if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement)) |
| + newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); |
| + |
| + updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| +} |
| + |
| +bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) |
| +{ |
| + return handleMousePressEventSingleClickAlgorithm<VisibleSelection::InDOMTree>(event); |
| +} |
| + |
| +bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) |
| +{ |
| + TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick"); |
| + |
| + if (event.event().button() != LeftButton) |
| + return false; |
| + |
| + if (selection().isRange()) { |
| + // A double-click when range is already selected |
| + // should not change the selection. So, do not call |
| + // selectClosestWordFromMouseEvent, but do set |
| + // m_beganSelectingText to prevent handleMouseReleaseEvent |
| + // from setting caret selection. |
| + m_selectionState = SelectionState::ExtendedSelection; |
| + } else { |
| + selectClosestWordFromMouseEvent(event); |
| + } |
| + return true; |
| +} |
| + |
| +bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) |
| +{ |
| + TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick"); |
| + |
| + if (event.event().button() != LeftButton) |
| + return false; |
| + |
| + Node* innerNode = event.innerNode(); |
| + if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| + return false; |
| + |
| + VisibleSelection newSelection; |
| + VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localPoint())); |
| + if (pos.isNotNull()) { |
| + newSelection = VisibleSelection(pos); |
| + expandSelectionUsingGranularity(newSelection, ParagraphGranularity); |
| + } |
| + |
| + return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
| +} |
| + |
| +void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResults& event) |
| +{ |
| + // If we got the event back, that must mean it wasn't prevented, |
| + // so it's allowed to start a drag or selection if it wasn't in a scrollbar. |
| + m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !event.scrollbar(); |
| + m_mouseDownWasSingleClickInSelection = false; |
| +} |
| + |
| +void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node* mousePressNode, const IntPoint& lastKnownMousePosition) |
| +{ |
| + if (m_selectionState != SelectionState::ExtendedSelection) { |
| + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); |
| + HitTestResult result(request, mouseDownPos); |
| + m_frame->document()->layoutView()->hitTest(result); |
| + |
| + updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownMousePosition); |
| + } |
| + updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStartPos, lastKnownMousePosition); |
| +} |
| + |
| +void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| +{ |
| + FrameView* view = m_frame->view(); |
| + if (!view) |
| + return; |
| + LayoutView* layoutObject = m_frame->contentLayoutObject(); |
| + if (!layoutObject) |
| + return; |
| + |
| + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move); |
| + HitTestResult result(request, view->rootFrameToContents(lastKnownMousePosition)); |
| + layoutObject->hitTest(result); |
| + updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownMousePosition); |
| +} |
| + |
| +void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTestResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition) |
| +{ |
| + updateSelectionForMouseDragAlgorithm<VisibleSelection::InDOMTree>(hitTestResult, mousePressNode, dragStartPos, lastKnownMousePosition); |
| +} |
| + |
| bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event, const LayoutPoint& dragStartPos) |
| { |
| bool handled = false; |
| @@ -457,9 +468,9 @@ bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes |
| // press and it's not a context menu click. We do this so when clicking |
| // on the selection, the selection goes away. However, if we are |
| // editing, place the caret. |
| - if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection |
| + if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionState::ExtendedSelection |
| && dragStartPos == event.event().position() |
| - && m_frame->selection().isRange() |
| + && selection().isRange() |
| && event.event().button() != RightButton) { |
| VisibleSelection newSelection; |
| Node* node = event.innerNode(); |
| @@ -469,14 +480,14 @@ bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes |
| newSelection = VisibleSelection(pos); |
| } |
| - setSelectionIfNeeded(m_frame->selection(), newSelection); |
| + setSelectionIfNeeded(selection(), newSelection); |
| handled = true; |
| } |
| - m_frame->selection().notifyLayoutObjectOfSelectionChange(UserTriggered); |
| + selection().notifyLayoutObjectOfSelectionChange(UserTriggered); |
| - m_frame->selection().selectFrameElementInParentIfFullySelected(); |
| + selection().selectFrameElementInParentIfFullySelected(); |
| if (event.event().button() == MiddleButton && !event.isOverLink()) { |
| // Ignore handled, since we want to paste to where the caret was placed anyway. |
| @@ -486,7 +497,6 @@ bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes |
| return handled; |
| } |
| - |
| bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent) |
| { |
| // If the event was a middle click, attempt to copy global selection in after |
| @@ -525,58 +535,61 @@ bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges |
| #else |
| bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled(); |
| #endif |
| - if (shouldLongPressSelectWord) { |
| - |
| + if (!shouldLongPressSelectWord) |
| + return false; |
| - Node* innerNode = hitTestResult.innerNode(); |
| - if (!hitTestResult.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() |
| + Node* innerNode = hitTestResult.innerNode(); |
| + if (hitTestResult.isLiveLink() || !innerNode || !(innerNode->isContentEditable() || innerNode->isTextNode() |
| #if OS(ANDROID) |
| - || innerNode->canStartSelection() |
| + || innerNode->canStartSelection() |
| #endif |
| - )) { |
| - selectClosestWordFromHitTestResult(hitTestResult, DontAppendTrailingWhitespace); |
| - if (m_frame->selection().isRange()) |
| - return true; |
| - } |
| - } |
| - return false; |
| + )) |
| + return false; |
| + |
| + selectClosestWordFromHitTestResult(hitTestResult, AppendTrailingWhitespace::DontAppend); |
| + if (!selection().isRange()) |
| + return false; |
| + |
| + return true; |
| } |
| -void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResults& mev, const LayoutPoint& position) |
| +void SelectionController::prepareForContextMenu(const MouseEventWithHitTestResults& mev, const LayoutPoint& position) |
| { |
| - if (!m_frame->selection().contains(position) |
| - && !mev.scrollbar() |
| + if (selection().contains(position) |
| + || mev.scrollbar() |
| // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. |
| // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items |
| // available for text selections. But only if we're above text. |
| - && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev.innerNode()->isTextNode()))) { |
| - m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection |
| + || !(selection().isContentEditable() || (mev.innerNode() && mev.innerNode()->isTextNode()))) |
| + return; |
| - if (mev.hitTestResult().isMisspelled()) |
| - selectClosestMisspellingFromMouseEvent(mev); |
| - else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
| - selectClosestWordOrLinkFromMouseEvent(mev); |
| - } |
| + 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); |
| } |
| -void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitTestResults& mev) |
| +void SelectionController::preparePassMousePressEventToSubframe(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 |
| // really strange (having the whole frame be greyed out), so we deselect the |
| // selection. |
| IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); |
| - if (m_frame->selection().contains(p)) { |
| - VisiblePosition visiblePos( |
| - mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())); |
| - VisibleSelection newSelection(visiblePos); |
| - m_frame->selection().setSelection(newSelection); |
| - } |
| + if (!selection().contains(p)) |
| + return; |
| + |
| + VisiblePosition visiblePos( |
| + mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())); |
| + VisibleSelection newSelection(visiblePos); |
| + selection().setSelection(newSelection); |
| } |
| void SelectionController::initializeSelectionState() |
| { |
| - m_selectionInitiationState = HaveNotStartedSelection; |
| + m_selectionState = SelectionState::HaveNotStartedSelection; |
| } |
| void SelectionController::setMouseDownMayStartSelect(bool mayStartSelect) |
| @@ -594,4 +607,9 @@ bool SelectionController::mouseDownWasSingleClickInSelection() const |
| return m_mouseDownWasSingleClickInSelection; |
| } |
| +FrameSelection& SelectionController::selection() const |
| +{ |
| + return m_frame->selection(); |
| +} |
| + |
| } // namespace blink |