2 * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "EventHandler.h"
31 #include "AXObjectCache.h"
32 #include "AutoscrollController.h"
33 #include "BackForwardController.h"
34 #include "CachedImage.h"
36 #include "ChromeClient.h"
38 #include "CursorList.h"
40 #include "DocumentEventQueue.h"
41 #include "DragController.h"
42 #include "DragState.h"
44 #include "EditorClient.h"
45 #include "EventNames.h"
47 #include "FloatPoint.h"
48 #include "FloatRect.h"
49 #include "FocusController.h"
50 #include "FrameLoader.h"
51 #include "FrameSelection.h"
52 #include "FrameTree.h"
53 #include "FrameView.h"
54 #include "HTMLFrameElement.h"
55 #include "HTMLFrameSetElement.h"
56 #include "HTMLHtmlElement.h"
57 #include "HTMLIFrameElement.h"
58 #include "HTMLInputElement.h"
59 #include "HTMLNames.h"
60 #include "HitTestRequest.h"
61 #include "HitTestResult.h"
63 #include "InspectorInstrumentation.h"
64 #include "KeyboardEvent.h"
66 #include "MainFrame.h"
67 #include "MouseEvent.h"
68 #include "MouseEventWithHitTestResults.h"
70 #include "PageOverlayController.h"
71 #include "PlatformEvent.h"
72 #include "PlatformKeyboardEvent.h"
73 #include "PlatformWheelEvent.h"
74 #include "PluginDocument.h"
75 #include "RenderFrameSet.h"
76 #include "RenderLayer.h"
77 #include "RenderListBox.h"
78 #include "RenderNamedFlowThread.h"
79 #include "RenderTextControlSingleLine.h"
80 #include "RenderView.h"
81 #include "RenderWidget.h"
82 #include "RuntimeApplicationChecks.h"
83 #include "SVGDocument.h"
85 #include "ScrollLatchingState.h"
86 #include "Scrollbar.h"
88 #include "ShadowRoot.h"
89 #include "SpatialNavigation.h"
90 #include "StyleCachedImage.h"
91 #include "TextEvent.h"
92 #include "TextIterator.h"
93 #include "UserGestureIndicator.h"
94 #include "UserTypingGestureIndicator.h"
95 #include "VisibleUnits.h"
96 #include "WheelEvent.h"
97 #include "WindowsKeyboardCodes.h"
98 #include "htmlediting.h"
99 #include <wtf/Assertions.h>
100 #include <wtf/CurrentTime.h>
101 #include <wtf/NeverDestroyed.h>
102 #include <wtf/StdLibExtras.h>
103 #include <wtf/WeakPtr.h>
105 #if ENABLE(IOS_TOUCH_EVENTS)
106 #include "PlatformTouchEventIOS.h"
109 #if ENABLE(TOUCH_EVENTS)
110 #include "TouchEvent.h"
111 #include "TouchList.h"
114 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
115 #include "PlatformTouchEvent.h"
118 #if ENABLE(MAC_GESTURE_EVENTS)
119 #include "PlatformGestureEventMac.h"
122 #if ENABLE(POINTER_LOCK)
123 #include "PointerLockController.h"
128 using namespace HTMLNames;
130 #if ENABLE(DRAG_SUPPORT)
131 // The link drag hysteresis is much larger than the others because there
132 // needs to be enough space to cancel the link press without starting a link drag,
133 // and because dragging links is rare.
134 const int LinkDragHysteresis = 40;
135 const int ImageDragHysteresis = 5;
136 const int TextDragHysteresis = 3;
137 const int GeneralDragHysteresis = 3;
138 #endif // ENABLE(DRAG_SUPPORT)
140 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
141 const float GestureUnknown = 0;
144 #if ENABLE(IOS_TOUCH_EVENTS)
145 // FIXME: Share this constant with EventHandler and SliderThumbElement.
146 const unsigned InvalidTouchIdentifier = 0;
149 // Match key code of composition keydown event on windows.
150 // IE sends VK_PROCESSKEY which has value 229;
151 const int CompositionEventKeyCode = 229;
153 using namespace SVGNames;
155 #if !ENABLE(IOS_TOUCH_EVENTS)
156 // The amount of time to wait before sending a fake mouse event, triggered
157 // during a scroll. The short interval is used if the content responds to the mouse events
158 // in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used.
159 const double fakeMouseMoveDurationThreshold = 0.01;
160 const double fakeMouseMoveShortInterval = 0.1;
161 const double fakeMouseMoveLongInterval = 0.25;
164 #if ENABLE(CURSOR_SUPPORT)
165 // The amount of time to wait for a cursor update on style and layout changes
166 // Set to 50Hz, no need to be faster than common screen refresh rate
167 const double cursorUpdateInterval = 0.02;
169 const int maximumCursorSize = 128;
172 #if ENABLE(MOUSE_CURSOR_SCALE)
173 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
174 // need to ensure here is that the scale isn't so small that integer overflow can occur when
175 // dividing cursor sizes (limited above) by the scale.
176 const double minimumCursorScale = 0.001;
179 enum NoCursorChangeType { NoCursorChange };
181 class OptionalCursor {
183 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
184 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
186 bool isCursorChange() const { return m_isCursorChange; }
187 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
190 bool m_isCursorChange;
194 class MaximumDurationTracker {
196 explicit MaximumDurationTracker(double *maxDuration)
197 : m_maxDuration(maxDuration)
198 , m_start(monotonicallyIncreasingTime())
202 ~MaximumDurationTracker()
204 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
208 double* m_maxDuration;
212 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
213 class SyntheticTouchPoint : public PlatformTouchPoint {
216 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
217 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
219 const static int idDefaultValue = 0;
220 const static int radiusYDefaultValue = 1;
221 const static int radiusXDefaultValue = 1;
222 const static float rotationAngleDefaultValue = 0.0f;
223 const static float forceDefaultValue = 1.0f;
225 m_id = idDefaultValue; // There is only one active TouchPoint.
226 m_screenPos = event.globalPosition();
227 m_pos = event.position();
228 m_radiusY = radiusYDefaultValue;
229 m_radiusX = radiusXDefaultValue;
230 m_rotationAngle = rotationAngleDefaultValue;
231 m_force = forceDefaultValue;
233 PlatformEvent::Type type = event.type();
234 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
237 case PlatformEvent::MouseMoved:
238 m_state = TouchMoved;
240 case PlatformEvent::MousePressed:
241 m_state = TouchPressed;
243 case PlatformEvent::MouseReleased:
244 m_state = TouchReleased;
247 ASSERT_NOT_REACHED();
253 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
255 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
257 switch (event.type()) {
258 case PlatformEvent::MouseMoved:
261 case PlatformEvent::MousePressed:
264 case PlatformEvent::MouseReleased:
268 ASSERT_NOT_REACHED();
272 m_timestamp = event.timestamp();
273 m_modifiers = event.modifiers();
274 m_touchPoints.append(SyntheticTouchPoint(event));
277 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
279 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
282 case WheelEvent::DOM_DELTA_PAGE:
284 case WheelEvent::DOM_DELTA_LINE:
286 case WheelEvent::DOM_DELTA_PIXEL:
287 return ScrollByPixel;
289 return ScrollByPixel;
293 static inline bool didScrollInScrollableArea(ScrollableArea* scrollableArea, WheelEvent& wheelEvent)
295 ScrollGranularity scrollGranularity = wheelGranularityToScrollGranularity(wheelEvent.deltaMode());
296 bool didHandleWheelEvent = false;
297 if (float absoluteDelta = std::abs(wheelEvent.deltaX()))
298 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent.deltaX() > 0 ? ScrollRight : ScrollLeft, scrollGranularity, absoluteDelta);
300 if (float absoluteDelta = std::abs(wheelEvent.deltaY()))
301 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent.deltaY() > 0 ? ScrollDown : ScrollUp, scrollGranularity, absoluteDelta);
303 return didHandleWheelEvent;
306 static inline bool handleWheelEventInAppropriateEnclosingBox(Node* startNode, WheelEvent& wheelEvent, Element** stopElement, const FloatSize& filteredPlatformDelta, const FloatSize& filteredVelocity)
308 bool shouldHandleEvent = wheelEvent.deltaX() || wheelEvent.deltaY();
310 shouldHandleEvent |= wheelEvent.phase() == PlatformWheelEventPhaseEnded;
311 #if ENABLE(CSS_SCROLL_SNAP)
312 shouldHandleEvent |= wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded;
315 if (!startNode->renderer() || !shouldHandleEvent)
318 RenderBox& initialEnclosingBox = startNode->renderer()->enclosingBox();
319 if (initialEnclosingBox.isListBox())
320 return didScrollInScrollableArea(static_cast<RenderListBox*>(&initialEnclosingBox), wheelEvent);
322 RenderBox* currentEnclosingBox = &initialEnclosingBox;
323 while (currentEnclosingBox) {
324 if (RenderLayer* boxLayer = currentEnclosingBox->layer()) {
325 const PlatformWheelEvent* platformEvent = wheelEvent.wheelEvent();
326 bool scrollingWasHandled;
327 if (platformEvent != nullptr) {
328 auto copiedEvent = platformEvent->copyWithDeltasAndVelocity(filteredPlatformDelta.width(), filteredPlatformDelta.height(), filteredVelocity);
329 scrollingWasHandled = boxLayer->handleWheelEvent(copiedEvent);
331 scrollingWasHandled = didScrollInScrollableArea(boxLayer, wheelEvent);
333 if (scrollingWasHandled) {
335 *stopElement = currentEnclosingBox->element();
340 if (stopElement && *stopElement && *stopElement == currentEnclosingBox->element())
343 currentEnclosingBox = currentEnclosingBox->containingBlock();
344 if (currentEnclosingBox && currentEnclosingBox->isRenderNamedFlowThread())
345 currentEnclosingBox = RenderNamedFlowThread::fragmentFromRenderBoxAsRenderBlock(currentEnclosingBox, roundedIntPoint(wheelEvent.absoluteLocation()), initialEnclosingBox);
346 if (!currentEnclosingBox || currentEnclosingBox->isRenderView())
352 #if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS))
353 static inline bool shouldGesturesTriggerActive()
355 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
356 // rely on them to set the active state. Unfortunately there's no generic way to
357 // know in advance what event types are supported.
364 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
369 #if ENABLE(DRAG_SUPPORT)
370 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
378 EventHandler::EventHandler(Frame& frame)
380 , m_hoverTimer(*this, &EventHandler::hoverTimerFired)
381 #if ENABLE(CURSOR_SUPPORT)
382 , m_cursorUpdateTimer(*this, &EventHandler::cursorUpdateTimerFired)
385 , m_pendingMomentumWheelEventsTimer(*this, &EventHandler::clearLatchedState)
387 , m_autoscrollController(std::make_unique<AutoscrollController>())
388 #if !ENABLE(IOS_TOUCH_EVENTS)
389 , m_fakeMouseMoveEventTimer(*this, &EventHandler::fakeMouseMoveEventTimerFired)
391 #if ENABLE(CURSOR_VISIBILITY)
392 , m_autoHideCursorTimer(*this, &EventHandler::autoHideCursorTimerFired)
397 EventHandler::~EventHandler()
399 #if !ENABLE(IOS_TOUCH_EVENTS)
400 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
402 #if ENABLE(CURSOR_VISIBILITY)
403 ASSERT(!m_autoHideCursorTimer.isActive());
407 #if ENABLE(DRAG_SUPPORT)
408 DragState& EventHandler::dragState()
410 static NeverDestroyed<DragState> state;
413 #endif // ENABLE(DRAG_SUPPORT)
415 void EventHandler::clear()
418 #if ENABLE(CURSOR_SUPPORT)
419 m_cursorUpdateTimer.stop();
421 #if !ENABLE(IOS_TOUCH_EVENTS)
422 m_fakeMouseMoveEventTimer.stop();
424 #if ENABLE(CURSOR_VISIBILITY)
425 cancelAutoHideCursorTimer();
427 m_resizeLayer = nullptr;
428 m_elementUnderMouse = nullptr;
429 m_lastElementUnderMouse = nullptr;
430 m_lastMouseMoveEventSubframe = nullptr;
431 m_lastScrollbarUnderMouse = nullptr;
433 m_clickNode = nullptr;
434 #if ENABLE(IOS_GESTURE_EVENTS)
435 m_gestureInitialDiameter = GestureUnknown;
436 m_gestureInitialRotation = GestureUnknown;
438 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
439 m_gestureLastDiameter = GestureUnknown;
440 m_gestureLastRotation = GestureUnknown;
441 m_gestureTargets.clear();
443 #if ENABLE(IOS_TOUCH_EVENTS)
445 m_firstTouchID = InvalidTouchIdentifier;
446 m_touchEventTargetSubframe = nullptr;
448 m_frameSetBeingResized = nullptr;
449 #if ENABLE(DRAG_SUPPORT)
450 m_dragTarget = nullptr;
451 m_shouldOnlyFireDragOverEvent = false;
453 m_mousePositionIsUnknown = true;
454 m_lastKnownMousePosition = IntPoint();
455 m_lastKnownMouseGlobalPosition = IntPoint();
456 m_mousePressNode = nullptr;
457 m_mousePressed = false;
458 m_capturesDragging = false;
459 m_capturingMouseEventsElement = nullptr;
461 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
462 m_originatingTouchPointTargets.clear();
463 m_originatingTouchPointDocument = nullptr;
464 m_originatingTouchPointTargetKey = 0;
466 m_maxMouseMovedDuration = 0;
467 m_baseEventType = PlatformEvent::NoType;
468 m_didStartDrag = false;
471 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
473 if (nodeToBeRemoved.contains(m_clickNode.get()))
474 m_clickNode = nullptr;
477 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
479 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection))
480 selection.setSelection(newSelection);
483 static inline bool dispatchSelectStart(Node* node)
485 if (!node || !node->renderer())
488 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
491 static Node* nodeToSelectOnMouseDownForNode(Node& targetNode)
493 #if ENABLE(USERSELECT_ALL)
494 if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(&targetNode))
495 return rootUserSelectAll;
498 if (targetNode.shouldSelectOnMouseDown())
504 static VisibleSelection expandSelectionToRespectSelectOnMouseDown(Node& targetNode, const VisibleSelection& selection)
506 Node* nodeToSelect = nodeToSelectOnMouseDownForNode(targetNode);
510 VisibleSelection newSelection(selection);
511 newSelection.setBase(positionBeforeNode(nodeToSelect).upstream(CanCrossEditingBoundary));
512 newSelection.setExtent(positionAfterNode(nodeToSelect).downstream(CanCrossEditingBoundary));
517 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
519 if (Position::nodeIsUserSelectNone(targetNode))
522 if (!dispatchSelectStart(targetNode))
525 if (selection.isRange())
526 m_selectionInitiationState = ExtendedSelection;
528 granularity = CharacterGranularity;
529 m_selectionInitiationState = PlacedCaret;
532 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity);
537 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
539 Node* targetNode = result.targetNode();
540 VisibleSelection newSelection;
542 if (targetNode && targetNode->renderer()) {
543 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
544 if (pos.isNotNull()) {
545 newSelection = VisibleSelection(pos);
546 newSelection.expandUsingGranularity(WordGranularity);
549 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
550 newSelection.appendTrailingWhitespace();
552 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
556 static AppendTrailingWhitespace shouldAppendTrailingWhitespace(const MouseEventWithHitTestResults& result, const Frame& frame)
558 return (result.event().clickCount() == 2 && frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace;
561 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
563 if (m_mouseDownMayStartSelect)
564 selectClosestWordFromHitTestResult(result.hitTestResult(), shouldAppendTrailingWhitespace(result, m_frame));
568 VisibleSelection EventHandler::selectClosestWordFromHitTestResultBasedOnLookup(const HitTestResult&)
570 return VisibleSelection();
574 void EventHandler::selectClosestContextualWordFromMouseEvent(const MouseEventWithHitTestResults& mouseEvent)
576 Node* targetNode = mouseEvent.targetNode();
577 const HitTestResult& result = mouseEvent.hitTestResult();
578 VisibleSelection newSelection;
579 bool appendTrailingWhitespace = shouldAppendTrailingWhitespace(mouseEvent, m_frame);
581 if (targetNode && targetNode->renderer()) {
582 newSelection = selectClosestWordFromHitTestResultBasedOnLookup(result);
583 if (newSelection.isNone()) {
584 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
585 if (pos.isNotNull()) {
586 newSelection = VisibleSelection(pos);
587 newSelection.expandUsingGranularity(WordGranularity);
591 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
592 newSelection.appendTrailingWhitespace();
594 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
598 void EventHandler::selectClosestContextualWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
600 Element* urlElement = result.hitTestResult().URLElement();
601 if (!urlElement || !isDraggableLink(*urlElement)) {
602 if (Node* targetNode = result.targetNode()) {
603 if (isEditableNode(*targetNode))
604 return selectClosestWordFromMouseEvent(result);
607 return selectClosestContextualWordFromMouseEvent(result);
610 Node* targetNode = result.targetNode();
612 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) {
613 VisibleSelection newSelection;
614 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
615 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(*urlElement))
616 newSelection = VisibleSelection::selectionFromContentsOfNode(urlElement);
618 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
622 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
624 if (event.event().button() != LeftButton)
627 if (m_frame.selection().isRange())
628 // A double-click when range is already selected
629 // should not change the selection. So, do not call
630 // selectClosestWordFromMouseEvent, but do set
631 // m_beganSelectingText to prevent handleMouseReleaseEvent
632 // from setting caret selection.
633 m_selectionInitiationState = ExtendedSelection;
635 selectClosestWordFromMouseEvent(event);
640 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
642 if (event.event().button() != LeftButton)
645 Node* targetNode = event.targetNode();
646 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
649 VisibleSelection newSelection;
650 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
651 if (pos.isNotNull()) {
652 newSelection = VisibleSelection(pos);
653 newSelection.expandUsingGranularity(ParagraphGranularity);
656 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), ParagraphGranularity);
659 static int textDistance(const Position& start, const Position& end)
661 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
662 return TextIterator::rangeLength(range.get(), true);
665 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
667 Ref<Frame> protectedFrame(m_frame);
669 m_frame.document()->updateLayoutIgnorePendingStylesheets();
670 Node* targetNode = event.targetNode();
671 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
674 // Extend the selection if the Shift key is down, unless the click is in a link.
675 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
677 // Don't restart the selection when the mouse is pressed on an
678 // existing selection so we can allow for text dragging.
679 if (FrameView* view = m_frame.view()) {
680 LayoutPoint vPoint = view->windowToContents(event.event().position());
681 if (!extendSelection && m_frame.selection().contains(vPoint)) {
682 m_mouseDownWasSingleClickInSelection = true;
687 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
688 if (visiblePos.isNull())
689 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM);
690 Position pos = visiblePos.deepEquivalent();
692 VisibleSelection newSelection = m_frame.selection().selection();
693 TextGranularity granularity = CharacterGranularity;
695 if (extendSelection && newSelection.isCaretOrRange()) {
696 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectSelectOnMouseDown(*targetNode, VisibleSelection(pos));
697 if (selectionInUserSelectAll.isRange()) {
698 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
699 pos = selectionInUserSelectAll.start();
700 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
701 pos = selectionInUserSelectAll.end();
704 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) {
705 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
706 // was created right-to-left
707 Position start = newSelection.start();
708 Position end = newSelection.end();
709 int distanceToStart = textDistance(start, pos);
710 int distanceToEnd = textDistance(pos, end);
711 if (distanceToStart <= distanceToEnd)
712 newSelection = VisibleSelection(end, pos);
714 newSelection = VisibleSelection(start, pos);
716 newSelection.setExtent(pos);
718 if (m_frame.selection().granularity() != CharacterGranularity) {
719 granularity = m_frame.selection().granularity();
720 newSelection.expandUsingGranularity(m_frame.selection().granularity());
723 newSelection = expandSelectionToRespectSelectOnMouseDown(*targetNode, visiblePos);
725 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity);
727 if (event.event().button() == MiddleButton) {
728 // Ignore handled, since we want to paste to where the caret was placed anyway.
729 handled = handlePasteGlobalSelection(event.event()) || handled;
734 static inline bool canMouseDownStartSelect(Node* node)
736 if (!node || !node->renderer())
739 return node->canStartSelection() || Position::nodeIsUserSelectAll(node);
742 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
744 Ref<Frame> protectedFrame(m_frame);
746 #if ENABLE(DRAG_SUPPORT)
748 dragState().source = nullptr;
751 #if !ENABLE(IOS_TOUCH_EVENTS)
752 cancelFakeMouseMoveEvent();
755 m_frame.document()->updateLayoutIgnorePendingStylesheets();
757 if (ScrollView* scrollView = m_frame.view()) {
758 if (scrollView->isPointInScrollbarCorner(event.event().position()))
762 bool singleClick = event.event().clickCount() <= 1;
764 // If we got the event back, that must mean it wasn't prevented,
765 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
766 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
768 #if ENABLE(DRAG_SUPPORT)
769 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
770 // FIXME: eventMayStartDrag() does not check for shift key press, link or image event targets.
771 // Bug: https://bugs.webkit.org/show_bug.cgi?id=155390
773 // Single mouse down on links or images can always trigger drag-n-drop.
774 bool isMouseDownOnLinkOrImage = event.isOverLink() || event.hitTestResult().image();
775 m_mouseDownMayStartDrag = singleClick && (!event.event().shiftKey() || isMouseDownOnLinkOrImage);
778 m_mouseDownWasSingleClickInSelection = false;
780 m_mouseDown = event.event();
782 if (m_immediateActionStage != ImmediateActionStage::PerformedHitTest)
783 m_immediateActionStage = ImmediateActionStage::None;
785 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
788 if (is<SVGDocument>(*m_frame.document()) && downcast<SVGDocument>(*m_frame.document()).zoomAndPanEnabled()) {
789 if (event.event().shiftKey() && singleClick) {
791 downcast<SVGDocument>(*m_frame.document()).startPan(m_frame.view()->windowToContents(event.event().position()));
796 // We don't do this at the start of mouse down handling,
797 // because we don't want to do it until we know we didn't hit a widget.
801 m_mousePressNode = event.targetNode();
802 m_frame.document()->setFocusNavigationStartingNode(event.targetNode());
803 #if ENABLE(DRAG_SUPPORT)
804 m_dragStartPos = event.event().position();
807 bool swallowEvent = false;
808 m_mousePressed = true;
809 m_selectionInitiationState = HaveNotStartedSelection;
811 if (event.event().clickCount() == 2)
812 swallowEvent = handleMousePressEventDoubleClick(event);
813 else if (event.event().clickCount() >= 3)
814 swallowEvent = handleMousePressEventTripleClick(event);
816 swallowEvent = handleMousePressEventSingleClick(event);
818 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
819 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
824 #if ENABLE(DRAG_SUPPORT)
825 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
830 Ref<Frame> protectedFrame(m_frame);
832 if (handleDrag(event, ShouldCheckDragHysteresis))
835 Node* targetNode = event.targetNode();
836 if (event.event().button() != LeftButton || !targetNode)
839 RenderObject* renderer = targetNode->renderer();
841 Element* parent = targetNode->parentOrShadowHostElement();
845 renderer = parent->renderer();
846 if (!renderer || !renderer->isListBox())
850 #if PLATFORM(COCOA) // FIXME: Why does this assertion fire on other platforms?
851 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
854 m_mouseDownMayStartDrag = false;
856 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
857 m_autoscrollController->startAutoscrollForSelection(renderer);
858 m_mouseDownMayStartAutoscroll = false;
861 if (m_selectionInitiationState != ExtendedSelection) {
862 HitTestResult result(m_mouseDownPos);
863 m_frame.document()->renderView()->hitTest(HitTestRequest(), result);
865 updateSelectionForMouseDrag(result);
867 updateSelectionForMouseDrag(event.hitTestResult());
871 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
873 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
874 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
875 // in handleMousePressEvent
876 RenderView* renderView = m_frame.contentRenderer();
880 if (event.button() != LeftButton || event.clickCount() != 1)
883 FrameView* view = m_frame.view();
887 Page* page = m_frame.page();
891 Ref<Frame> protectedFrame(m_frame);
893 updateDragSourceActionsAllowed();
894 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
895 HitTestResult result(view->windowToContents(event.position()));
896 renderView->hitTest(request, result);
898 Element* targetElement = result.targetElement();
899 return targetElement && page->dragController().draggableElement(&m_frame, targetElement, result.roundedPointInInnerNodeFrame(), state);
902 void EventHandler::updateSelectionForMouseDrag()
904 FrameView* view = m_frame.view();
907 RenderView* renderView = m_frame.contentRenderer();
911 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
912 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
913 renderView->hitTest(request, result);
914 updateSelectionForMouseDrag(result);
917 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
919 FloatPoint selectionEndPoint = localPoint;
920 Element* editableElement = selection.rootEditableElement();
922 if (!targetNode->renderer())
923 return VisiblePosition();
925 if (editableElement && !editableElement->contains(targetNode)) {
926 if (!editableElement->renderer())
927 return VisiblePosition();
929 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
930 selectionEndPoint = editableElement->renderer()->absoluteToLocal(absolutePoint);
931 targetNode = editableElement;
934 return targetNode->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr);
937 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
939 if (!m_mouseDownMayStartSelect)
942 Node* target = hitTestResult.targetNode();
946 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target);
948 // Don't modify the selection if we're not on a node.
949 if (targetPosition.isNull())
952 // Restart the selection if this is the first mouse move. This work is usually
953 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
954 VisibleSelection newSelection = m_frame.selection().selection();
956 // Special case to limit selection to the containing block for SVG text.
957 // FIXME: Isn't there a better non-SVG-specific way to do this?
958 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
959 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
960 if (selectionBaseRenderer->isSVGText())
961 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
964 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
967 if (m_selectionInitiationState != ExtendedSelection) {
968 // Always extend selection here because it's caused by a mouse drag
969 m_selectionInitiationState = ExtendedSelection;
970 newSelection = VisibleSelection(targetPosition);
973 #if ENABLE(USERSELECT_ALL)
974 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
975 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
976 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
977 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
979 // Reset base for user select all when base is inside user-select-all area and extent < base.
980 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
981 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
983 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
984 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
985 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
986 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
987 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
989 newSelection.setExtent(targetPosition);
992 newSelection.setExtent(targetPosition);
995 if (m_frame.selection().granularity() != CharacterGranularity)
996 newSelection.expandUsingGranularity(m_frame.selection().granularity());
998 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
999 FrameSelection::AdjustEndpointsAtBidiBoundary);
1001 #endif // ENABLE(DRAG_SUPPORT)
1003 void EventHandler::lostMouseCapture()
1005 m_frame.selection().setCaretBlinkingSuspended(false);
1008 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
1010 if (eventLoopHandleMouseUp(event))
1013 // If this was the first click in the window, we don't even want to clear the selection.
1014 // This case occurs when the user clicks on a draggable element, since we have to process
1015 // the mouse down and drag events to see if we might start a drag. For other first clicks
1016 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1017 // ignored upstream of this layer.
1018 return eventActivatedView(event.event());
1021 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1023 if (autoscrollInProgress())
1024 stopAutoscrollTimer();
1026 Ref<Frame> protectedFrame(m_frame);
1028 if (handleMouseUp(event))
1031 // Used to prevent mouseMoveEvent from initiating a drag before
1032 // the mouse is pressed again.
1033 m_mousePressed = false;
1034 m_capturesDragging = false;
1035 #if ENABLE(DRAG_SUPPORT)
1036 m_mouseDownMayStartDrag = false;
1038 m_mouseDownMayStartSelect = false;
1039 m_mouseDownMayStartAutoscroll = false;
1040 m_mouseDownWasInSubframe = false;
1042 bool handled = false;
1044 // Clear the selection if the mouse didn't move after the last mouse
1045 // press and it's not a context menu click. We do this so when clicking
1046 // on the selection, the selection goes away. However, if we are
1047 // editing, place the caret.
1048 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
1049 #if ENABLE(DRAG_SUPPORT)
1050 && m_dragStartPos == event.event().position()
1052 && m_frame.selection().isRange()
1053 && event.event().button() != RightButton) {
1054 VisibleSelection newSelection;
1055 Node* node = event.targetNode();
1056 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
1057 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
1058 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint(), nullptr);
1059 newSelection = VisibleSelection(pos);
1062 setSelectionIfNeeded(m_frame.selection(), newSelection);
1067 if (event.event().button() == MiddleButton) {
1068 // Ignore handled, since we want to paste to where the caret was placed anyway.
1069 handled = handlePasteGlobalSelection(event.event()) || handled;
1075 #if ENABLE(PAN_SCROLLING)
1077 void EventHandler::didPanScrollStart()
1079 m_autoscrollController->didPanScrollStart();
1082 void EventHandler::didPanScrollStop()
1084 m_autoscrollController->didPanScrollStop();
1087 void EventHandler::startPanScrolling(RenderElement* renderer)
1090 if (!is<RenderBox>(*renderer))
1092 m_autoscrollController->startPanScrolling(downcast<RenderBox>(renderer), lastKnownMousePosition());
1097 #endif // ENABLE(PAN_SCROLLING)
1099 RenderBox* EventHandler::autoscrollRenderer() const
1101 return m_autoscrollController->autoscrollRenderer();
1104 void EventHandler::updateAutoscrollRenderer()
1106 m_autoscrollController->updateAutoscrollRenderer();
1109 bool EventHandler::autoscrollInProgress() const
1111 return m_autoscrollController->autoscrollInProgress();
1114 bool EventHandler::panScrollInProgress() const
1116 return m_autoscrollController->panScrollInProgress();
1119 #if ENABLE(DRAG_SUPPORT)
1120 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1122 Page* page = m_frame.page();
1124 return DragSourceActionNone;
1126 FrameView* view = m_frame.view();
1128 return DragSourceActionNone;
1130 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1132 #endif // ENABLE(DRAG_SUPPORT)
1134 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1136 Ref<Frame> protectedFrame(m_frame);
1138 // We always send hitTestResultAtPoint to the main frame if we have one,
1139 // otherwise we might hit areas that are obscured by higher frames.
1140 if (!m_frame.isMainFrame()) {
1141 Frame& mainFrame = m_frame.mainFrame();
1142 FrameView* frameView = m_frame.view();
1143 FrameView* mainView = mainFrame.view();
1144 if (frameView && mainView) {
1145 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
1146 return mainFrame.eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
1150 unsigned nonNegativePaddingWidth = std::max<LayoutUnit>(0, padding.width()).toUnsigned();
1151 unsigned nonNegativePaddingHeight = std::max<LayoutUnit>(0, padding.height()).toUnsigned();
1153 // We should always start hit testing a clean tree.
1154 if (auto* frameView = m_frame.view())
1155 frameView->updateLayoutAndStyleIfNeededRecursive();
1157 HitTestResult result(point, nonNegativePaddingHeight, nonNegativePaddingWidth, nonNegativePaddingHeight, nonNegativePaddingWidth);
1158 RenderView* renderView = m_frame.contentRenderer();
1162 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
1163 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
1164 renderView->hitTest(request, result);
1165 if (!request.readOnly())
1166 m_frame.document()->updateHoverActiveState(request, result.targetElement());
1168 if (request.disallowsUserAgentShadowContent())
1169 result.setToNonUserAgentShadowAncestor();
1174 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1176 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed);
1179 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1181 Node* node = startingNode;
1184 node = m_frame.document()->focusedElement();
1187 node = m_mousePressNode.get();
1190 auto r = node->renderer();
1191 if (r && !r->isListBox() && r->enclosingBox().scroll(direction, granularity)) {
1192 setFrameWasScrolledByUser();
1200 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1202 Node* node = startingNode;
1205 node = m_frame.document()->focusedElement();
1208 node = m_mousePressNode.get();
1211 auto r = node->renderer();
1212 if (r && !r->isListBox() && r->enclosingBox().logicalScroll(direction, granularity)) {
1213 setFrameWasScrolledByUser();
1221 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1223 Ref<Frame> protectedFrame(m_frame);
1225 // The layout needs to be up to date to determine if we can scroll. We may be
1226 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1227 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1228 if (scrollOverflow(direction, granularity, startingNode))
1230 Frame* frame = &m_frame;
1231 FrameView* view = frame->view();
1232 if (view && view->scroll(direction, granularity))
1234 frame = frame->tree().parent();
1237 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement());
1240 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1242 Ref<Frame> protectedFrame(m_frame);
1244 // The layout needs to be up to date to determine if we can scroll. We may be
1245 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1246 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1247 if (logicalScrollOverflow(direction, granularity, startingNode))
1249 Frame* frame = &m_frame;
1250 FrameView* view = frame->view();
1252 bool scrolled = false;
1254 // Mac also resets the scroll position in the inline direction.
1255 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1258 if (view && view->logicalScroll(direction, granularity))
1264 frame = frame->tree().parent();
1268 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement());
1271 IntPoint EventHandler::lastKnownMousePosition() const
1273 return m_lastKnownMousePosition;
1276 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1278 if (!hitTestResult.isOverWidget())
1280 return subframeForTargetNode(hitTestResult.targetNode());
1283 Frame* EventHandler::subframeForTargetNode(Node* node)
1288 auto renderer = node->renderer();
1289 if (!is<RenderWidget>(renderer))
1292 Widget* widget = downcast<RenderWidget>(*renderer).widget();
1293 if (!is<FrameView>(widget))
1296 return &downcast<FrameView>(*widget).frame();
1299 #if ENABLE(CURSOR_SUPPORT)
1300 static bool isSubmitImage(Node* node)
1302 return is<HTMLInputElement>(node) && downcast<HTMLInputElement>(*node).isImageButton();
1305 // Returns true if the node's editable block is not current focused for editing
1306 static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame)
1308 return frame.selection().selection().rootEditableElement() != node.rootEditableElement();
1311 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1316 bool editable = node->hasEditableStyle();
1317 bool editableLinkEnabled = false;
1319 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1321 switch (m_frame.settings().editableLinkBehavior()) {
1323 case EditableLinkDefaultBehavior:
1324 case EditableLinkAlwaysLive:
1325 editableLinkEnabled = true;
1328 case EditableLinkNeverLive:
1329 editableLinkEnabled = false;
1332 case EditableLinkLiveWhenNotFocused:
1333 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey;
1336 case EditableLinkOnlyLiveWithShiftKey:
1337 editableLinkEnabled = shiftKey;
1342 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1345 void EventHandler::cursorUpdateTimerFired()
1347 ASSERT(m_frame.document());
1351 void EventHandler::updateCursor()
1353 if (m_mousePositionIsUnknown)
1356 FrameView* view = m_frame.view();
1360 RenderView* renderView = view->renderView();
1364 if (!view->shouldSetCursor())
1371 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1373 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::AllowFrameScrollbars);
1374 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1375 renderView->hitTest(request, result);
1377 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1378 if (optionalCursor.isCursorChange()) {
1379 m_currentMouseCursor = optionalCursor.cursor();
1380 view->setCursor(m_currentMouseCursor);
1384 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1386 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1387 return NoCursorChange;
1389 if (!m_frame.page())
1390 return NoCursorChange;
1392 #if ENABLE(PAN_SCROLLING)
1393 if (m_frame.mainFrame().eventHandler().panScrollInProgress())
1394 return NoCursorChange;
1397 Ref<Frame> protectedFrame(m_frame);
1399 // Use always pointer cursor for scrollbars.
1400 if (result.scrollbar()) {
1401 #if ENABLE(CURSOR_VISIBILITY)
1402 cancelAutoHideCursorTimer();
1404 return pointerCursor();
1407 Node* node = result.targetNode();
1409 return NoCursorChange;
1411 auto renderer = node->renderer();
1412 auto* style = renderer ? &renderer->style() : nullptr;
1413 bool horizontalText = !style || style->isHorizontalWritingMode();
1414 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1416 #if ENABLE(CURSOR_VISIBILITY)
1417 if (style && style->cursorVisibility() == CursorVisibilityAutoHide)
1418 startAutoHideCursorTimer();
1420 cancelAutoHideCursorTimer();
1424 Cursor overrideCursor;
1425 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1426 case SetCursorBasedOnStyle:
1429 return overrideCursor;
1430 case DoNotSetCursor:
1431 return NoCursorChange;
1435 if (style && style->cursors()) {
1436 const CursorList* cursors = style->cursors();
1437 for (unsigned i = 0; i < cursors->size(); ++i) {
1438 StyleImage* styleImage = (*cursors)[i].image();
1441 CachedImage* cachedImage = styleImage->cachedImage();
1444 float scale = styleImage->imageScaleFactor();
1445 // Get hotspot and convert from logical pixels to physical pixels.
1446 IntPoint hotSpot = (*cursors)[i].hotSpot();
1447 FloatSize size = cachedImage->imageForRenderer(renderer)->size();
1448 if (cachedImage->errorOccurred())
1450 // Limit the size of cursors (in UI pixels) so that they cannot be
1451 // used to cover UI elements in chrome.
1452 size.scale(1 / scale);
1453 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1456 Image* image = cachedImage->imageForRenderer(renderer);
1457 #if ENABLE(MOUSE_CURSOR_SCALE)
1458 // Ensure no overflow possible in calculations above.
1459 if (scale < minimumCursorScale)
1461 return Cursor(image, hotSpot, scale);
1464 return Cursor(image, hotSpot);
1465 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1469 // During selection, use an I-beam regardless of the content beneath the cursor.
1470 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1472 && m_mouseDownMayStartSelect
1473 #if ENABLE(DRAG_SUPPORT)
1474 && !m_mouseDownMayStartDrag
1476 && m_frame.selection().isCaretOrRange()
1477 && !m_capturingMouseEventsElement)
1480 switch (style ? style->cursor() : CursorAuto) {
1482 bool editable = node->hasEditableStyle();
1484 if (useHandCursor(node, result.isOverLink(), shiftKey))
1485 return handCursor();
1487 bool inResizer = false;
1489 if (RenderLayer* layer = renderer->enclosingLayer()) {
1490 if (FrameView* view = m_frame.view())
1491 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1495 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1497 return pointerCursor();
1500 return crossCursor();
1502 return handCursor();
1504 return moveCursor();
1505 case CursorAllScroll:
1506 return moveCursor();
1508 return eastResizeCursor();
1510 return westResizeCursor();
1512 return northResizeCursor();
1514 return southResizeCursor();
1515 case CursorNeResize:
1516 return northEastResizeCursor();
1517 case CursorSwResize:
1518 return southWestResizeCursor();
1519 case CursorNwResize:
1520 return northWestResizeCursor();
1521 case CursorSeResize:
1522 return southEastResizeCursor();
1523 case CursorNsResize:
1524 return northSouthResizeCursor();
1525 case CursorEwResize:
1526 return eastWestResizeCursor();
1527 case CursorNeswResize:
1528 return northEastSouthWestResizeCursor();
1529 case CursorNwseResize:
1530 return northWestSouthEastResizeCursor();
1531 case CursorColResize:
1532 return columnResizeCursor();
1533 case CursorRowResize:
1534 return rowResizeCursor();
1536 return iBeamCursor();
1538 return waitCursor();
1540 return helpCursor();
1541 case CursorVerticalText:
1542 return verticalTextCursor();
1544 return cellCursor();
1545 case CursorContextMenu:
1546 return contextMenuCursor();
1547 case CursorProgress:
1548 return progressCursor();
1550 return noDropCursor();
1552 return aliasCursor();
1554 return copyCursor();
1556 return noneCursor();
1557 case CursorNotAllowed:
1558 return notAllowedCursor();
1560 return pointerCursor();
1562 return zoomInCursor();
1564 return zoomOutCursor();
1565 case CursorWebkitGrab:
1566 return grabCursor();
1567 case CursorWebkitGrabbing:
1568 return grabbingCursor();
1570 return pointerCursor();
1572 #endif // ENABLE(CURSOR_SUPPORT)
1574 #if ENABLE(CURSOR_VISIBILITY)
1575 void EventHandler::startAutoHideCursorTimer()
1577 Page* page = m_frame.page();
1581 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
1583 #if !ENABLE(IOS_TOUCH_EVENTS)
1584 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1585 // so cancel any pending fake mouse moves.
1586 if (m_fakeMouseMoveEventTimer.isActive())
1587 m_fakeMouseMoveEventTimer.stop();
1591 void EventHandler::cancelAutoHideCursorTimer()
1593 if (m_autoHideCursorTimer.isActive())
1594 m_autoHideCursorTimer.stop();
1597 void EventHandler::autoHideCursorTimerFired()
1599 m_currentMouseCursor = noneCursor();
1600 FrameView* view = m_frame.view();
1601 if (view && view->isActive())
1602 view->setCursor(m_currentMouseCursor);
1606 static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
1608 FrameView* view = frame.view();
1609 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1610 // Historically the code would just crash; this is clearly no worse than that.
1611 return view ? view->windowToContents(windowPoint) : windowPoint;
1614 static Scrollbar* scrollbarForMouseEvent(const MouseEventWithHitTestResults& mouseEvent, FrameView* view)
1617 if (auto* scrollbar = view->scrollbarAtPoint(mouseEvent.event().position()))
1620 return mouseEvent.scrollbar();
1624 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& platformMouseEvent)
1626 Ref<Frame> protectedFrame(m_frame);
1627 RefPtr<FrameView> protector(m_frame.view());
1629 if (InspectorInstrumentation::handleMousePress(m_frame)) {
1634 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
1637 #if ENABLE(TOUCH_EVENTS)
1638 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1639 if (defaultPrevented)
1643 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
1645 // FIXME (bug 68185): this call should be made at another abstraction layer
1646 m_frame.loader().resetMultipleFormSubmissionProtection();
1648 #if !ENABLE(IOS_TOUCH_EVENTS)
1649 cancelFakeMouseMoveEvent();
1651 m_mousePressed = true;
1652 m_capturesDragging = true;
1653 setLastKnownMousePosition(platformMouseEvent);
1654 m_mouseDownTimestamp = platformMouseEvent.timestamp();
1655 #if ENABLE(DRAG_SUPPORT)
1656 m_mouseDownMayStartDrag = false;
1658 m_mouseDownMayStartSelect = false;
1659 m_mouseDownMayStartAutoscroll = false;
1660 if (FrameView* view = m_frame.view())
1661 m_mouseDownPos = view->windowToContents(platformMouseEvent.position());
1666 m_mouseDownWasInSubframe = false;
1668 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
1669 // Save the document point we generate in case the window coordinate is invalidated by what happens
1670 // when we dispatch the event.
1671 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, platformMouseEvent.position());
1672 MouseEventWithHitTestResults mouseEvent = m_frame.document()->prepareMouseEvent(request, documentPoint, platformMouseEvent);
1674 if (!mouseEvent.targetNode()) {
1679 m_mousePressNode = mouseEvent.targetNode();
1680 m_frame.document()->setFocusNavigationStartingNode(mouseEvent.targetNode());
1682 RefPtr<Frame> subframe = subframeForHitTestResult(mouseEvent);
1683 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe.get())) {
1684 // Start capturing future events for this frame. We only do this if we didn't clear
1685 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1686 m_capturesDragging = subframe->eventHandler().capturesDragging();
1687 if (m_mousePressed && m_capturesDragging) {
1688 m_capturingMouseEventsElement = subframe->ownerElement();
1689 m_eventHandlerWillResetCapturingMouseEventsElement = true;
1695 #if ENABLE(PAN_SCROLLING)
1696 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1697 // because it will set m_autoscrollType to NoAutoscroll on return.
1698 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress();
1699 stopAutoscrollTimer();
1700 if (isPanScrollInProgress) {
1701 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1702 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1708 m_clickCount = platformMouseEvent.clickCount();
1709 m_clickNode = mouseEvent.targetNode();
1716 if (FrameView* view = m_frame.view()) {
1717 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1718 IntPoint p = view->windowToContents(platformMouseEvent.position());
1719 if (layer && layer->isPointInResizeControl(p)) {
1720 layer->setInResizeMode(true);
1721 m_resizeLayer = layer;
1722 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1728 m_frame.selection().setCaretBlinkingSuspended(true);
1730 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1731 m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
1733 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1734 // in case the scrollbar widget was destroyed when the mouse event was handled.
1735 if (mouseEvent.scrollbar()) {
1736 const bool wasLastScrollBar = mouseEvent.scrollbar() == m_lastScrollbarUnderMouse;
1737 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1738 if (wasLastScrollBar && mouseEvent.scrollbar() != m_lastScrollbarUnderMouse)
1739 m_lastScrollbarUnderMouse = nullptr;
1742 if (!swallowEvent) {
1743 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1744 // If a mouse event handler changes the input element type to one that has a widget associated,
1745 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1746 // event target node can't still be the shadow node.
1747 if (is<ShadowRoot>(*mouseEvent.targetNode()) && is<HTMLInputElement>(*downcast<ShadowRoot>(*mouseEvent.targetNode()).host()))
1748 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1751 Scrollbar* scrollbar = scrollbarForMouseEvent(mouseEvent, m_frame.view());
1752 updateLastScrollbarUnderMouse(scrollbar, true);
1754 bool passedToScrollbar = scrollbar && passMousePressEventToScrollbar(mouseEvent, scrollbar);
1755 if (!swallowEvent) {
1756 if (passedToScrollbar)
1757 swallowEvent = true;
1759 swallowEvent = handleMousePressEvent(mouseEvent);
1761 return swallowEvent;
1764 // This method only exists for platforms that don't know how to deliver
1765 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& platformMouseEvent)
1767 Ref<Frame> protectedFrame(m_frame);
1768 RefPtr<FrameView> protector(m_frame.view());
1770 m_frame.selection().setCaretBlinkingSuspended(false);
1772 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
1774 // We get this instead of a second mouse-up
1775 m_mousePressed = false;
1776 setLastKnownMousePosition(platformMouseEvent);
1778 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
1779 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1780 Frame* subframe = subframeForHitTestResult(mouseEvent);
1781 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1782 m_capturingMouseEventsElement = nullptr;
1783 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe))
1786 m_clickCount = platformMouseEvent.clickCount();
1787 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
1789 bool swallowClickEvent = platformMouseEvent.button() != RightButton && mouseEvent.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1791 if (m_lastScrollbarUnderMouse)
1792 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
1794 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mouseEvent);
1798 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1801 static ScrollableArea* enclosingScrollableArea(Node* node)
1803 for (auto ancestor = node; ancestor; ancestor = ancestor->parentOrShadowHostNode()) {
1804 if (is<HTMLIFrameElement>(*ancestor) || is<HTMLHtmlElement>(*ancestor) || is<HTMLDocument>(*ancestor))
1807 auto renderer = ancestor->renderer();
1811 if (is<RenderListBox>(*renderer))
1812 return downcast<RenderListBox>(renderer);
1814 return renderer->enclosingLayer();
1820 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1822 Ref<Frame> protectedFrame(m_frame);
1823 RefPtr<FrameView> protector(m_frame.view());
1824 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1826 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(event))
1829 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1830 bool result = handleMouseMoveEvent(event, &hoveredNode);
1832 Page* page = m_frame.page();
1836 if (auto scrolledArea = enclosingScrollableArea(hoveredNode.innerNode())) {
1837 if (FrameView* frameView = m_frame.view()) {
1838 if (frameView->containsScrollableArea(scrolledArea))
1839 scrolledArea->mouseMovedInContentArea();
1843 if (FrameView* frameView = m_frame.view())
1844 frameView->mouseMovedInContentArea();
1846 hoveredNode.setToNonUserAgentShadowAncestor();
1847 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1848 page->chrome().setToolTip(hoveredNode);
1852 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1854 HitTestResult hoveredNode;
1855 return handleMouseMoveEvent(event, &hoveredNode, true);
1858 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1860 #if ENABLE(TOUCH_EVENTS)
1861 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1862 if (defaultPrevented)
1866 Ref<Frame> protectedFrame(m_frame);
1867 RefPtr<FrameView> protector(m_frame.view());
1869 setLastKnownMousePosition(platformMouseEvent);
1871 if (m_hoverTimer.isActive())
1872 m_hoverTimer.stop();
1874 #if ENABLE(CURSOR_SUPPORT)
1875 m_cursorUpdateTimer.stop();
1878 #if !ENABLE(IOS_TOUCH_EVENTS)
1879 cancelFakeMouseMoveEvent();
1883 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1887 if (m_frameSetBeingResized)
1888 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, platformMouseEvent, false);
1890 // On iOS, our scrollbars are managed by UIKit.
1892 // Send events right to a scrollbar if the mouse is pressed.
1893 if (m_lastScrollbarUnderMouse && m_mousePressed)
1894 return m_lastScrollbarUnderMouse->mouseMoved(platformMouseEvent);
1897 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowFrameScrollbars;
1899 hitType |= HitTestRequest::Active;
1900 else if (onlyUpdateScrollbars) {
1901 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1902 // means that :hover and :active freeze in the state they were in, rather than updating
1903 // for nodes the mouse moves while the window is not key (which will be the case if
1904 // onlyUpdateScrollbars is true).
1905 hitType |= HitTestRequest::ReadOnly;
1908 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
1909 // Treat any mouse move events as readonly if the user is currently touching the screen.
1911 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1913 HitTestRequest request(hitType);
1914 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1916 *hoveredNode = mouseEvent.hitTestResult();
1918 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1919 m_resizeLayer->resize(platformMouseEvent, m_offsetFromResizeCorner);
1921 Scrollbar* scrollbar = mouseEvent.scrollbar();
1922 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1924 // On iOS, our scrollbars are managed by UIKit.
1926 if (!m_mousePressed && scrollbar)
1927 scrollbar->mouseMoved(platformMouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1929 if (onlyUpdateScrollbars) {
1930 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1935 bool swallowEvent = false;
1936 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
1938 // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts.
1939 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1940 passMouseMoveEventToSubframe(mouseEvent, m_lastMouseMoveEventSubframe.get());
1943 // Update over/out state before passing the event to the subframe.
1944 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1946 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1947 // node to be detached from its FrameView, in which case the event should not be passed.
1948 if (newSubframe->view())
1949 swallowEvent |= passMouseMoveEventToSubframe(mouseEvent, newSubframe.get(), hoveredNode);
1950 #if ENABLE(CURSOR_SUPPORT)
1952 if (FrameView* view = m_frame.view()) {
1953 OptionalCursor optionalCursor = selectCursor(mouseEvent.hitTestResult(), platformMouseEvent.shiftKey());
1954 if (optionalCursor.isCursorChange()) {
1955 m_currentMouseCursor = optionalCursor.cursor();
1956 view->setCursor(m_currentMouseCursor);
1962 m_lastMouseMoveEventSubframe = newSubframe;
1967 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
1968 #if ENABLE(DRAG_SUPPORT)
1970 swallowEvent = handleMouseDraggedEvent(mouseEvent);
1971 #endif // ENABLE(DRAG_SUPPORT)
1973 return swallowEvent;
1976 void EventHandler::invalidateClick()
1979 m_clickNode = nullptr;
1982 static Node* targetNodeForClickEvent(Node* mousePressNode, Node* mouseReleaseNode)
1984 if (!mousePressNode || !mouseReleaseNode)
1987 if (mousePressNode == mouseReleaseNode)
1988 return mouseReleaseNode;
1990 Element* mouseReleaseShadowHost = mouseReleaseNode->shadowHost();
1991 if (mouseReleaseShadowHost && mouseReleaseShadowHost == mousePressNode->shadowHost()) {
1992 // We want to dispatch the click to the shadow tree host element to give listeners the illusion that the
1993 // shadom tree is a single element. For example, we want to give the illusion that <input type="range">
1994 // is a single element even though it is a composition of multiple shadom tree elements.
1995 return mouseReleaseShadowHost;
2000 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMouseEvent)
2002 Ref<Frame> protectedFrame(m_frame);
2003 RefPtr<FrameView> protector(m_frame.view());
2005 m_frame.selection().setCaretBlinkingSuspended(false);
2007 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
2010 #if ENABLE(TOUCH_EVENTS)
2011 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
2012 if (defaultPrevented)
2016 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
2018 #if ENABLE(PAN_SCROLLING)
2019 m_autoscrollController->handleMouseReleaseEvent(platformMouseEvent);
2022 m_mousePressed = false;
2023 setLastKnownMousePosition(platformMouseEvent);
2027 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
2031 if (m_frameSetBeingResized)
2032 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, platformMouseEvent, false);
2034 // If an immediate action began or was completed using this series of mouse events, then we should send mouseup to
2035 // the DOM and return now so that we don't perform our own default behaviors.
2036 if (m_immediateActionStage == ImmediateActionStage::ActionCompleted || m_immediateActionStage == ImmediateActionStage::ActionUpdated || m_immediateActionStage == ImmediateActionStage::ActionCancelledAfterUpdate) {
2037 m_immediateActionStage = ImmediateActionStage::None;
2038 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), true, m_clickCount, platformMouseEvent, false);
2040 m_immediateActionStage = ImmediateActionStage::None;
2042 if (m_lastScrollbarUnderMouse) {
2044 m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
2045 bool cancelable = true;
2046 bool setUnder = false;
2047 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
2050 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
2051 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
2052 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
2053 if (m_eventHandlerWillResetCapturingMouseEventsElement)
2054 m_capturingMouseEventsElement = nullptr;
2055 if (subframe && passMouseReleaseEventToSubframe(mouseEvent, subframe))
2058 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
2060 bool contextMenuEvent = platformMouseEvent.button() == RightButton;
2062 Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode());
2063 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true);
2065 if (m_resizeLayer) {
2066 m_resizeLayer->setInResizeMode(false);
2067 m_resizeLayer = nullptr;
2070 bool swallowMouseReleaseEvent = false;
2071 if (!swallowMouseUpEvent)
2072 swallowMouseReleaseEvent = handleMouseReleaseEvent(mouseEvent);
2076 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2079 #if ENABLE(MOUSE_FORCE_EVENTS)
2080 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& event)
2082 Ref<Frame> protectedFrame(m_frame);
2083 RefPtr<FrameView> protector(m_frame.view());
2085 setLastKnownMousePosition(event);
2087 HitTestRequest::HitTestRequestType hitType = HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::Active;
2089 HitTestRequest request(hitType);
2090 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2092 bool swallowedEvent = !dispatchMouseEvent(eventNames().webkitmouseforcechangedEvent, mouseEvent.targetNode(), false, 0, event, false);
2093 if (event.type() == PlatformEvent::MouseForceDown)
2094 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforcedownEvent, mouseEvent.targetNode(), false, 0, event, false);
2095 if (event.type() == PlatformEvent::MouseForceUp)
2096 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforceupEvent, mouseEvent.targetNode(), false, 0, event, false);
2098 return swallowedEvent;
2101 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& )
2105 #endif // #if ENABLE(MOUSE_FORCE_EVENTS)
2107 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& platformMouseEvent)
2109 // If the event was a middle click, attempt to copy global selection in after
2110 // the newly set caret position.
2112 // This code is called from either the mouse up or mouse down handling. There
2113 // is some debate about when the global selection is pasted:
2114 // xterm: pastes on up.
2115 // GTK: pastes on down.
2116 // Qt: pastes on up.
2117 // Firefox: pastes on up.
2118 // Chromium: pastes on up.
2120 // There is something of a webcompat angle to this well, as highlighted by
2121 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
2122 // down then the text is pasted just before the onclick handler runs and
2123 // clears the text box. So it's important this happens after the event
2124 // handlers have been fired.
2126 if (platformMouseEvent.type() != PlatformEvent::MousePressed)
2129 if (platformMouseEvent.type() != PlatformEvent::MouseReleased)
2133 if (!m_frame.page())
2135 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame();
2136 // Do not paste here if the focus was moved somewhere else.
2137 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection())
2138 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute();
2143 #if ENABLE(DRAG_SUPPORT)
2145 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2147 Ref<Frame> protectedFrame(m_frame);
2148 FrameView* view = m_frame.view();
2150 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2154 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2155 Ref<MouseEvent> me = MouseEvent::create(eventType,
2156 true, true, event.timestamp(), m_frame.document()->defaultView(),
2157 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2158 #if ENABLE(POINTER_LOCK)
2159 event.movementDelta().x(), event.movementDelta().y(),
2161 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2162 0, 0, event.force(), NoTap, dataTransfer);
2164 dragTarget.dispatchEvent(me);
2165 return me->defaultPrevented();
2168 static bool targetIsFrame(Node* target, Frame*& frame)
2170 if (!is<HTMLFrameElementBase>(target))
2173 frame = downcast<HTMLFrameElementBase>(*target).contentFrame();
2177 static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation)
2179 if (dragOperation == "copy")
2180 return DragOperationCopy;
2181 if (dragOperation == "move")
2182 return DragOperationMove;
2183 if (dragOperation == "link")
2184 return DragOperationLink;
2185 return DragOperationNone;
2188 static String convertDragOperationToDropZoneOperation(DragOperation operation)
2190 switch (operation) {
2191 case DragOperationCopy:
2192 return ASCIILiteral("copy");
2193 case DragOperationMove:
2194 return ASCIILiteral("move");
2195 case DragOperationLink:
2196 return ASCIILiteral("link");
2198 return ASCIILiteral("copy");
2202 static bool hasDropZoneType(DataTransfer& dataTransfer, const String& keyword)
2204 if (keyword.startsWith("file:"))
2205 return dataTransfer.hasFileOfType(keyword.substring(5));
2207 if (keyword.startsWith("string:"))
2208 return dataTransfer.hasStringOfType(keyword.substring(7));
2213 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
2216 Element* element = is<Element>(*target) ? downcast<Element>(target) : target->parentElement();
2217 for (; element; element = element->parentElement()) {
2218 SpaceSplitString keywords(element->attributeWithoutSynchronization(webkitdropzoneAttr), true);
2219 bool matched = false;
2220 DragOperation dragOperation = DragOperationNone;
2221 for (unsigned i = 0, size = keywords.size(); i < size; ++i) {
2222 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2223 if (op != DragOperationNone) {
2224 if (dragOperation == DragOperationNone)
2227 matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string());
2228 if (matched && dragOperation != DragOperationNone)
2232 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2239 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2241 Ref<Frame> protectedFrame(m_frame);
2243 bool accept = false;
2245 if (!m_frame.view())
2248 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
2249 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2251 RefPtr<Element> newTarget;
2252 if (Node* targetNode = mouseEvent.targetNode()) {
2253 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch)
2254 if (!is<Element>(*targetNode))
2255 newTarget = targetNode->parentOrShadowHostElement();
2257 newTarget = downcast<Element>(targetNode);
2260 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2262 if (m_dragTarget != newTarget) {
2263 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2264 // it is sometimes incorrect when dragging within subframes, as seen with
2265 // LayoutTests/fast/events/drag-in-frames.html.
2267 // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
2269 if (targetIsFrame(newTarget.get(), targetFrame)) {
2271 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2272 } else if (newTarget) {
2273 // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event.
2274 if (dragState().source && dragState().shouldDispatchEvents) {
2275 // for now we don't care if event handler cancels default behavior, since there is none
2276 dispatchDragSrcEvent(eventNames().dragEvent, event);
2278 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, dataTransfer);
2280 accept = findDropZone(newTarget.get(), dataTransfer);
2283 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2285 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2286 } else if (m_dragTarget)
2287 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2290 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2291 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2292 m_shouldOnlyFireDragOverEvent = true;
2296 if (targetIsFrame(newTarget.get(), targetFrame)) {
2298 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2299 } else if (newTarget) {
2300 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2301 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
2302 // for now we don't care if event handler cancels default behavior, since there is none
2303 dispatchDragSrcEvent(eventNames().dragEvent, event);
2305 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, dataTransfer);
2307 accept = findDropZone(newTarget.get(), dataTransfer);
2308 m_shouldOnlyFireDragOverEvent = false;
2311 m_dragTarget = WTFMove(newTarget);
2315 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2317 Ref<Frame> protectedFrame(m_frame);
2320 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2322 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
2323 } else if (m_dragTarget) {
2324 if (dragState().source && dragState().shouldDispatchEvents)
2325 dispatchDragSrcEvent(eventNames().dragEvent, event);
2326 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2331 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2333 Ref<Frame> protectedFrame(m_frame);
2336 bool preventedDefault = false;
2337 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2339 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
2340 } else if (m_dragTarget)
2341 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer);
2343 return preventedDefault;
2346 void EventHandler::clearDragState()
2348 stopAutoscrollTimer();
2349 m_dragTarget = nullptr;
2350 m_capturingMouseEventsElement = nullptr;
2351 m_shouldOnlyFireDragOverEvent = false;
2353 m_sendingEventToSubview = false;
2356 #endif // ENABLE(DRAG_SUPPORT)
2358 void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element)
2360 m_capturingMouseEventsElement = element;
2361 m_eventHandlerWillResetCapturingMouseEventsElement = false;
2364 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent)
2366 Ref<Frame> protectedFrame(m_frame);
2367 ASSERT(m_frame.document());
2368 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mouseEvent.position()), mouseEvent);
2371 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
2376 for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
2377 for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
2378 if (currObj1 == currObj2)
2386 static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName)
2388 for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) {
2389 if (curr->hasCapturingEventListeners(eventName))
2395 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& platformMouseEvent, bool fireMouseOverOut)
2397 Ref<Frame> protectedFrame(m_frame);
2398 Element* targetElement = nullptr;
2400 // If we're capturing, we always go right to that element.
2401 if (m_capturingMouseEventsElement)
2402 targetElement = m_capturingMouseEventsElement.get();
2403 else if (targetNode) {
2404 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646>
2405 while (targetNode && !is<Element>(*targetNode))
2406 targetNode = targetNode->parentInComposedTree();
2407 targetElement = downcast<Element>(targetNode);
2410 m_elementUnderMouse = targetElement;
2412 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2413 if (fireMouseOverOut) {
2414 auto scrollableAreaForLastNode = enclosingScrollableArea(m_lastElementUnderMouse.get());
2415 auto scrollableAreaForNodeUnderMouse = enclosingScrollableArea(m_elementUnderMouse.get());
2416 Page* page = m_frame.page();
2418 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) {
2419 // The mouse has moved between frames.
2420 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2421 if (FrameView* frameView = frame->view())
2422 frameView->mouseExitedContentArea();
2424 } else if (page && (scrollableAreaForLastNode && (!scrollableAreaForNodeUnderMouse || scrollableAreaForNodeUnderMouse != scrollableAreaForLastNode))) {
2425 // The mouse has moved between layers.
2426 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2427 if (FrameView* frameView = frame->view()) {
2428 if (frameView->containsScrollableArea(scrollableAreaForLastNode))
2429 scrollableAreaForLastNode->mouseExitedContentArea();
2434 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) {
2435 // The mouse has moved between frames.
2436 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2437 if (FrameView* frameView = frame->view())
2438 frameView->mouseEnteredContentArea();
2440 } else if (page && (scrollableAreaForNodeUnderMouse && (!scrollableAreaForLastNode || scrollableAreaForNodeUnderMouse != scrollableAreaForLastNode))) {
2441 // The mouse has moved between layers.
2442 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2443 if (FrameView* frameView = frame->view()) {
2444 if (frameView->containsScrollableArea(scrollableAreaForNodeUnderMouse))
2445 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
2450 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) {
2451 m_lastElementUnderMouse = nullptr;
2452 m_lastScrollbarUnderMouse = nullptr;
2455 if (m_lastElementUnderMouse != m_elementUnderMouse) {
2456 // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor
2457 // or a normal eventhandler on the element itself (they don't bubble).
2458 // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks.
2459 bool hasCapturingMouseEnterListener = hierarchyHasCapturingEventListeners(m_elementUnderMouse.get(), eventNames().mouseenterEvent);
2460 bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent);
2462 RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr;
2463 RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr;
2464 RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer);
2466 Vector<Ref<Element>, 32> leftElementsChain;
2467 if (oldHoverRenderer) {
2468 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) {
2469 if (Element* element = curr->element())
2470 leftElementsChain.append(*element);
2473 // If the old hovered element is not null but it's renderer is, it was probably detached.
2474 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied.
2475 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement())
2476 leftElementsChain.append(*element);
2479 Vector<Ref<Element>, 32> enteredElementsChain;
2480 const Element* ancestorElement = ancestor ? ancestor->element() : nullptr;
2481 for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) {
2482 if (Element *element = curr->element()) {
2483 if (element == ancestorElement)
2485 enteredElementsChain.append(*element);
2489 // Send mouseout event to the old node.
2490 if (m_lastElementUnderMouse)
2491 m_lastElementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
2493 // Send mouseleave to the node hierarchy no longer under the mouse.
2494 for (auto& chain : leftElementsChain) {
2495 if (hasCapturingMouseLeaveListener || chain->hasEventListeners(eventNames().mouseleaveEvent))
2496 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseleaveEvent, 0, m_elementUnderMouse.get());
2499 // Send mouseover event to the new node.
2500 if (m_elementUnderMouse)
2501 m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
2503 // Send mouseleave event to the nodes hierarchy under the mouse.
2504 for (auto& chain : enteredElementsChain) {
2505 if (hasCapturingMouseEnterListener || chain->hasEventListeners(eventNames().mouseenterEvent))
2506 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseenterEvent, 0, m_lastElementUnderMouse.get());
2509 m_lastElementUnderMouse = m_elementUnderMouse;
2513 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
2515 Ref<Frame> protectedFrame(m_frame);
2517 if (auto* view = m_frame.view())
2518 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2520 updateMouseEventTargetNode(targetNode, platformMouseEvent, setUnder);
2522 if (m_elementUnderMouse && !m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventType, clickCount))
2525 if (eventType != eventNames().mousedownEvent)
2528 // If clicking on a frame scrollbar, do not make any change to which element is focused.
2529 auto* view = m_frame.view();
2530 if (view && view->scrollbarAtPoint(platformMouseEvent.position()))
2533 // The layout needs to be up to date to determine if an element is focusable.
2534 m_frame.document()->updateLayoutIgnorePendingStylesheets();
2536 // Remove focus from the currently focused element when a link or button is clicked.
2537 // This is expected by some sites that rely on change event handlers running
2538 // from form fields before the button click is processed, behavior that was inherited
2539 // from the user interface of Windows, where pushing a button moves focus to the button.
2541 // Walk up the DOM tree to search for an element to focus.
2543 for (element = m_elementUnderMouse.get(); element; element = element->parentOrShadowHostElement()) {
2544 if (element->isMouseFocusable())
2548 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus an
2549 // element on mouse down if it's selected and inside a focused element. It will be
2550 // focused if the user does a mouseup over it, however, because the mouseup
2551 // will set a selection inside it, which will also set the focused element.
2552 if (element && m_frame.selection().isRange()) {
2553 if (auto range = m_frame.selection().toNormalizedRange()) {
2554 auto result = range->compareNode(*element);
2555 if (!result.hasException() && result.releaseReturnValue() == Range::NODE_INSIDE && element->isDescendantOf(m_frame.document()->focusedElement()))
2560 // Only change the focus when clicking scrollbars if it can be transferred to a mouse focusable node.
2561 if (!element && isInsideScrollbar(platformMouseEvent.position()))
2564 // If focus shift is blocked, we eat the event.
2565 auto* page = m_frame.page();
2566 if (page && !page->focusController().setFocusedElement(element, &m_frame))
2572 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2574 if (RenderView* renderView = m_frame.contentRenderer()) {
2575 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
2576 HitTestResult result(windowPoint);
2577 renderView->hitTest(request, result);
2578 return result.scrollbar();
2586 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2595 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, WeakPtr<ScrollableArea>&, bool&)
2599 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event)
2601 m_frame.mainFrame().wheelEventDeltaFilter()->updateFromDelta(FloatSize(event.deltaX(), event.deltaY()));
2604 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, const WeakPtr<ScrollableArea>&)
2606 Ref<Frame> protectedFrame(m_frame);
2608 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2609 FrameView* view = m_frame.view();
2611 bool didHandleEvent = view ? view->wheelEvent(event) : false;
2612 m_isHandlingWheelEvent = false;
2613 return didHandleEvent;
2616 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode*)
2621 void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, const WeakPtr<ScrollableArea>&)
2625 IntPoint EventHandler::effectiveMousePositionForSelectionAutoscroll() const
2627 return m_lastKnownMousePosition;
2630 void EventHandler::clearOrScheduleClearingLatchedStateIfNeeded(const PlatformWheelEvent&)
2632 clearLatchedState();
2636 Widget* EventHandler::widgetForEventTarget(Element* eventTarget)
2641 auto* target = eventTarget->renderer();
2642 if (!is<RenderWidget>(target))
2645 return downcast<RenderWidget>(*target).widget();
2648 static WeakPtr<Widget> widgetForElement(const Element& element)
2650 auto target = element.renderer();
2651 if (!is<RenderWidget>(target) || !downcast<RenderWidget>(*target).widget())
2654 return downcast<RenderWidget>(*target).widget()->createWeakPtr();
2657 bool EventHandler::completeWidgetWheelEvent(const PlatformWheelEvent& event, const WeakPtr<Widget>& widget, const WeakPtr<ScrollableArea>& scrollableArea, ContainerNode* scrollableContainer)
2659 m_isHandlingWheelEvent = false;
2661 // We do another check on the widget because the event handler can run JS which results in the frame getting destroyed.
2666 scrollableArea->setScrolledProgrammatically(false);
2668 platformNotifyIfEndGesture(event, scrollableArea);
2670 if (!widget->platformWidget())
2673 return platformCompletePlatformWidgetWheelEvent(event, *widget.get(), scrollableContainer);
2676 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
2678 RenderView* renderView = m_frame.contentRenderer();
2682 Ref<Frame> protectedFrame(m_frame);
2683 RefPtr<FrameView> protector(m_frame.view());
2685 FrameView* view = m_frame.view();
2689 m_isHandlingWheelEvent = true;
2690 setFrameWasScrolledByUser();
2692 HitTestRequest request;
2693 HitTestResult result(view->windowToContents(event.position()));
2694 renderView->hitTest(request, result);
2696 RefPtr<Element> element = result.targetElement();
2697 RefPtr<ContainerNode> scrollableContainer;
2698 WeakPtr<ScrollableArea> scrollableArea;
2699 bool isOverWidget = result.isOverWidget();
2700 platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget);
2703 if (event.phase() == PlatformWheelEventPhaseNone && event.momentumPhase() == PlatformWheelEventPhaseNone)
2704 m_frame.mainFrame().resetLatchingState();
2707 // FIXME: It should not be necessary to do this mutation here.
2708 // Instead, the handlers should know convert vertical scrolls appropriately.
2709 PlatformWheelEvent adjustedEvent = event;
2710 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, event))
2711 adjustedEvent = event.copyTurningVerticalTicksIntoHorizontalTicks();
2713 platformRecordWheelEvent(adjustedEvent);
2717 if (WeakPtr<Widget> widget = widgetForElement(*element)) {
2718 if (widgetDidHandleWheelEvent(event, *widget.get()))
2719 return completeWidgetWheelEvent(adjustedEvent, widget, scrollableArea, scrollableContainer.get());
2723 if (!element->dispatchWheelEvent(adjustedEvent)) {
2724 m_isHandlingWheelEvent = false;
2725 if (scrollableArea && scrollableArea->isScrolledProgrammatically()) {
2726 // Web developer is controlling scrolling, so don't attempt to latch.
2727 clearLatchedState();
2728 scrollableArea->setScrolledProgrammatically(false);
2731 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2737 scrollableArea->setScrolledProgrammatically(false);
2739 bool handledEvent = platformCompleteWheelEvent(adjustedEvent, scrollableContainer.get(), scrollableArea);
2740 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2741 return handledEvent;
2744 void EventHandler::clearLatchedState()
2747 m_frame.mainFrame().resetLatchingState();
2749 if (auto filter = m_frame.mainFrame().wheelEventDeltaFilter())
2750 filter->endFilteringDeltas();
2753 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent& wheelEvent)
2758 Ref<Frame> protectedFrame(m_frame);
2760 FloatSize filteredPlatformDelta(wheelEvent.deltaX(), wheelEvent.deltaY());
2761 FloatSize filteredVelocity;
2762 if (const PlatformWheelEvent* platformWheelEvent = wheelEvent.wheelEvent()) {
2763 filteredPlatformDelta.setWidth(platformWheelEvent->deltaX());
2764 filteredPlatformDelta.setHeight(platformWheelEvent->deltaY());
2768 ScrollLatchingState* latchedState = m_frame.mainFrame().latchingState();
2769 Element* stopElement = latchedState ? latchedState->previousWheelScrolledElement() : nullptr;
2771 if (m_frame.mainFrame().wheelEventDeltaFilter()->isFilteringDeltas()) {
2772 filteredPlatformDelta = m_frame.mainFrame().wheelEventDeltaFilter()->filteredDelta();
2773 filteredVelocity = m_frame.mainFrame().wheelEventDeltaFilter()->filteredVelocity();
2776 Element* stopElement = nullptr;
2780 if (handleWheelEventInAppropriateEnclosingBox(startNode, wheelEvent, &stopElement, filteredPlatformDelta, filteredVelocity))
2781 wheelEvent.setDefaultHandled();
2784 if (latchedState && !latchedState->wheelEventElement())
2785 latchedState->setPreviousWheelScrolledElement(stopElement);
2789 #if ENABLE(CONTEXT_MENUS)
2790 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2792 Ref<Frame> protectedFrame(m_frame);
2794 Document* doc = m_frame.document();
2795 FrameView* view = m_frame.view();
2799 // Clear mouse press state to avoid initiating a drag while context menu is up.
2800 m_mousePressed = false;
2802 LayoutPoint viewportPos = view->windowToContents(event.position());
2803 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
2804 MouseEventWithHitTestResults mouseEvent = doc->prepareMouseEvent(request, viewportPos, event);
2806 // Do not show context menus when clicking on scrollbars.
2807 if (mouseEvent.scrollbar() || view->scrollbarAtPoint(event.position()))
2810 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick()
2811 && !m_frame.selection().contains(viewportPos)
2812 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2813 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2814 // available for text selections. But only if we're above text.
2815 && (m_frame.selection().selection().isContentEditable() || (mouseEvent.targetNode() && mouseEvent.targetNode()->isTextNode()))) {
2816 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2817 selectClosestContextualWordOrLinkFromMouseEvent(mouseEvent);
2820 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mouseEvent.targetNode(), true, 0, event, false);
2822 return swallowEvent;
2825 bool EventHandler::sendContextMenuEventForKey()
2827 Ref<Frame> protectedFrame(m_frame);
2829 FrameView* view = m_frame.view();
2833 Document* doc = m_frame.document();
2837 // Clear mouse press state to avoid initiating a drag while context menu is up.
2838 m_mousePressed = false;
2840 static const int kContextMenuMargin = 1;
2843 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2845 int rightAligned = 0;
2849 Element* focusedElement = doc->focusedElement();
2850 const VisibleSelection& selection = m_frame.selection().selection();
2851 Position start = selection.start();
2853 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2854 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2855 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get());
2857 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2858 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2859 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2860 location = IntPoint(x, y);
2861 } else if (focusedElement) {
2862 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2865 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2866 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2868 location = IntPoint(
2869 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2870 kContextMenuMargin);
2873 m_frame.view()->setCursor(pointerCursor());
2875 IntPoint position = view->contentsToRootView(location);
2876 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2878 Node* targetNode = doc->focusedElement();
2882 // Use the focused node as the target for hover and active.
2883 HitTestResult result(position);
2884 result.setInnerNode(targetNode);
2885 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.targetElement());
2887 // The contextmenu event is a mouse event even when invoked using the keyboard.
2888 // This is required for web compatibility.
2891 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2893 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2896 PlatformMouseEvent platformMouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime(), ForceAtClick, NoTap);
2898 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, platformMouseEvent, false);
2900 #endif // ENABLE(CONTEXT_MENUS)
2902 void EventHandler::scheduleHoverStateUpdate()
2904 if (!m_hoverTimer.isActive())
2905 m_hoverTimer.startOneShot(0);
2908 #if ENABLE(CURSOR_SUPPORT)
2909 void EventHandler::scheduleCursorUpdate()
2911 if (!m_cursorUpdateTimer.isActive())
2912 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2916 void EventHandler::dispatchFakeMouseMoveEventSoon()
2918 #if !ENABLE(IOS_TOUCH_EVENTS)
2922 if (m_mousePositionIsUnknown)
2925 if (Page* page = m_frame.page()) {
2926 if (!page->chrome().client().shouldDispatchFakeMouseMoveEvents())
2930 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2931 // reschedule the timer and use a longer time. This will cause the content
2932 // to receive these moves only after the user is done scrolling, reducing
2933 // pauses during the scroll.
2934 if (m_fakeMouseMoveEventTimer.isActive())
2935 m_fakeMouseMoveEventTimer.stop();
2936 m_fakeMouseMoveEventTimer.startOneShot(m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold ? fakeMouseMoveLongInterval : fakeMouseMoveShortInterval);
2940 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2942 #if ENABLE(IOS_TOUCH_EVENTS)
2945 FrameView* view = m_frame.view();
2949 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2952 dispatchFakeMouseMoveEventSoon();
2956 #if !ENABLE(IOS_TOUCH_EVENTS)
2957 void EventHandler::cancelFakeMouseMoveEvent()
2959 m_fakeMouseMoveEventTimer.stop();
2962 void EventHandler::fakeMouseMoveEventTimerFired()
2964 ASSERT(!m_mousePressed);
2966 FrameView* view = m_frame.view();
2970 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive())
2977 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2978 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime(), 0, NoTap);
2979 mouseMoved(fakeMouseMoveEvent);
2981 #endif // !ENABLE(IOS_TOUCH_EVENTS)
2983 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2985 m_frameSetBeingResized = frameSet;
2988 void EventHandler::resizeLayerDestroyed()
2990 ASSERT(m_resizeLayer);
2991 m_resizeLayer = nullptr;
2994 void EventHandler::hoverTimerFired()
2996 m_hoverTimer.stop();
2998 ASSERT(m_frame.document());
3000 Ref<Frame> protectedFrame(m_frame);
3002 if (RenderView* renderView = m_frame.contentRenderer()) {
3003 if (FrameView* view = m_frame.view()) {
3004 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
3005 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
3006 renderView->hitTest(request, result);
3007 m_frame.document()->updateHoverActiveState(request, result.targetElement());
3012 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& event)
3014 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3015 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3016 // lower case variants are present in a document, the correct element is matched based on Shift key state.
3017 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3018 ASSERT(!accessKeyModifiers().contains(PlatformEvent::Modifier::ShiftKey));
3020 if ((event.modifiers() - PlatformEvent::Modifier::ShiftKey) != accessKeyModifiers())
3022 Element* element = m_frame.document()->getElementByAccessKey(event.unmodifiedText());
3025 element->accessKeyAction(false);
3030 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
3036 #if ENABLE(FULLSCREEN_API)
3037 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
3039 Document* document = m_frame.document();
3040 if (document->webkitFullScreenKeyboardInputAllowed())
3043 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3044 if (keyEvent.text().length() != 1)
3046 UChar character = keyEvent.text()[0];
3047 return character == ' ';
3050 int keyCode = keyEvent.windowsVirtualKeyCode();
3051 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3052 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3053 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3054 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3058 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3060 Ref<Frame> protectedFrame(m_frame);
3061 RefPtr<FrameView> protector(m_frame.view());
3063 LOG(Editing, "EventHandler %p keyEvent (text %s keyIdentifier %s)", this, initialKeyEvent.text().utf8().data(), initialKeyEvent.keyIdentifier().utf8().data());
3065 #if ENABLE(POINTER_LOCK)
3066 if (initialKeyEvent.type() == PlatformEvent::KeyDown && initialKeyEvent.windowsVirtualKeyCode() == VK_ESCAPE && m_frame.page()->pointerLockController().element()) {
3067 m_frame.page()->pointerLockController().requestPointerUnlockAndForceCursorVisible();
3072 #if ENABLE(FULLSCREEN_API)
3073 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
3077 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL) {
3078 if (auto* element = m_frame.document()->focusedElement()) {
3079 if (is<HTMLInputElement>(*element))
3080 downcast<HTMLInputElement>(*element).capsLockStateMayHaveChanged();
3084 #if ENABLE(PAN_SCROLLING)
3085 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) {
3086 // If a key is pressed while the panScroll is in progress then we want to stop
3087 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3088 stopAutoscrollTimer();
3090 // If we were in panscroll mode, we swallow the key event
3095 // Check for cases where we are too early for events -- possible unmatched key up
3096 // from pressing return in the location bar.
3097 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document());
3101 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
3102 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3104 if (FrameView* view = m_frame.view())
3105 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3107 // FIXME (bug 68185): this call should be made at another abstraction layer
3108 m_frame.loader().resetMultipleFormSubmissionProtection();
3110 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3111 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3112 // with access keys. Then we dispatch keydown, but suppress its default handling.
3113 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3114 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3115 bool matchedAnAccessKey = false;
3116 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3117 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3119 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3120 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3121 return !element->dispatchKeyEvent(initialKeyEvent);
3123 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3125 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3126 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3127 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3128 Ref<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3129 if (matchedAnAccessKey)
3130 keydown->setDefaultPrevented(true);
3131 keydown->setTarget(element);
3133 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3134 element->dispatchEvent(keydown);
3135 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3136 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3137 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3140 // Run input method in advance of DOM event handling. This may result in the IM
3141 // modifying the page prior the keydown event, but this behaviour is necessary
3142 // in order to match IE:
3143 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3144 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3145 m_frame.editor().handleInputMethodKeydown(keydown.get());
3147 bool handledByInputMethod = keydown->defaultHandled();
3149 if (handledByInputMethod) {
3150 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3151 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3152 keydown->setTarget(element);
3153 keydown->setDefaultHandled();
3156 if (accessibilityPreventsEventPropogation(keydown))
3157 keydown->stopPropagation();
3159 element->dispatchEvent(keydown);
3160 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3161 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3162 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3163 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3164 return keydownResult;
3166 // Focus may have changed during keydown handling, so refetch element.
3167 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element.
3168 if (!keydownResult) {
3169 element = eventTargetElementForDocument(m_frame.document());
3174 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3175 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3176 if (keyPressEvent.text().isEmpty())
3177 return keydownResult;
3178 Ref<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView());
3179 keypress->setTarget(element);
3181 keypress->setDefaultPrevented(true);
3183 keypress->keypressCommands() = keydown->keypressCommands();
3185 element->dispatchEvent(keypress);
3187 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3190 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3192 static NeverDestroyed<AtomicString> Down("Down", AtomicString::ConstructFromLiteral);
3193 static NeverDestroyed<AtomicString> Up("Up", AtomicString::ConstructFromLiteral);
3194 static NeverDestroyed<AtomicString> Left("Left", AtomicString::ConstructFromLiteral);
3195 static NeverDestroyed<AtomicString> Right("Right", AtomicString::ConstructFromLiteral);
3197 FocusDirection retVal = FocusDirectionNone;
3199 if (keyIdentifier == Down)
3200 retVal = FocusDirectionDown;
3201 else if (keyIdentifier == Up)
3202 retVal = FocusDirectionUp;
3203 else if (keyIdentifier == Left)
3204 retVal = FocusDirectionLeft;
3205 else if (keyIdentifier == Right)
3206 retVal = FocusDirectionRight;
3211 static void setInitialKeyboardSelection(Frame& frame, SelectionDirection direction)
3213 Document* document = frame.document();
3217 FrameSelection& selection = frame.selection();
3219 if (!selection.isNone())
3222 Element* focusedElement = document->focusedElement();
3223 VisiblePosition visiblePosition;
3225 switch (direction) {
3226 case DirectionBackward:
3229 visiblePosition = VisiblePosition(positionBeforeNode(focusedElement));
3231 visiblePosition = endOfDocument(document);
3233 case DirectionForward:
3234 case DirectionRight:
3236 visiblePosition = VisiblePosition(positionAfterNode(focusedElement));
3238 visiblePosition = startOfDocument(document);
3242 AXTextStateChangeIntent intent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, false });
3243 selection.setSelection(visiblePosition, FrameSelection::defaultSetSelectionOptions(UserTriggered), intent);
3246 static void handleKeyboardSelectionMovement(Frame& frame, KeyboardEvent& event)
3248 FrameSelection& selection = frame.selection();
3250 bool isCommanded = event.getModifierState("Meta");
3251 bool isOptioned = event.getModifierState("Alt");
3252 bool isSelection = !selection.isNone();
3254 FrameSelection::EAlteration alternation = event.getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3255 SelectionDirection direction = DirectionForward;
3256 TextGranularity granularity = CharacterGranularity;
3258 switch (focusDirectionForKey(event.keyIdentifier())) {
3259 case FocusDirectionNone:
3261 case FocusDirectionForward:
3262 case FocusDirectionBackward:
3263 ASSERT_NOT_REACHED();
3265 case FocusDirectionUp:
3266 direction = DirectionBackward;
3267 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3269 case FocusDirectionDown:
3270 direction = DirectionForward;
3271 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3273 case FocusDirectionLeft:
3274 direction = DirectionLeft;
3275 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3277 case FocusDirectionRight:
3278 direction = DirectionRight;
3279 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3284 selection.modify(alternation, direction, granularity, UserTriggered);
3286 setInitialKeyboardSelection(frame, direction);
3288 event.setDefaultHandled();
3291 void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent& event)
3293 if (event.type() == eventNames().keydownEvent) {
3294 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3295 handleKeyboardSelectionMovement(m_frame, event);
3299 bool EventHandler::accessibilityPreventsEventPropogation(KeyboardEvent& event)
3302 if (!AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3305 if (!m_frame.settings().preventKeyboardDOMEventDispatch())
3308 // Check for key events that are relevant to accessibility: tab and arrows keys that change focus
3309 if (event.keyIdentifier() == "U+0009")
3311 FocusDirection direction = focusDirectionForKey(event.keyIdentifier());
3312 if (direction != FocusDirectionNone)
3315 UNUSED_PARAM(event);
3320 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent& event)
3322 Ref<Frame> protectedFrame(m_frame);
3324 if (event.type() == eventNames().keydownEvent) {
3325 m_frame.editor().handleKeyboardEvent(event);
3326 if (event.defaultHandled())
3328 if (event.keyIdentifier() == "U+0009")
3329 defaultTabEventHandler(event);
3330 else if (event.keyIdentifier() == "U+0008")
3331 defaultBackspaceEventHandler(event);
3333 FocusDirection direction = focusDirectionForKey(event.keyIdentifier());
3334 if (direction != FocusDirectionNone)
3335 defaultArrowEventHandler(direction, event);
3338 handleKeyboardSelectionMovementForAccessibility(event);
3340 if (event.type() == eventNames().keypressEvent) {
3341 m_frame.editor().handleKeyboardEvent(event);
3342 if (event.defaultHandled())
3344 if (event.charCode() == ' ')
3345 defaultSpaceEventHandler(event);
3349 #if ENABLE(DRAG_SUPPORT)
3350 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3352 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3353 return dragHysteresisExceeded(dragViewportLocation);
3356 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3358 int threshold = GeneralDragHysteresis;
3359 switch (dragState().type) {
3360 case DragSourceActionSelection:
3361 threshold = TextDragHysteresis;
3363 case DragSourceActionImage:
3364 #if ENABLE(ATTACHMENT_ELEMENT)
3365 case DragSourceActionAttachment:
3367 threshold = ImageDragHysteresis;
3369 case DragSourceActionLink:
3370 threshold = LinkDragHysteresis;
3372 case DragSourceActionDHTML:
3374 case DragSourceActionNone:
3375 case DragSourceActionAny:
3376 ASSERT_NOT_REACHED();
3379 return mouseMovementExceedsThreshold(dragViewportLocation, threshold);
3382 void EventHandler::freeDataTransfer()
3384 if (!dragState().dataTransfer)
3386 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb);
3387 dragState().dataTransfer = nullptr;
3390 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3392 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3393 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
3394 prepareMouseEvent(request, event);
3396 if (dragState().source && dragState().shouldDispatchEvents) {
3397 dragState().dataTransfer->setDestinationOperation(operation);
3398 // For now we don't care if event handler cancels default behavior, since there is no default behavior.
3399 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3402 dragState().source = nullptr;
3403 // In case the drag was ended due to an escape key press we need to ensure
3404 // that consecutive mousemove events don't reinitiate the drag and drop.
3405 m_mouseDownMayStartDrag = false;
3408 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3410 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element.
3411 if (dragState().source && !dragState().source->inDocument())
3412 dragState().source = rootEditableElement;
3415 // Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
3416 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3418 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
3421 static bool ExactlyOneBitSet(DragSourceAction n)
3423 return n && !(n & (n - 1));
3426 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3428 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3429 // If we allowed the other side of the bridge to handle a drag
3430 // last time, then m_mousePressed might still be set. So we
3431 // clear it now to make sure the next move after a drag
3432 // doesn't look like a drag.
3433 m_mousePressed = false;
3437 Ref<Frame> protectedFrame(m_frame);
3439 if (eventLoopHandleMouseDragged(event))
3442 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3444 if (m_mouseDownMayStartDrag && !dragState().source) {
3445 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML);
3447 // try to find an element that wants to be dragged
3448 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
3449 HitTestResult result(m_mouseDownPos);
3450 m_frame.contentRenderer()->hitTest(request, result);
3452 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.targetElement(), m_mouseDownPos, dragState());
3454 if (!dragState().source)
3455 m_mouseDownMayStartDrag = false; // no element is draggable
3457 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection);
3460 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3461 // or else we bail on the dragging stuff and allow selection to occur
3462 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3463 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3464 if ((dragState().type & DragSourceActionImage)) {
3465 // ... unless the mouse is over an image, then we start dragging just the image
3466 dragState().type = DragSourceActionImage;
3467 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) {
3468 // ... but only bail if we're not over an unselectable element.
3469 m_mouseDownMayStartDrag = false;
3470 dragState().source = nullptr;
3471 // ... but if this was the first click in the window, we don't even want to start selection
3472 if (eventActivatedView(event.event()))
3473 m_mouseDownMayStartSelect = false;
3475 // Prevent the following case from occuring:
3476 // 1. User starts a drag immediately after mouse down over an unselectable element.
3477 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag.
3478 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet.
3479 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag.
3480 m_dragMayStartSelectionInstead = false;
3484 if (!m_mouseDownMayStartDrag)
3485 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3487 if (!ExactlyOneBitSet(dragState().type)) {
3488 ASSERT((dragState().type & DragSourceActionSelection));
3489 #if ENABLE(ATTACHMENT_ELEMENT)
3490 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3491 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3492 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionAttachment
3493 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);