Chromium Code Reviews| Index: Source/core/page/EventHandler.cpp |
| diff --git a/Source/core/page/EventHandler.cpp b/Source/core/page/EventHandler.cpp |
| index dd3c5aee907340e0eb1b561e52fb6f57dfe5547c..31777e72043ce167cae98667e8bfd6f163d16251 100644 |
| --- a/Source/core/page/EventHandler.cpp |
| +++ b/Source/core/page/EventHandler.cpp |
| @@ -34,14 +34,12 @@ |
| #include "core/clipboard/DataObject.h" |
| #include "core/clipboard/DataTransfer.h" |
| #include "core/dom/Document.h" |
| -#include "core/dom/DocumentMarkerController.h" |
| #include "core/dom/TouchList.h" |
| #include "core/dom/shadow/ComposedTreeTraversal.h" |
| #include "core/dom/shadow/ShadowRoot.h" |
| #include "core/editing/Editor.h" |
| #include "core/editing/FrameSelection.h" |
| -#include "core/editing/htmlediting.h" |
| -#include "core/editing/iterators/TextIterator.h" |
| +#include "core/editing/SelectionController.h" |
| #include "core/events/EventPath.h" |
| #include "core/events/KeyboardEvent.h" |
| #include "core/events/MouseEvent.h" |
| @@ -220,10 +218,8 @@ EventHandler::EventHandler(LocalFrame* frame) |
| : m_frame(frame) |
| , m_mousePressed(false) |
| , m_capturesDragging(false) |
| - , m_mouseDownMayStartSelect(false) |
| , m_mouseDownMayStartDrag(false) |
| - , m_mouseDownWasSingleClickInSelection(false) |
| - , m_selectionInitiationState(HaveNotStartedSelection) |
| + , m_selectionController(adoptPtrWillBeNoop(new SelectionController(frame))) |
| , m_hoverTimer(this, &EventHandler::hoverTimerFired) |
| , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) |
| , m_mouseDownMayStartAutoscroll(false) |
| @@ -273,6 +269,7 @@ DEFINE_TRACE(EventHandler) |
| visitor->trace(m_previousGestureScrolledNode); |
| visitor->trace(m_lastDeferredTapElement); |
| visitor->trace(m_currentScrollChain); |
| + visitor->trace(m_selectionController); |
| #endif |
| } |
| @@ -317,13 +314,10 @@ void EventHandler::clear() |
| m_scrollbarHandlingScrollGesture = nullptr; |
| m_maxMouseMovedDuration = 0; |
| m_touchPressed = false; |
| - m_mouseDownMayStartSelect = false; |
| m_mouseDownMayStartDrag = false; |
| m_lastShowPressTimestamp = 0; |
| m_lastDeferredTapElement = nullptr; |
| m_eventHandlerWillResetCapturingMouseEventsNode = false; |
| - m_mouseDownWasSingleClickInSelection = false; |
| - m_selectionInitiationState = HaveNotStartedSelection; |
| m_mouseDownMayStartAutoscroll = false; |
| m_svgPan = false; |
| m_mouseDownPos = IntPoint(); |
| @@ -333,7 +327,7 @@ void EventHandler::clear() |
| m_offsetFromResizeCorner = LayoutSize(); |
| m_currentMouseCursor = Cursor(); |
| m_mouseDown = PlatformMouseEvent(); |
| - |
| + selectionController().clear(); |
| } |
| void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved) |
| @@ -345,258 +339,6 @@ void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved) |
| } |
| } |
| -static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection) |
| -{ |
| - if (selection.selection() != newSelection) |
| - selection.setSelection(newSelection); |
| -} |
| - |
| -static inline bool dispatchSelectStart(Node* node) |
| -{ |
| - if (!node || !node->layoutObject()) |
| - return true; |
| - |
| - return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart)); |
| -} |
| - |
| -static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) |
| -{ |
| - Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode); |
| - if (!rootUserSelectAll) |
| - return selection; |
| - |
| - VisibleSelection newSelection(selection); |
| - newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary)); |
| - newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary)); |
| - |
| - return newSelection; |
| -} |
| - |
| -bool EventHandler::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 EventHandler::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); |
| - newSelection.expandUsingGranularity(WordGranularity); |
| - } |
| - |
| - if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange()) |
| - newSelection.appendTrailingWhitespace(); |
| - |
| - updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); |
| - } |
| -} |
| - |
| -void EventHandler::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 EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) |
| -{ |
| - if (m_mouseDownMayStartSelect) { |
| - selectClosestWordFromHitTestResult(result.hitTestResult(), |
| - (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); |
| - } |
| -} |
| - |
| -void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result) |
| -{ |
| - if (m_mouseDownMayStartSelect) { |
| - selectClosestMisspellingFromHitTestResult(result.hitTestResult(), |
| - (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace); |
| - } |
| -} |
| - |
| -void EventHandler::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); |
| - } |
| -} |
| - |
| -bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) |
| -{ |
| - TRACE_EVENT0("blink", "EventHandler::handleMousePressEventDoubleClick"); |
| - |
| - if (event.event().button() != LeftButton) |
| - 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 EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) |
| -{ |
| - TRACE_EVENT0("blink", "EventHandler::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); |
| - newSelection.expandUsingGranularity(ParagraphGranularity); |
| - } |
| - |
| - return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); |
| -} |
| - |
| -static int textDistance(const Position& start, const Position& end) |
| -{ |
| - RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, end); |
| - return TextIterator::rangeLength(range->startPosition(), range->endPosition(), true); |
| -} |
| - |
| -bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) |
| -{ |
| - TRACE_EVENT0("blink", "EventHandler::handleMousePressEventSingleClick"); |
| - |
| - m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
| - Node* innerNode = event.innerNode(); |
| - if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) |
| - return false; |
| - |
| - // Extend the selection if the Shift key is down, unless the click is in a link. |
| - bool extendSelection = event.event().shiftKey() && !event.isOverLink(); |
| - |
| - // Don't restart the selection when the mouse is pressed on an |
| - // 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)) { |
| - m_mouseDownWasSingleClickInSelection = true; |
| - return false; |
| - } |
| - } |
| - |
| - VisiblePosition visiblePos(innerNode->layoutObject()->positionForPoint(event.localPoint())); |
| - if (visiblePos.isNull()) |
| - visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM); |
| - Position pos = visiblePos.deepEquivalent(); |
| - |
| - VisibleSelection newSelection = m_frame->selection().selection(); |
| - TextGranularity granularity = CharacterGranularity; |
| - |
| - if (extendSelection && newSelection.isCaretOrRange()) { |
| - VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos)))); |
| - if (selectionInUserSelectAll.isRange()) { |
| - if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0) |
| - pos = selectionInUserSelectAll.start(); |
| - else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0) |
| - pos = selectionInUserSelectAll.end(); |
| - } |
| - |
| - 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 |
| - Position start = newSelection.start(); |
| - Position end = newSelection.end(); |
| - int distanceToStart = textDistance(start, pos); |
| - int distanceToEnd = textDistance(pos, end); |
| - if (distanceToStart <= distanceToEnd) |
| - newSelection = VisibleSelection(end, pos); |
| - else |
| - newSelection = VisibleSelection(start, pos); |
| - } |
| - } else { |
| - newSelection.setExtent(pos); |
| - } |
| - |
| - if (m_frame->selection().granularity() != CharacterGranularity) { |
| - granularity = m_frame->selection().granularity(); |
| - newSelection.expandUsingGranularity(m_frame->selection().granularity()); |
| - } |
| - } else { |
| - newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos)); |
| - } |
| - |
| - // Updating the selection is considered side-effect of the event and so it doesn't impact the handled state. |
| - updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity); |
| - return false; |
| -} |
| - |
| -static inline bool canMouseDownStartSelect(Node* node) |
| -{ |
| - if (!node || !node->layoutObject()) |
| - return true; |
| - |
| - if (!node->canStartSelection()) |
| - return false; |
| - |
| - return true; |
| -} |
| - |
| bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) |
| { |
| TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent"); |
| @@ -615,13 +357,9 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve |
| bool singleClick = event.event().clickCount() <= 1; |
| - // 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_mouseDownMayStartDrag = singleClick; |
| - m_mouseDownWasSingleClickInSelection = false; |
| + selectionController().handleMousePressEvent(event); |
| m_mouseDown = event.event(); |
| @@ -645,16 +383,15 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve |
| bool swallowEvent = false; |
| m_mousePressed = true; |
| - m_selectionInitiationState = HaveNotStartedSelection; |
| if (event.event().clickCount() == 2) |
| - swallowEvent = handleMousePressEventDoubleClick(event); |
| + swallowEvent = selectionController().handleMousePressEventDoubleClick(event); |
| else if (event.event().clickCount() >= 3) |
| - swallowEvent = handleMousePressEventTripleClick(event); |
| + swallowEvent = selectionController().handleMousePressEventTripleClick(event); |
| else |
| - swallowEvent = handleMousePressEventSingleClick(event); |
| + swallowEvent = selectionController().handleMousePressEventSingleClick(event); |
| - m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect |
| + m_mouseDownMayStartAutoscroll = selectionController().allowSelection() |
| || (m_mousePressNode && m_mousePressNode->layoutBox() && m_mousePressNode->layoutBox()->canBeProgramaticallyScrolled()); |
| return swallowEvent; |
| @@ -663,7 +400,6 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve |
| bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) |
| { |
| TRACE_EVENT0("blink", "EventHandler::handleMouseDraggedEvent"); |
| - |
| // While resetting m_mousePressed here may seem out of place, it turns out |
| // to be needed to handle some bugs^Wfeatures in Blink mouse event handling: |
| // 1. Certain elements, such as <embed>, capture mouse events. They do not |
| @@ -711,99 +447,10 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e |
| } |
| } |
| - if (m_selectionInitiationState != ExtendedSelection) { |
| - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); |
| - HitTestResult result(request, m_mouseDownPos); |
| - m_frame->document()->layoutView()->hitTest(result); |
| - |
| - updateSelectionForMouseDrag(result); |
| - } |
| - updateSelectionForMouseDrag(event.hitTestResult()); |
| + selectionController().handleMouseDraggedEvent(event, m_mouseDownPos, m_dragStartPos, m_mousePressNode, m_lastKnownMousePosition); |
| return true; |
| } |
| -void EventHandler::updateSelectionForMouseDrag() |
| -{ |
| - FrameView* view = m_frame->view(); |
| - if (!view) |
| - return; |
| - LayoutView* renderer = m_frame->contentRenderer(); |
| - if (!renderer) |
| - return; |
| - |
| - HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move); |
| - HitTestResult result(request, view->rootFrameToContents(m_lastKnownMousePosition)); |
| - renderer->hitTest(result); |
| - updateSelectionForMouseDrag(result); |
| -} |
| - |
| -void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult) |
| -{ |
| - if (!m_mouseDownMayStartSelect) |
| - return; |
| - |
| - Node* target = hitTestResult.innerNode(); |
| - if (!target) |
| - return; |
| - |
| - VisiblePosition targetPosition = m_frame->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(); |
| - |
| - // 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? |
| - if (Node* selectionBaseNode = newSelection.base().deprecatedNode()) { |
| - if (LayoutObject* selectionBaseRenderer = selectionBaseNode->layoutObject()) { |
| - if (selectionBaseRenderer->isSVGText()) { |
| - if (target->layoutObject()->containingBlock() != selectionBaseRenderer->containingBlock()) |
| - return; |
| - } |
| - } |
| - } |
| - |
| - if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target)) |
| - return; |
| - |
| - if (m_selectionInitiationState != ExtendedSelection) { |
| - // Always extend selection here because it's caused by a mouse drag |
| - m_selectionInitiationState = ExtendedSelection; |
| - newSelection = VisibleSelection(targetPosition); |
| - } |
| - |
| - if (RuntimeEnabledFeatures::userSelectAllEnabled()) { |
| - Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get()); |
| - if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) { |
| - newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary)); |
| - newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary)); |
| - } else { |
| - // Reset base for user select all when base is inside user-select-all area and extent < base. |
| - if (rootUserSelectAllForMousePressNode && comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->layoutObject()->positionForPoint(m_dragStartPos)) < 0) |
| - newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary)); |
| - |
| - Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target); |
| - if (rootUserSelectAllForTarget && m_mousePressNode->layoutObject() && comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->layoutObject()->positionForPoint(m_dragStartPos)) < 0) |
| - newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary)); |
| - else if (rootUserSelectAllForTarget && m_mousePressNode->layoutObject()) |
| - newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary)); |
| - else |
| - newSelection.setExtent(targetPosition); |
| - } |
| - } else { |
| - newSelection.setExtent(targetPosition); |
| - } |
| - |
| - if (m_frame->selection().granularity() != CharacterGranularity) |
| - newSelection.expandUsingGranularity(m_frame->selection().granularity()); |
| - |
| - m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(), |
| - FrameSelection::AdjustEndpointsAtBidiBoundary); |
| -} |
| - |
| bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) |
| { |
| AutoscrollController* controller = autoscrollController(); |
| @@ -815,42 +462,9 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e |
| m_mousePressed = false; |
| m_capturesDragging = false; |
| m_mouseDownMayStartDrag = false; |
| - m_mouseDownMayStartSelect = false; |
| m_mouseDownMayStartAutoscroll = false; |
| - bool handled = false; |
| - |
| - // Clear the selection if the mouse didn't move after the last mouse |
| - // 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 |
| - && m_dragStartPos == event.event().position() |
| - && m_frame->selection().isRange() |
| - && event.event().button() != RightButton) { |
| - VisibleSelection newSelection; |
| - Node* node = event.innerNode(); |
| - bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled(); |
| - if (node && node->layoutObject() && (caretBrowsing || node->hasEditableStyle())) { |
| - VisiblePosition pos = VisiblePosition(node->layoutObject()->positionForPoint(event.localPoint())); |
| - newSelection = VisibleSelection(pos); |
| - } |
| - |
| - setSelectionIfNeeded(m_frame->selection(), newSelection); |
| - |
| - handled = true; |
| - } |
| - |
| - m_frame->selection().notifyRendererOfSelectionChange(UserTriggered); |
| - |
| - m_frame->selection().selectFrameElementInParentIfFullySelected(); |
| - |
| - if (event.event().button() == MiddleButton && !event.isOverLink()) { |
| - // Ignore handled, since we want to paste to where the caret was placed anyway. |
| - handled = handlePasteGlobalSelection(event.event()) || handled; |
| - } |
| - |
| - return handled; |
| + return selectionController().handleMouseReleaseEvent(event, m_dragStartPos); |
| } |
| #if OS(WIN) |
| @@ -1230,7 +844,7 @@ OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* |
| // During selection, use an I-beam no matter what we're over. |
| // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection. |
| - if (m_mousePressed && m_mouseDownMayStartSelect |
| + if (m_mousePressed && selectionController().allowSelection() |
| && !m_mouseDownMayStartDrag |
| && m_frame->selection().isCaretOrRange() |
| && !m_capturingMouseEventsNode) { |
| @@ -1267,7 +881,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) |
| setLastKnownMousePosition(mouseEvent); |
| m_mouseDownTimestamp = mouseEvent.timestamp(); |
| m_mouseDownMayStartDrag = false; |
| - m_mouseDownMayStartSelect = false; |
| + selectionController().setAllowSelection(false); |
| m_mouseDownMayStartAutoscroll = false; |
| if (FrameView* view = m_frame->view()) { |
| m_mouseDownPos = view->rootFrameToContents(mouseEvent.position()); |
| @@ -1277,6 +891,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) |
| } |
| HitTestRequest request(HitTestRequest::Active); |
| + |
| // Save the document point we generate in case the window coordinate is invalidated by what happens |
| // when we dispatch the event. |
| LayoutPoint documentPoint = contentPointFromRootFrame(m_frame, mouseEvent.position()); |
| @@ -1333,6 +948,11 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) |
| m_frame->selection().setCaretBlinkingSuspended(true); |
| bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.innerNode(), m_clickCount, mouseEvent, true); |
| + // SelectionState is initialized after dispatching mousedown event in order not to keep the selection by DOM APIs |
| + // Because we can't give the user the chance to handle the selection by user action like dragging if we keep the selection in case of mousedown. |
| + // FireFox also has the same behavior and it's more compatible with other browsers. |
| + selectionController().initializeSelectionState(); |
|
Rick Byers
2015/05/01 13:22:09
This is a behavior change, right?
Miyoung Shin(g)
2015/05/03 01:45:24
Done.
I'd missed this. I should change the behavio
|
| + |
| HitTestResult hitTestResult = hitTestResultInFrame(m_frame, mouseEvent.position(), HitTestRequest::ReadOnly); |
| swallowEvent = swallowEvent || handleMouseFocus(MouseEventWithHitTestResults(mouseEvent, hitTestResult)); |
| m_capturesDragging = !swallowEvent || mev.scrollbar(); |
| @@ -1641,38 +1261,6 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) |
| return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; |
| } |
| -bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent) |
| -{ |
| - // If the event was a middle click, attempt to copy global selection in after |
| - // the newly set caret position. |
| - // |
| - // This code is called from either the mouse up or mouse down handling. There |
| - // is some debate about when the global selection is pasted: |
| - // xterm: pastes on up. |
| - // GTK: pastes on down. |
| - // Qt: pastes on up. |
| - // Firefox: pastes on up. |
| - // Chromium: pastes on up. |
| - // |
| - // There is something of a webcompat angle to this well, as highlighted by |
| - // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on |
| - // down then the text is pasted just before the onclick handler runs and |
| - // clears the text box. So it's important this happens after the event |
| - // handlers have been fired. |
| - if (mouseEvent.type() != PlatformEvent::MouseReleased) |
| - return false; |
| - |
| - if (!m_frame->page()) |
| - return false; |
| - Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); |
| - // Do not paste here if the focus was moved somewhere else. |
| - if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection()) |
| - return m_frame->editor().command("PasteGlobalSelection").execute(); |
| - |
| - return false; |
| -} |
| - |
| - |
| bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer) |
| { |
| FrameView* view = m_frame->view(); |
| @@ -2435,6 +2023,7 @@ bool EventHandler::handleGestureTap(const GestureEventWithHitTestResults& target |
| static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftButtonDown), |
| PlatformMouseEvent::FromTouch, gestureEvent.timestamp()); |
| bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true); |
| + selectionController().initializeSelectionState(); |
|
Rick Byers
2015/05/01 13:22:09
is this a a behavior change?
Miyoung Shin(g)
2015/05/03 01:45:24
Done.
|
| if (!swallowMouseDownEvent) |
| swallowMouseDownEvent = handleMouseFocus(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest)); |
| if (!swallowMouseDownEvent) |
| @@ -2529,7 +2118,7 @@ bool EventHandler::handleGestureLongPress(const GestureEventWithHitTestResults& |
| || innerNode->canStartSelection() |
| #endif |
| )) { |
| - selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace); |
| + selectionController().selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace); |
| if (m_frame->selection().isRange()) { |
| focusDocumentView(); |
| return true; |
| @@ -3015,19 +2604,7 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) |
| HitTestRequest request(HitTestRequest::Active); |
| MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, positionInContents, event); |
| - if (!m_frame->selection().contains(positionInContents) |
| - && !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 |
| - |
| - if (mev.hitTestResult().isMisspelled()) |
| - selectClosestMisspellingFromMouseEvent(mev); |
| - else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick()) |
| - selectClosestWordOrLinkFromMouseEvent(mev); |
| - } |
| + selectionController().selectionForContextMenu(mev, positionInContents); |
| return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.innerNode(), 0, event, false); |
| } |
| @@ -3513,7 +3090,7 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, DragIni |
| } |
| if (!m_mouseDownMayStartDrag) |
| - return initiator == DragInitiator::Mouse && !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; |
| + return initiator == DragInitiator::Mouse && !selectionController().allowSelection() && !m_mouseDownMayStartAutoscroll; |
| // We are starting a text/image/url drag, so the cursor should be an arrow |
| // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer). |
| @@ -3740,6 +3317,11 @@ bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& |
| return true; |
| } |
| +void EventHandler::updateSelectionForMouseDrag() |
| +{ |
| + selectionController().updateSelectionForMouseDrag(m_mousePressNode, m_dragStartPos, m_lastKnownMouseGlobalPosition); |
| +} |
| + |
| // If scrollbar (under mouse) is different from last, send a mouse exited. Set |
| // last to scrollbar if setLast is true; else set last to 0. |
| void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast) |
| @@ -4084,14 +3666,7 @@ bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& m |
| // 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); |
| - } |
| - |
| + selectionController().releaseSelection(mev); |
| subframe->eventHandler().handleMousePressEvent(mev.event()); |
| return true; |
| } |