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"
46 #include "ExceptionCodePlaceholder.h"
48 #include "FloatPoint.h"
49 #include "FloatRect.h"
50 #include "FocusController.h"
51 #include "FrameLoader.h"
52 #include "FrameSelection.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "HTMLFrameElement.h"
56 #include "HTMLFrameSetElement.h"
57 #include "HTMLHtmlElement.h"
58 #include "HTMLIFrameElement.h"
59 #include "HTMLInputElement.h"
60 #include "HTMLNames.h"
61 #include "HitTestRequest.h"
62 #include "HitTestResult.h"
64 #include "InspectorInstrumentation.h"
65 #include "KeyboardEvent.h"
67 #include "MainFrame.h"
68 #include "MouseEvent.h"
69 #include "MouseEventWithHitTestResults.h"
71 #include "PageOverlayController.h"
72 #include "PlatformEvent.h"
73 #include "PlatformKeyboardEvent.h"
74 #include "PlatformWheelEvent.h"
75 #include "PluginDocument.h"
76 #include "PointerLockController.h"
77 #include "RenderFrameSet.h"
78 #include "RenderLayer.h"
79 #include "RenderListBox.h"
80 #include "RenderNamedFlowThread.h"
81 #include "RenderTextControlSingleLine.h"
82 #include "RenderView.h"
83 #include "RenderWidget.h"
84 #include "RuntimeApplicationChecks.h"
85 #include "SVGDocument.h"
87 #include "ScrollLatchingState.h"
88 #include "Scrollbar.h"
90 #include "ShadowRoot.h"
91 #include "SpatialNavigation.h"
92 #include "StyleCachedImage.h"
93 #include "TextEvent.h"
94 #include "TextIterator.h"
95 #include "UserGestureIndicator.h"
96 #include "UserTypingGestureIndicator.h"
97 #include "VisibleUnits.h"
98 #include "WheelEvent.h"
99 #include "WindowsKeyboardCodes.h"
100 #include "htmlediting.h"
101 #include <wtf/Assertions.h>
102 #include <wtf/CurrentTime.h>
103 #include <wtf/NeverDestroyed.h>
104 #include <wtf/StdLibExtras.h>
105 #include <wtf/WeakPtr.h>
107 #if ENABLE(IOS_TOUCH_EVENTS)
108 #include "PlatformTouchEventIOS.h"
111 #if ENABLE(TOUCH_EVENTS)
112 #include "TouchEvent.h"
113 #include "TouchList.h"
116 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
117 #include "PlatformTouchEvent.h"
120 #if ENABLE(MAC_GESTURE_EVENTS)
121 #include "PlatformGestureEventMac.h"
126 using namespace HTMLNames;
128 #if ENABLE(DRAG_SUPPORT)
129 // The link drag hysteresis is much larger than the others because there
130 // needs to be enough space to cancel the link press without starting a link drag,
131 // and because dragging links is rare.
132 const int LinkDragHysteresis = 40;
133 const int ImageDragHysteresis = 5;
134 const int TextDragHysteresis = 3;
135 const int GeneralDragHysteresis = 3;
136 #endif // ENABLE(DRAG_SUPPORT)
138 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
139 const float GestureUnknown = 0;
142 #if ENABLE(IOS_TOUCH_EVENTS)
143 // FIXME: Share this constant with EventHandler and SliderThumbElement.
144 const unsigned InvalidTouchIdentifier = 0;
147 // Match key code of composition keydown event on windows.
148 // IE sends VK_PROCESSKEY which has value 229;
149 const int CompositionEventKeyCode = 229;
151 using namespace SVGNames;
153 #if !ENABLE(IOS_TOUCH_EVENTS)
154 // The amount of time to wait before sending a fake mouse event, triggered
155 // during a scroll. The short interval is used if the content responds to the mouse events
156 // in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used.
157 const double fakeMouseMoveDurationThreshold = 0.01;
158 const double fakeMouseMoveShortInterval = 0.1;
159 const double fakeMouseMoveLongInterval = 0.25;
162 #if ENABLE(CURSOR_SUPPORT)
163 // The amount of time to wait for a cursor update on style and layout changes
164 // Set to 50Hz, no need to be faster than common screen refresh rate
165 const double cursorUpdateInterval = 0.02;
167 const int maximumCursorSize = 128;
170 #if ENABLE(MOUSE_CURSOR_SCALE)
171 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
172 // need to ensure here is that the scale isn't so small that integer overflow can occur when
173 // dividing cursor sizes (limited above) by the scale.
174 const double minimumCursorScale = 0.001;
177 enum NoCursorChangeType { NoCursorChange };
179 class OptionalCursor {
181 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
182 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
184 bool isCursorChange() const { return m_isCursorChange; }
185 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
188 bool m_isCursorChange;
192 class MaximumDurationTracker {
194 explicit MaximumDurationTracker(double *maxDuration)
195 : m_maxDuration(maxDuration)
196 , m_start(monotonicallyIncreasingTime())
200 ~MaximumDurationTracker()
202 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
206 double* m_maxDuration;
210 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
211 class SyntheticTouchPoint : public PlatformTouchPoint {
214 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
215 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
217 const static int idDefaultValue = 0;
218 const static int radiusYDefaultValue = 1;
219 const static int radiusXDefaultValue = 1;
220 const static float rotationAngleDefaultValue = 0.0f;
221 const static float forceDefaultValue = 1.0f;
223 m_id = idDefaultValue; // There is only one active TouchPoint.
224 m_screenPos = event.globalPosition();
225 m_pos = event.position();
226 m_radiusY = radiusYDefaultValue;
227 m_radiusX = radiusXDefaultValue;
228 m_rotationAngle = rotationAngleDefaultValue;
229 m_force = forceDefaultValue;
231 PlatformEvent::Type type = event.type();
232 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
235 case PlatformEvent::MouseMoved:
236 m_state = TouchMoved;
238 case PlatformEvent::MousePressed:
239 m_state = TouchPressed;
241 case PlatformEvent::MouseReleased:
242 m_state = TouchReleased;
245 ASSERT_NOT_REACHED();
251 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
253 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
255 switch (event.type()) {
256 case PlatformEvent::MouseMoved:
259 case PlatformEvent::MousePressed:
262 case PlatformEvent::MouseReleased:
266 ASSERT_NOT_REACHED();
270 m_timestamp = event.timestamp();
271 m_modifiers = event.modifiers();
272 m_touchPoints.append(SyntheticTouchPoint(event));
275 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
277 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
280 case WheelEvent::DOM_DELTA_PAGE:
282 case WheelEvent::DOM_DELTA_LINE:
284 case WheelEvent::DOM_DELTA_PIXEL:
285 return ScrollByPixel;
287 return ScrollByPixel;
291 static inline bool didScrollInScrollableArea(ScrollableArea* scrollableArea, WheelEvent& wheelEvent)
293 ScrollGranularity scrollGranularity = wheelGranularityToScrollGranularity(wheelEvent.deltaMode());
294 bool didHandleWheelEvent = false;
295 if (float absoluteDelta = std::abs(wheelEvent.deltaX()))
296 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent.deltaX() > 0 ? ScrollRight : ScrollLeft, scrollGranularity, absoluteDelta);
298 if (float absoluteDelta = std::abs(wheelEvent.deltaY()))
299 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent.deltaY() > 0 ? ScrollDown : ScrollUp, scrollGranularity, absoluteDelta);
301 return didHandleWheelEvent;
304 static inline bool handleWheelEventInAppropriateEnclosingBox(Node* startNode, WheelEvent& wheelEvent, Element** stopElement, const FloatSize& filteredPlatformDelta)
306 bool shouldHandleEvent = wheelEvent.deltaX() || wheelEvent.deltaY();
308 shouldHandleEvent |= wheelEvent.phase() == PlatformWheelEventPhaseEnded;
309 #if ENABLE(CSS_SCROLL_SNAP)
310 shouldHandleEvent |= wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded;
313 if (!startNode->renderer() || !shouldHandleEvent)
316 RenderBox& initialEnclosingBox = startNode->renderer()->enclosingBox();
317 if (initialEnclosingBox.isListBox())
318 return didScrollInScrollableArea(static_cast<RenderListBox*>(&initialEnclosingBox), wheelEvent);
320 RenderBox* currentEnclosingBox = &initialEnclosingBox;
321 while (currentEnclosingBox) {
322 if (RenderLayer* boxLayer = currentEnclosingBox->layer()) {
323 const PlatformWheelEvent* platformEvent = wheelEvent.wheelEvent();
324 bool scrollingWasHandled;
325 if (platformEvent != nullptr)
326 scrollingWasHandled = boxLayer->handleWheelEvent(platformEvent->copyWithDeltas(filteredPlatformDelta.width(), filteredPlatformDelta.height()));
328 scrollingWasHandled = didScrollInScrollableArea(boxLayer, wheelEvent);
330 if (scrollingWasHandled) {
332 *stopElement = currentEnclosingBox->element();
337 if (stopElement && *stopElement && *stopElement == currentEnclosingBox->element())
340 currentEnclosingBox = currentEnclosingBox->containingBlock();
341 if (currentEnclosingBox && currentEnclosingBox->isRenderNamedFlowThread())
342 currentEnclosingBox = RenderNamedFlowThread::fragmentFromRenderBoxAsRenderBlock(currentEnclosingBox, roundedIntPoint(wheelEvent.absoluteLocation()), initialEnclosingBox);
343 if (!currentEnclosingBox || currentEnclosingBox->isRenderView())
349 #if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS))
350 static inline bool shouldGesturesTriggerActive()
352 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
353 // rely on them to set the active state. Unfortunately there's no generic way to
354 // know in advance what event types are supported.
361 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
366 #if ENABLE(DRAG_SUPPORT)
367 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
375 EventHandler::EventHandler(Frame& frame)
377 , m_hoverTimer(*this, &EventHandler::hoverTimerFired)
378 #if ENABLE(CURSOR_SUPPORT)
379 , m_cursorUpdateTimer(*this, &EventHandler::cursorUpdateTimerFired)
382 , m_pendingMomentumWheelEventsTimer(*this, &EventHandler::clearLatchedState)
384 , m_autoscrollController(std::make_unique<AutoscrollController>())
385 #if !ENABLE(IOS_TOUCH_EVENTS)
386 , m_fakeMouseMoveEventTimer(*this, &EventHandler::fakeMouseMoveEventTimerFired)
388 #if ENABLE(CURSOR_VISIBILITY)
389 , m_autoHideCursorTimer(*this, &EventHandler::autoHideCursorTimerFired)
394 EventHandler::~EventHandler()
396 #if !ENABLE(IOS_TOUCH_EVENTS)
397 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
399 #if ENABLE(CURSOR_VISIBILITY)
400 ASSERT(!m_autoHideCursorTimer.isActive());
404 #if ENABLE(DRAG_SUPPORT)
405 DragState& EventHandler::dragState()
407 static NeverDestroyed<DragState> state;
410 #endif // ENABLE(DRAG_SUPPORT)
412 void EventHandler::clear()
415 #if ENABLE(CURSOR_SUPPORT)
416 m_cursorUpdateTimer.stop();
418 #if !ENABLE(IOS_TOUCH_EVENTS)
419 m_fakeMouseMoveEventTimer.stop();
421 #if ENABLE(CURSOR_VISIBILITY)
422 cancelAutoHideCursorTimer();
424 m_resizeLayer = nullptr;
425 m_elementUnderMouse = nullptr;
426 m_lastElementUnderMouse = nullptr;
427 m_lastMouseMoveEventSubframe = nullptr;
428 m_lastScrollbarUnderMouse = nullptr;
430 m_clickNode = nullptr;
431 #if ENABLE(IOS_GESTURE_EVENTS)
432 m_gestureInitialDiameter = GestureUnknown;
433 m_gestureInitialRotation = GestureUnknown;
435 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
436 m_gestureLastDiameter = GestureUnknown;
437 m_gestureLastRotation = GestureUnknown;
438 m_gestureTargets.clear();
440 #if ENABLE(IOS_TOUCH_EVENTS)
442 m_firstTouchID = InvalidTouchIdentifier;
443 m_touchEventTargetSubframe = nullptr;
445 m_frameSetBeingResized = nullptr;
446 #if ENABLE(DRAG_SUPPORT)
447 m_dragTarget = nullptr;
448 m_shouldOnlyFireDragOverEvent = false;
450 m_mousePositionIsUnknown = true;
451 m_lastKnownMousePosition = IntPoint();
452 m_lastKnownMouseGlobalPosition = IntPoint();
453 m_mousePressNode = nullptr;
454 m_mousePressed = false;
455 m_capturesDragging = false;
456 m_capturingMouseEventsElement = nullptr;
458 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
459 m_originatingTouchPointTargets.clear();
460 m_originatingTouchPointDocument = nullptr;
461 m_originatingTouchPointTargetKey = 0;
463 m_maxMouseMovedDuration = 0;
464 m_baseEventType = PlatformEvent::NoType;
465 m_didStartDrag = false;
468 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
470 if (nodeToBeRemoved.contains(m_clickNode.get()))
471 m_clickNode = nullptr;
474 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
476 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection))
477 selection.setSelection(newSelection);
480 static inline bool dispatchSelectStart(Node* node)
482 if (!node || !node->renderer())
485 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
488 static Node* nodeToSelectOnMouseDownForNode(Node& targetNode)
490 #if ENABLE(USERSELECT_ALL)
491 if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(&targetNode))
492 return rootUserSelectAll;
495 if (targetNode.shouldSelectOnMouseDown())
501 static VisibleSelection expandSelectionToRespectSelectOnMouseDown(Node& targetNode, const VisibleSelection& selection)
503 Node* nodeToSelect = nodeToSelectOnMouseDownForNode(targetNode);
507 VisibleSelection newSelection(selection);
508 newSelection.setBase(positionBeforeNode(nodeToSelect).upstream(CanCrossEditingBoundary));
509 newSelection.setExtent(positionAfterNode(nodeToSelect).downstream(CanCrossEditingBoundary));
514 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
516 if (Position::nodeIsUserSelectNone(targetNode))
519 if (!dispatchSelectStart(targetNode))
522 if (selection.isRange())
523 m_selectionInitiationState = ExtendedSelection;
525 granularity = CharacterGranularity;
526 m_selectionInitiationState = PlacedCaret;
529 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity);
534 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
536 Node* targetNode = result.targetNode();
537 VisibleSelection newSelection;
539 if (targetNode && targetNode->renderer()) {
540 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
541 if (pos.isNotNull()) {
542 newSelection = VisibleSelection(pos);
543 newSelection.expandUsingGranularity(WordGranularity);
546 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
547 newSelection.appendTrailingWhitespace();
549 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
553 static AppendTrailingWhitespace shouldAppendTrailingWhitespace(const MouseEventWithHitTestResults& result, const Frame& frame)
555 return (result.event().clickCount() == 2 && frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace;
558 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
560 if (m_mouseDownMayStartSelect)
561 selectClosestWordFromHitTestResult(result.hitTestResult(), shouldAppendTrailingWhitespace(result, m_frame));
565 VisibleSelection EventHandler::selectClosestWordFromHitTestResultBasedOnLookup(const HitTestResult&)
567 return VisibleSelection();
571 void EventHandler::selectClosestContextualWordFromMouseEvent(const MouseEventWithHitTestResults& mouseEvent)
573 Node* targetNode = mouseEvent.targetNode();
574 const HitTestResult& result = mouseEvent.hitTestResult();
575 VisibleSelection newSelection;
576 bool appendTrailingWhitespace = shouldAppendTrailingWhitespace(mouseEvent, m_frame);
578 if (targetNode && targetNode->renderer()) {
579 newSelection = selectClosestWordFromHitTestResultBasedOnLookup(result);
580 if (newSelection.isNone()) {
581 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
582 if (pos.isNotNull()) {
583 newSelection = VisibleSelection(pos);
584 newSelection.expandUsingGranularity(WordGranularity);
588 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
589 newSelection.appendTrailingWhitespace();
591 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
595 void EventHandler::selectClosestContextualWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
597 Element* urlElement = result.hitTestResult().URLElement();
598 if (!urlElement || !isDraggableLink(*urlElement)) {
599 if (Node* targetNode = result.targetNode()) {
600 if (isEditableNode(*targetNode))
601 return selectClosestWordFromMouseEvent(result);
604 return selectClosestContextualWordFromMouseEvent(result);
607 Node* targetNode = result.targetNode();
609 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) {
610 VisibleSelection newSelection;
611 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
612 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(urlElement))
613 newSelection = VisibleSelection::selectionFromContentsOfNode(urlElement);
615 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
619 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
621 if (event.event().button() != LeftButton)
624 if (m_frame.selection().isRange())
625 // A double-click when range is already selected
626 // should not change the selection. So, do not call
627 // selectClosestWordFromMouseEvent, but do set
628 // m_beganSelectingText to prevent handleMouseReleaseEvent
629 // from setting caret selection.
630 m_selectionInitiationState = ExtendedSelection;
632 selectClosestWordFromMouseEvent(event);
637 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
639 if (event.event().button() != LeftButton)
642 Node* targetNode = event.targetNode();
643 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
646 VisibleSelection newSelection;
647 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
648 if (pos.isNotNull()) {
649 newSelection = VisibleSelection(pos);
650 newSelection.expandUsingGranularity(ParagraphGranularity);
653 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), ParagraphGranularity);
656 static int textDistance(const Position& start, const Position& end)
658 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
659 return TextIterator::rangeLength(range.get(), true);
662 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
664 Ref<Frame> protectedFrame(m_frame);
666 m_frame.document()->updateLayoutIgnorePendingStylesheets();
667 Node* targetNode = event.targetNode();
668 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
671 // Extend the selection if the Shift key is down, unless the click is in a link.
672 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
674 // Don't restart the selection when the mouse is pressed on an
675 // existing selection so we can allow for text dragging.
676 if (FrameView* view = m_frame.view()) {
677 LayoutPoint vPoint = view->windowToContents(event.event().position());
678 if (!extendSelection && m_frame.selection().contains(vPoint)) {
679 m_mouseDownWasSingleClickInSelection = true;
684 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
685 if (visiblePos.isNull())
686 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM);
687 Position pos = visiblePos.deepEquivalent();
689 VisibleSelection newSelection = m_frame.selection().selection();
690 TextGranularity granularity = CharacterGranularity;
692 if (extendSelection && newSelection.isCaretOrRange()) {
693 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectSelectOnMouseDown(*targetNode, VisibleSelection(pos));
694 if (selectionInUserSelectAll.isRange()) {
695 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
696 pos = selectionInUserSelectAll.start();
697 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
698 pos = selectionInUserSelectAll.end();
701 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) {
702 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
703 // was created right-to-left
704 Position start = newSelection.start();
705 Position end = newSelection.end();
706 int distanceToStart = textDistance(start, pos);
707 int distanceToEnd = textDistance(pos, end);
708 if (distanceToStart <= distanceToEnd)
709 newSelection = VisibleSelection(end, pos);
711 newSelection = VisibleSelection(start, pos);
713 newSelection.setExtent(pos);
715 if (m_frame.selection().granularity() != CharacterGranularity) {
716 granularity = m_frame.selection().granularity();
717 newSelection.expandUsingGranularity(m_frame.selection().granularity());
720 newSelection = expandSelectionToRespectSelectOnMouseDown(*targetNode, visiblePos);
722 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity);
724 if (event.event().button() == MiddleButton) {
725 // Ignore handled, since we want to paste to where the caret was placed anyway.
726 handled = handlePasteGlobalSelection(event.event()) || handled;
731 static inline bool canMouseDownStartSelect(Node* node)
733 if (!node || !node->renderer())
736 return node->canStartSelection() || Position::nodeIsUserSelectAll(node);
739 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
741 Ref<Frame> protectedFrame(m_frame);
743 #if ENABLE(DRAG_SUPPORT)
745 dragState().source = nullptr;
748 #if !ENABLE(IOS_TOUCH_EVENTS)
749 cancelFakeMouseMoveEvent();
752 m_frame.document()->updateLayoutIgnorePendingStylesheets();
754 if (ScrollView* scrollView = m_frame.view()) {
755 if (scrollView->isPointInScrollbarCorner(event.event().position()))
759 bool singleClick = event.event().clickCount() <= 1;
761 // If we got the event back, that must mean it wasn't prevented,
762 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
763 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
765 #if ENABLE(DRAG_SUPPORT)
766 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
767 // FIXME: eventMayStartDrag() does not check for shift key press, link or image event targets.
768 // Bug: https://bugs.webkit.org/show_bug.cgi?id=155390
770 // Single mouse down on links or images can always trigger drag-n-drop.
771 bool isMouseDownOnLinkOrImage = event.isOverLink() || event.hitTestResult().image();
772 m_mouseDownMayStartDrag = singleClick && (!event.event().shiftKey() || isMouseDownOnLinkOrImage);
775 m_mouseDownWasSingleClickInSelection = false;
777 m_mouseDown = event.event();
779 if (m_immediateActionStage != ImmediateActionStage::PerformedHitTest)
780 m_immediateActionStage = ImmediateActionStage::None;
782 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
785 if (is<SVGDocument>(*m_frame.document()) && downcast<SVGDocument>(*m_frame.document()).zoomAndPanEnabled()) {
786 if (event.event().shiftKey() && singleClick) {
788 downcast<SVGDocument>(*m_frame.document()).startPan(m_frame.view()->windowToContents(event.event().position()));
793 // We don't do this at the start of mouse down handling,
794 // because we don't want to do it until we know we didn't hit a widget.
798 m_mousePressNode = event.targetNode();
799 m_frame.document()->setFocusNavigationStartingNode(event.targetNode());
800 #if ENABLE(DRAG_SUPPORT)
801 m_dragStartPos = event.event().position();
804 bool swallowEvent = false;
805 m_mousePressed = true;
806 m_selectionInitiationState = HaveNotStartedSelection;
808 if (event.event().clickCount() == 2)
809 swallowEvent = handleMousePressEventDoubleClick(event);
810 else if (event.event().clickCount() >= 3)
811 swallowEvent = handleMousePressEventTripleClick(event);
813 swallowEvent = handleMousePressEventSingleClick(event);
815 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
816 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
821 #if ENABLE(DRAG_SUPPORT)
822 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
827 Ref<Frame> protectedFrame(m_frame);
829 if (handleDrag(event, ShouldCheckDragHysteresis))
832 Node* targetNode = event.targetNode();
833 if (event.event().button() != LeftButton || !targetNode)
836 RenderObject* renderer = targetNode->renderer();
838 Element* parent = targetNode->parentOrShadowHostElement();
842 renderer = parent->renderer();
843 if (!renderer || !renderer->isListBox())
847 #if PLATFORM(COCOA) // FIXME: Why does this assertion fire on other platforms?
848 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
851 m_mouseDownMayStartDrag = false;
853 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
854 m_autoscrollController->startAutoscrollForSelection(renderer);
855 m_mouseDownMayStartAutoscroll = false;
858 if (m_selectionInitiationState != ExtendedSelection) {
859 HitTestResult result(m_mouseDownPos);
860 m_frame.document()->renderView()->hitTest(HitTestRequest(), result);
862 updateSelectionForMouseDrag(result);
864 updateSelectionForMouseDrag(event.hitTestResult());
868 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
870 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
871 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
872 // in handleMousePressEvent
873 RenderView* renderView = m_frame.contentRenderer();
877 if (event.button() != LeftButton || event.clickCount() != 1)
880 FrameView* view = m_frame.view();
884 Page* page = m_frame.page();
888 Ref<Frame> protectedFrame(m_frame);
890 updateDragSourceActionsAllowed();
891 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
892 HitTestResult result(view->windowToContents(event.position()));
893 renderView->hitTest(request, result);
895 return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
898 void EventHandler::updateSelectionForMouseDrag()
900 FrameView* view = m_frame.view();
903 RenderView* renderView = m_frame.contentRenderer();
907 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
908 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
909 renderView->hitTest(request, result);
910 updateSelectionForMouseDrag(result);
913 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
915 FloatPoint selectionEndPoint = localPoint;
916 Element* editableElement = selection.rootEditableElement();
918 if (!targetNode->renderer())
919 return VisiblePosition();
921 if (editableElement && !editableElement->contains(targetNode)) {
922 if (!editableElement->renderer())
923 return VisiblePosition();
925 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
926 selectionEndPoint = editableElement->renderer()->absoluteToLocal(absolutePoint);
927 targetNode = editableElement;
930 return targetNode->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr);
933 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
935 if (!m_mouseDownMayStartSelect)
938 Node* target = hitTestResult.targetNode();
942 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target);
944 // Don't modify the selection if we're not on a node.
945 if (targetPosition.isNull())
948 // Restart the selection if this is the first mouse move. This work is usually
949 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
950 VisibleSelection newSelection = m_frame.selection().selection();
952 // Special case to limit selection to the containing block for SVG text.
953 // FIXME: Isn't there a better non-SVG-specific way to do this?
954 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
955 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
956 if (selectionBaseRenderer->isSVGText())
957 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
960 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
963 if (m_selectionInitiationState != ExtendedSelection) {
964 // Always extend selection here because it's caused by a mouse drag
965 m_selectionInitiationState = ExtendedSelection;
966 newSelection = VisibleSelection(targetPosition);
969 #if ENABLE(USERSELECT_ALL)
970 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
971 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
972 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
973 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
975 // Reset base for user select all when base is inside user-select-all area and extent < base.
976 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
977 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
979 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
980 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
981 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
982 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
983 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
985 newSelection.setExtent(targetPosition);
988 newSelection.setExtent(targetPosition);
991 if (m_frame.selection().granularity() != CharacterGranularity)
992 newSelection.expandUsingGranularity(m_frame.selection().granularity());
994 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
995 FrameSelection::AdjustEndpointsAtBidiBoundary);
997 #endif // ENABLE(DRAG_SUPPORT)
999 void EventHandler::lostMouseCapture()
1001 m_frame.selection().setCaretBlinkingSuspended(false);
1004 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
1006 if (eventLoopHandleMouseUp(event))
1009 // If this was the first click in the window, we don't even want to clear the selection.
1010 // This case occurs when the user clicks on a draggable element, since we have to process
1011 // the mouse down and drag events to see if we might start a drag. For other first clicks
1012 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1013 // ignored upstream of this layer.
1014 return eventActivatedView(event.event());
1017 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1019 if (autoscrollInProgress())
1020 stopAutoscrollTimer();
1022 Ref<Frame> protectedFrame(m_frame);
1024 if (handleMouseUp(event))
1027 // Used to prevent mouseMoveEvent from initiating a drag before
1028 // the mouse is pressed again.
1029 m_mousePressed = false;
1030 m_capturesDragging = false;
1031 #if ENABLE(DRAG_SUPPORT)
1032 m_mouseDownMayStartDrag = false;
1034 m_mouseDownMayStartSelect = false;
1035 m_mouseDownMayStartAutoscroll = false;
1036 m_mouseDownWasInSubframe = false;
1038 bool handled = false;
1040 // Clear the selection if the mouse didn't move after the last mouse
1041 // press and it's not a context menu click. We do this so when clicking
1042 // on the selection, the selection goes away. However, if we are
1043 // editing, place the caret.
1044 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
1045 #if ENABLE(DRAG_SUPPORT)
1046 && m_dragStartPos == event.event().position()
1048 && m_frame.selection().isRange()
1049 && event.event().button() != RightButton) {
1050 VisibleSelection newSelection;
1051 Node* node = event.targetNode();
1052 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
1053 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
1054 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint(), nullptr);
1055 newSelection = VisibleSelection(pos);
1058 setSelectionIfNeeded(m_frame.selection(), newSelection);
1063 if (event.event().button() == MiddleButton) {
1064 // Ignore handled, since we want to paste to where the caret was placed anyway.
1065 handled = handlePasteGlobalSelection(event.event()) || handled;
1071 #if ENABLE(PAN_SCROLLING)
1073 void EventHandler::didPanScrollStart()
1075 m_autoscrollController->didPanScrollStart();
1078 void EventHandler::didPanScrollStop()
1080 m_autoscrollController->didPanScrollStop();
1083 void EventHandler::startPanScrolling(RenderElement* renderer)
1086 if (!is<RenderBox>(*renderer))
1088 m_autoscrollController->startPanScrolling(downcast<RenderBox>(renderer), lastKnownMousePosition());
1093 #endif // ENABLE(PAN_SCROLLING)
1095 RenderBox* EventHandler::autoscrollRenderer() const
1097 return m_autoscrollController->autoscrollRenderer();
1100 void EventHandler::updateAutoscrollRenderer()
1102 m_autoscrollController->updateAutoscrollRenderer();
1105 bool EventHandler::autoscrollInProgress() const
1107 return m_autoscrollController->autoscrollInProgress();
1110 bool EventHandler::panScrollInProgress() const
1112 return m_autoscrollController->panScrollInProgress();
1115 #if ENABLE(DRAG_SUPPORT)
1116 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1118 Page* page = m_frame.page();
1120 return DragSourceActionNone;
1122 FrameView* view = m_frame.view();
1124 return DragSourceActionNone;
1126 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1128 #endif // ENABLE(DRAG_SUPPORT)
1130 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1132 Ref<Frame> protectedFrame(m_frame);
1134 // We always send hitTestResultAtPoint to the main frame if we have one,
1135 // otherwise we might hit areas that are obscured by higher frames.
1136 if (!m_frame.isMainFrame()) {
1137 Frame& mainFrame = m_frame.mainFrame();
1138 FrameView* frameView = m_frame.view();
1139 FrameView* mainView = mainFrame.view();
1140 if (frameView && mainView) {
1141 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
1142 return mainFrame.eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
1146 unsigned nonNegativePaddingWidth = std::max<LayoutUnit>(0, padding.width()).toUnsigned();
1147 unsigned nonNegativePaddingHeight = std::max<LayoutUnit>(0, padding.height()).toUnsigned();
1149 // We should always start hit testing a clean tree.
1150 if (auto* frameView = m_frame.view())
1151 frameView->updateLayoutAndStyleIfNeededRecursive();
1153 HitTestResult result(point, nonNegativePaddingHeight, nonNegativePaddingWidth, nonNegativePaddingHeight, nonNegativePaddingWidth);
1154 RenderView* renderView = m_frame.contentRenderer();
1158 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
1159 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
1160 renderView->hitTest(request, result);
1161 if (!request.readOnly())
1162 m_frame.document()->updateHoverActiveState(request, result.innerElement());
1164 if (request.disallowsUserAgentShadowContent())
1165 result.setToNonUserAgentShadowAncestor();
1170 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1172 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed);
1175 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1177 Node* node = startingNode;
1180 node = m_frame.document()->focusedElement();
1183 node = m_mousePressNode.get();
1186 auto r = node->renderer();
1187 if (r && !r->isListBox() && r->enclosingBox().scroll(direction, granularity)) {
1188 setFrameWasScrolledByUser();
1196 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1198 Node* node = startingNode;
1201 node = m_frame.document()->focusedElement();
1204 node = m_mousePressNode.get();
1207 auto r = node->renderer();
1208 if (r && !r->isListBox() && r->enclosingBox().logicalScroll(direction, granularity)) {
1209 setFrameWasScrolledByUser();
1217 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1219 Ref<Frame> protectedFrame(m_frame);
1221 // The layout needs to be up to date to determine if we can scroll. We may be
1222 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1223 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1224 if (scrollOverflow(direction, granularity, startingNode))
1226 Frame* frame = &m_frame;
1227 FrameView* view = frame->view();
1228 if (view && view->scroll(direction, granularity))
1230 frame = frame->tree().parent();
1233 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement());
1236 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1238 Ref<Frame> protectedFrame(m_frame);
1240 // The layout needs to be up to date to determine if we can scroll. We may be
1241 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1242 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1243 if (logicalScrollOverflow(direction, granularity, startingNode))
1245 Frame* frame = &m_frame;
1246 FrameView* view = frame->view();
1248 bool scrolled = false;
1250 // Mac also resets the scroll position in the inline direction.
1251 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1254 if (view && view->logicalScroll(direction, granularity))
1260 frame = frame->tree().parent();
1264 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement());
1267 IntPoint EventHandler::lastKnownMousePosition() const
1269 return m_lastKnownMousePosition;
1272 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1274 if (!hitTestResult.isOverWidget())
1276 return subframeForTargetNode(hitTestResult.targetNode());
1279 Frame* EventHandler::subframeForTargetNode(Node* node)
1284 auto renderer = node->renderer();
1285 if (!is<RenderWidget>(renderer))
1288 Widget* widget = downcast<RenderWidget>(*renderer).widget();
1289 if (!is<FrameView>(widget))
1292 return &downcast<FrameView>(*widget).frame();
1295 #if ENABLE(CURSOR_SUPPORT)
1296 static bool isSubmitImage(Node* node)
1298 return is<HTMLInputElement>(node) && downcast<HTMLInputElement>(*node).isImageButton();
1301 // Returns true if the node's editable block is not current focused for editing
1302 static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame)
1304 return frame.selection().selection().rootEditableElement() != node.rootEditableElement();
1307 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1312 bool editable = node->hasEditableStyle();
1313 bool editableLinkEnabled = false;
1315 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1317 switch (m_frame.settings().editableLinkBehavior()) {
1319 case EditableLinkDefaultBehavior:
1320 case EditableLinkAlwaysLive:
1321 editableLinkEnabled = true;
1324 case EditableLinkNeverLive:
1325 editableLinkEnabled = false;
1328 case EditableLinkLiveWhenNotFocused:
1329 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey;
1332 case EditableLinkOnlyLiveWithShiftKey:
1333 editableLinkEnabled = shiftKey;
1338 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1341 void EventHandler::cursorUpdateTimerFired()
1343 ASSERT(m_frame.document());
1347 void EventHandler::updateCursor()
1349 if (m_mousePositionIsUnknown)
1352 FrameView* view = m_frame.view();
1356 RenderView* renderView = view->renderView();
1360 if (!view->shouldSetCursor())
1367 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1369 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::AllowFrameScrollbars);
1370 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1371 renderView->hitTest(request, result);
1373 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1374 if (optionalCursor.isCursorChange()) {
1375 m_currentMouseCursor = optionalCursor.cursor();
1376 view->setCursor(m_currentMouseCursor);
1380 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1382 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1383 return NoCursorChange;
1385 if (!m_frame.page())
1386 return NoCursorChange;
1388 #if ENABLE(PAN_SCROLLING)
1389 if (m_frame.mainFrame().eventHandler().panScrollInProgress())
1390 return NoCursorChange;
1393 Ref<Frame> protectedFrame(m_frame);
1395 // Use always pointer cursor for scrollbars.
1396 if (result.scrollbar()) {
1397 #if ENABLE(CURSOR_VISIBILITY)
1398 cancelAutoHideCursorTimer();
1400 return pointerCursor();
1403 Node* node = result.targetNode();
1405 return NoCursorChange;
1407 auto renderer = node->renderer();
1408 auto* style = renderer ? &renderer->style() : nullptr;
1409 bool horizontalText = !style || style->isHorizontalWritingMode();
1410 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1412 #if ENABLE(CURSOR_VISIBILITY)
1413 if (style && style->cursorVisibility() == CursorVisibilityAutoHide)
1414 startAutoHideCursorTimer();
1416 cancelAutoHideCursorTimer();
1420 Cursor overrideCursor;
1421 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1422 case SetCursorBasedOnStyle:
1425 return overrideCursor;
1426 case DoNotSetCursor:
1427 return NoCursorChange;
1431 if (style && style->cursors()) {
1432 const CursorList* cursors = style->cursors();
1433 for (unsigned i = 0; i < cursors->size(); ++i) {
1434 StyleImage* styleImage = (*cursors)[i].image();
1437 CachedImage* cachedImage = styleImage->cachedImage();
1440 float scale = styleImage->imageScaleFactor();
1441 // Get hotspot and convert from logical pixels to physical pixels.
1442 IntPoint hotSpot = (*cursors)[i].hotSpot();
1443 FloatSize size = cachedImage->imageForRenderer(renderer)->size();
1444 if (cachedImage->errorOccurred())
1446 // Limit the size of cursors (in UI pixels) so that they cannot be
1447 // used to cover UI elements in chrome.
1448 size.scale(1 / scale);
1449 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1452 Image* image = cachedImage->imageForRenderer(renderer);
1453 #if ENABLE(MOUSE_CURSOR_SCALE)
1454 // Ensure no overflow possible in calculations above.
1455 if (scale < minimumCursorScale)
1457 return Cursor(image, hotSpot, scale);
1460 return Cursor(image, hotSpot);
1461 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1465 // During selection, use an I-beam regardless of the content beneath the cursor.
1466 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1468 && m_mouseDownMayStartSelect
1469 #if ENABLE(DRAG_SUPPORT)
1470 && !m_mouseDownMayStartDrag
1472 && m_frame.selection().isCaretOrRange()
1473 && !m_capturingMouseEventsElement)
1476 switch (style ? style->cursor() : CursorAuto) {
1478 bool editable = node->hasEditableStyle();
1480 if (useHandCursor(node, result.isOverLink(), shiftKey))
1481 return handCursor();
1483 bool inResizer = false;
1485 if (RenderLayer* layer = renderer->enclosingLayer()) {
1486 if (FrameView* view = m_frame.view())
1487 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1491 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1493 return pointerCursor();
1496 return crossCursor();
1498 return handCursor();
1500 return moveCursor();
1501 case CursorAllScroll:
1502 return moveCursor();
1504 return eastResizeCursor();
1506 return westResizeCursor();
1508 return northResizeCursor();
1510 return southResizeCursor();
1511 case CursorNeResize:
1512 return northEastResizeCursor();
1513 case CursorSwResize:
1514 return southWestResizeCursor();
1515 case CursorNwResize:
1516 return northWestResizeCursor();
1517 case CursorSeResize:
1518 return southEastResizeCursor();
1519 case CursorNsResize:
1520 return northSouthResizeCursor();
1521 case CursorEwResize:
1522 return eastWestResizeCursor();
1523 case CursorNeswResize:
1524 return northEastSouthWestResizeCursor();
1525 case CursorNwseResize:
1526 return northWestSouthEastResizeCursor();
1527 case CursorColResize:
1528 return columnResizeCursor();
1529 case CursorRowResize:
1530 return rowResizeCursor();
1532 return iBeamCursor();
1534 return waitCursor();
1536 return helpCursor();
1537 case CursorVerticalText:
1538 return verticalTextCursor();
1540 return cellCursor();
1541 case CursorContextMenu:
1542 return contextMenuCursor();
1543 case CursorProgress:
1544 return progressCursor();
1546 return noDropCursor();
1548 return aliasCursor();
1550 return copyCursor();
1552 return noneCursor();
1553 case CursorNotAllowed:
1554 return notAllowedCursor();
1556 return pointerCursor();
1558 return zoomInCursor();
1560 return zoomOutCursor();
1561 case CursorWebkitGrab:
1562 return grabCursor();
1563 case CursorWebkitGrabbing:
1564 return grabbingCursor();
1566 return pointerCursor();
1568 #endif // ENABLE(CURSOR_SUPPORT)
1570 #if ENABLE(CURSOR_VISIBILITY)
1571 void EventHandler::startAutoHideCursorTimer()
1573 Page* page = m_frame.page();
1577 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
1579 #if !ENABLE(IOS_TOUCH_EVENTS)
1580 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1581 // so cancel any pending fake mouse moves.
1582 if (m_fakeMouseMoveEventTimer.isActive())
1583 m_fakeMouseMoveEventTimer.stop();
1587 void EventHandler::cancelAutoHideCursorTimer()
1589 if (m_autoHideCursorTimer.isActive())
1590 m_autoHideCursorTimer.stop();
1593 void EventHandler::autoHideCursorTimerFired()
1595 m_currentMouseCursor = noneCursor();
1596 FrameView* view = m_frame.view();
1597 if (view && view->isActive())
1598 view->setCursor(m_currentMouseCursor);
1602 static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
1604 FrameView* view = frame.view();
1605 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1606 // Historically the code would just crash; this is clearly no worse than that.
1607 return view ? view->windowToContents(windowPoint) : windowPoint;
1610 static Scrollbar* scrollbarForMouseEvent(const MouseEventWithHitTestResults& mouseEvent, FrameView* view)
1613 if (auto* scrollbar = view->scrollbarAtPoint(mouseEvent.event().position()))
1616 return mouseEvent.scrollbar();
1620 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& platformMouseEvent)
1622 Ref<Frame> protectedFrame(m_frame);
1623 RefPtr<FrameView> protector(m_frame.view());
1625 if (InspectorInstrumentation::handleMousePress(m_frame)) {
1630 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
1633 #if ENABLE(TOUCH_EVENTS)
1634 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1635 if (defaultPrevented)
1639 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
1641 // FIXME (bug 68185): this call should be made at another abstraction layer
1642 m_frame.loader().resetMultipleFormSubmissionProtection();
1644 #if !ENABLE(IOS_TOUCH_EVENTS)
1645 cancelFakeMouseMoveEvent();
1647 m_mousePressed = true;
1648 m_capturesDragging = true;
1649 setLastKnownMousePosition(platformMouseEvent);
1650 m_mouseDownTimestamp = platformMouseEvent.timestamp();
1651 #if ENABLE(DRAG_SUPPORT)
1652 m_mouseDownMayStartDrag = false;
1654 m_mouseDownMayStartSelect = false;
1655 m_mouseDownMayStartAutoscroll = false;
1656 if (FrameView* view = m_frame.view())
1657 m_mouseDownPos = view->windowToContents(platformMouseEvent.position());
1662 m_mouseDownWasInSubframe = false;
1664 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
1665 // Save the document point we generate in case the window coordinate is invalidated by what happens
1666 // when we dispatch the event.
1667 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, platformMouseEvent.position());
1668 MouseEventWithHitTestResults mouseEvent = m_frame.document()->prepareMouseEvent(request, documentPoint, platformMouseEvent);
1670 if (!mouseEvent.targetNode()) {
1675 m_mousePressNode = mouseEvent.targetNode();
1676 m_frame.document()->setFocusNavigationStartingNode(mouseEvent.targetNode());
1678 RefPtr<Frame> subframe = subframeForHitTestResult(mouseEvent);
1679 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe.get())) {
1680 // Start capturing future events for this frame. We only do this if we didn't clear
1681 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1682 m_capturesDragging = subframe->eventHandler().capturesDragging();
1683 if (m_mousePressed && m_capturesDragging) {
1684 m_capturingMouseEventsElement = subframe->ownerElement();
1685 m_eventHandlerWillResetCapturingMouseEventsElement = true;
1691 #if ENABLE(PAN_SCROLLING)
1692 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1693 // because it will set m_autoscrollType to NoAutoscroll on return.
1694 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress();
1695 stopAutoscrollTimer();
1696 if (isPanScrollInProgress) {
1697 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1698 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1704 m_clickCount = platformMouseEvent.clickCount();
1705 m_clickNode = mouseEvent.targetNode();
1712 if (FrameView* view = m_frame.view()) {
1713 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1714 IntPoint p = view->windowToContents(platformMouseEvent.position());
1715 if (layer && layer->isPointInResizeControl(p)) {
1716 layer->setInResizeMode(true);
1717 m_resizeLayer = layer;
1718 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1724 m_frame.selection().setCaretBlinkingSuspended(true);
1726 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1727 m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
1729 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1730 // in case the scrollbar widget was destroyed when the mouse event was handled.
1731 if (mouseEvent.scrollbar()) {
1732 const bool wasLastScrollBar = mouseEvent.scrollbar() == m_lastScrollbarUnderMouse;
1733 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1734 if (wasLastScrollBar && mouseEvent.scrollbar() != m_lastScrollbarUnderMouse)
1735 m_lastScrollbarUnderMouse = nullptr;
1738 if (!swallowEvent) {
1739 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1740 // If a mouse event handler changes the input element type to one that has a widget associated,
1741 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1742 // event target node can't still be the shadow node.
1743 if (is<ShadowRoot>(*mouseEvent.targetNode()) && is<HTMLInputElement>(*downcast<ShadowRoot>(*mouseEvent.targetNode()).host()))
1744 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1747 Scrollbar* scrollbar = scrollbarForMouseEvent(mouseEvent, m_frame.view());
1748 updateLastScrollbarUnderMouse(scrollbar, true);
1750 bool passedToScrollbar = scrollbar && passMousePressEventToScrollbar(mouseEvent, scrollbar);
1751 if (!swallowEvent) {
1752 if (passedToScrollbar)
1753 swallowEvent = true;
1755 swallowEvent = handleMousePressEvent(mouseEvent);
1757 return swallowEvent;
1760 // This method only exists for platforms that don't know how to deliver
1761 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& platformMouseEvent)
1763 Ref<Frame> protectedFrame(m_frame);
1764 RefPtr<FrameView> protector(m_frame.view());
1766 m_frame.selection().setCaretBlinkingSuspended(false);
1768 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
1770 // We get this instead of a second mouse-up
1771 m_mousePressed = false;
1772 setLastKnownMousePosition(platformMouseEvent);
1774 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
1775 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1776 Frame* subframe = subframeForHitTestResult(mouseEvent);
1777 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1778 m_capturingMouseEventsElement = nullptr;
1779 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe))
1782 m_clickCount = platformMouseEvent.clickCount();
1783 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
1785 bool swallowClickEvent = platformMouseEvent.button() != RightButton && mouseEvent.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1787 if (m_lastScrollbarUnderMouse)
1788 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
1790 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mouseEvent);
1794 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1797 static ScrollableArea* enclosingScrollableArea(Node* node)
1799 for (auto ancestor = node; ancestor; ancestor = ancestor->parentOrShadowHostNode()) {
1800 if (is<HTMLIFrameElement>(*ancestor) || is<HTMLHtmlElement>(*ancestor) || is<HTMLDocument>(*ancestor))
1803 auto renderer = ancestor->renderer();
1807 if (is<RenderListBox>(*renderer))
1808 return downcast<RenderListBox>(renderer);
1810 return renderer->enclosingLayer();
1816 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1818 Ref<Frame> protectedFrame(m_frame);
1819 RefPtr<FrameView> protector(m_frame.view());
1820 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1822 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(event))
1825 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1826 bool result = handleMouseMoveEvent(event, &hoveredNode);
1828 Page* page = m_frame.page();
1832 if (auto scrolledArea = enclosingScrollableArea(hoveredNode.innerNode())) {
1833 if (FrameView* frameView = m_frame.view()) {
1834 if (frameView->containsScrollableArea(scrolledArea))
1835 scrolledArea->mouseMovedInContentArea();
1839 if (FrameView* frameView = m_frame.view())
1840 frameView->mouseMovedInContentArea();
1842 hoveredNode.setToNonUserAgentShadowAncestor();
1843 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1844 page->chrome().setToolTip(hoveredNode);
1848 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1850 HitTestResult hoveredNode;
1851 return handleMouseMoveEvent(event, &hoveredNode, true);
1854 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1856 #if ENABLE(TOUCH_EVENTS)
1857 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1858 if (defaultPrevented)
1862 Ref<Frame> protectedFrame(m_frame);
1863 RefPtr<FrameView> protector(m_frame.view());
1865 setLastKnownMousePosition(platformMouseEvent);
1867 if (m_hoverTimer.isActive())
1868 m_hoverTimer.stop();
1870 #if ENABLE(CURSOR_SUPPORT)
1871 m_cursorUpdateTimer.stop();
1874 #if !ENABLE(IOS_TOUCH_EVENTS)
1875 cancelFakeMouseMoveEvent();
1879 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1883 if (m_frameSetBeingResized)
1884 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, platformMouseEvent, false);
1886 // On iOS, our scrollbars are managed by UIKit.
1888 // Send events right to a scrollbar if the mouse is pressed.
1889 if (m_lastScrollbarUnderMouse && m_mousePressed)
1890 return m_lastScrollbarUnderMouse->mouseMoved(platformMouseEvent);
1893 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowFrameScrollbars;
1895 hitType |= HitTestRequest::Active;
1896 else if (onlyUpdateScrollbars) {
1897 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1898 // means that :hover and :active freeze in the state they were in, rather than updating
1899 // for nodes the mouse moves while the window is not key (which will be the case if
1900 // onlyUpdateScrollbars is true).
1901 hitType |= HitTestRequest::ReadOnly;
1904 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
1905 // Treat any mouse move events as readonly if the user is currently touching the screen.
1907 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1909 HitTestRequest request(hitType);
1910 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1912 *hoveredNode = mouseEvent.hitTestResult();
1914 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1915 m_resizeLayer->resize(platformMouseEvent, m_offsetFromResizeCorner);
1917 Scrollbar* scrollbar = mouseEvent.scrollbar();
1918 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1920 // On iOS, our scrollbars are managed by UIKit.
1922 if (!m_mousePressed && scrollbar)
1923 scrollbar->mouseMoved(platformMouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1925 if (onlyUpdateScrollbars) {
1926 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1931 bool swallowEvent = false;
1932 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
1934 // 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.
1935 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1936 passMouseMoveEventToSubframe(mouseEvent, m_lastMouseMoveEventSubframe.get());
1939 // Update over/out state before passing the event to the subframe.
1940 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1942 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1943 // node to be detached from its FrameView, in which case the event should not be passed.
1944 if (newSubframe->view())
1945 swallowEvent |= passMouseMoveEventToSubframe(mouseEvent, newSubframe.get(), hoveredNode);
1946 #if ENABLE(CURSOR_SUPPORT)
1948 if (FrameView* view = m_frame.view()) {
1949 OptionalCursor optionalCursor = selectCursor(mouseEvent.hitTestResult(), platformMouseEvent.shiftKey());
1950 if (optionalCursor.isCursorChange()) {
1951 m_currentMouseCursor = optionalCursor.cursor();
1952 view->setCursor(m_currentMouseCursor);
1958 m_lastMouseMoveEventSubframe = newSubframe;
1963 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
1964 #if ENABLE(DRAG_SUPPORT)
1966 swallowEvent = handleMouseDraggedEvent(mouseEvent);
1967 #endif // ENABLE(DRAG_SUPPORT)
1969 return swallowEvent;
1972 void EventHandler::invalidateClick()
1975 m_clickNode = nullptr;
1978 static Node* targetNodeForClickEvent(Node* mousePressNode, Node* mouseReleaseNode)
1980 if (!mousePressNode || !mouseReleaseNode)
1983 if (mousePressNode == mouseReleaseNode)
1984 return mouseReleaseNode;
1986 Element* mouseReleaseShadowHost = mouseReleaseNode->shadowHost();
1987 if (mouseReleaseShadowHost && mouseReleaseShadowHost == mousePressNode->shadowHost()) {
1988 // We want to dispatch the click to the shadow tree host element to give listeners the illusion that the
1989 // shadom tree is a single element. For example, we want to give the illusion that <input type="range">
1990 // is a single element even though it is a composition of multiple shadom tree elements.
1991 return mouseReleaseShadowHost;
1996 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMouseEvent)
1998 Ref<Frame> protectedFrame(m_frame);
1999 RefPtr<FrameView> protector(m_frame.view());
2001 m_frame.selection().setCaretBlinkingSuspended(false);
2003 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
2006 #if ENABLE(TOUCH_EVENTS)
2007 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
2008 if (defaultPrevented)
2012 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
2014 #if ENABLE(PAN_SCROLLING)
2015 m_autoscrollController->handleMouseReleaseEvent(platformMouseEvent);
2018 m_mousePressed = false;
2019 setLastKnownMousePosition(platformMouseEvent);
2023 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
2027 if (m_frameSetBeingResized)
2028 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, platformMouseEvent, false);
2030 // If an immediate action began or was completed using this series of mouse events, then we should send mouseup to
2031 // the DOM and return now so that we don't perform our own default behaviors.
2032 if (m_immediateActionStage == ImmediateActionStage::ActionCompleted || m_immediateActionStage == ImmediateActionStage::ActionUpdated || m_immediateActionStage == ImmediateActionStage::ActionCancelledAfterUpdate) {
2033 m_immediateActionStage = ImmediateActionStage::None;
2034 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), true, m_clickCount, platformMouseEvent, false);
2036 m_immediateActionStage = ImmediateActionStage::None;
2038 if (m_lastScrollbarUnderMouse) {
2040 m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
2041 bool cancelable = true;
2042 bool setUnder = false;
2043 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
2046 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
2047 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
2048 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
2049 if (m_eventHandlerWillResetCapturingMouseEventsElement)
2050 m_capturingMouseEventsElement = nullptr;
2051 if (subframe && passMouseReleaseEventToSubframe(mouseEvent, subframe))
2054 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
2056 bool contextMenuEvent = platformMouseEvent.button() == RightButton;
2058 Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode());
2059 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true);
2061 if (m_resizeLayer) {
2062 m_resizeLayer->setInResizeMode(false);
2063 m_resizeLayer = nullptr;
2066 bool swallowMouseReleaseEvent = false;
2067 if (!swallowMouseUpEvent)
2068 swallowMouseReleaseEvent = handleMouseReleaseEvent(mouseEvent);
2072 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2075 #if ENABLE(MOUSE_FORCE_EVENTS)
2076 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& event)
2078 Ref<Frame> protectedFrame(m_frame);
2079 RefPtr<FrameView> protector(m_frame.view());
2081 setLastKnownMousePosition(event);
2083 HitTestRequest::HitTestRequestType hitType = HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::Active;
2085 HitTestRequest request(hitType);
2086 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2088 bool swallowedEvent = !dispatchMouseEvent(eventNames().webkitmouseforcechangedEvent, mouseEvent.targetNode(), false, 0, event, false);
2089 if (event.type() == PlatformEvent::MouseForceDown)
2090 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforcedownEvent, mouseEvent.targetNode(), false, 0, event, false);
2091 if (event.type() == PlatformEvent::MouseForceUp)
2092 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforceupEvent, mouseEvent.targetNode(), false, 0, event, false);
2094 return swallowedEvent;
2097 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& )
2101 #endif // #if ENABLE(MOUSE_FORCE_EVENTS)
2103 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& platformMouseEvent)
2105 // If the event was a middle click, attempt to copy global selection in after
2106 // the newly set caret position.
2108 // This code is called from either the mouse up or mouse down handling. There
2109 // is some debate about when the global selection is pasted:
2110 // xterm: pastes on up.
2111 // GTK: pastes on down.
2112 // Qt: pastes on up.
2113 // Firefox: pastes on up.
2114 // Chromium: pastes on up.
2116 // There is something of a webcompat angle to this well, as highlighted by
2117 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
2118 // down then the text is pasted just before the onclick handler runs and
2119 // clears the text box. So it's important this happens after the event
2120 // handlers have been fired.
2122 if (platformMouseEvent.type() != PlatformEvent::MousePressed)
2125 if (platformMouseEvent.type() != PlatformEvent::MouseReleased)
2129 if (!m_frame.page())
2131 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame();
2132 // Do not paste here if the focus was moved somewhere else.
2133 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection())
2134 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute();
2139 #if ENABLE(DRAG_SUPPORT)
2141 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2143 Ref<Frame> protectedFrame(m_frame);
2144 FrameView* view = m_frame.view();
2146 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2150 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2151 Ref<MouseEvent> me = MouseEvent::create(eventType,
2152 true, true, event.timestamp(), m_frame.document()->defaultView(),
2153 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2154 #if ENABLE(POINTER_LOCK)
2155 event.movementDelta().x(), event.movementDelta().y(),
2157 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2158 0, 0, event.force(), NoTap, dataTransfer);
2160 dragTarget.dispatchEvent(me);
2161 return me->defaultPrevented();
2164 static bool targetIsFrame(Node* target, Frame*& frame)
2166 if (!is<HTMLFrameElementBase>(target))
2169 frame = downcast<HTMLFrameElementBase>(*target).contentFrame();
2173 static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation)
2175 if (dragOperation == "copy")
2176 return DragOperationCopy;
2177 if (dragOperation == "move")
2178 return DragOperationMove;
2179 if (dragOperation == "link")
2180 return DragOperationLink;
2181 return DragOperationNone;
2184 static String convertDragOperationToDropZoneOperation(DragOperation operation)
2186 switch (operation) {
2187 case DragOperationCopy:
2188 return ASCIILiteral("copy");
2189 case DragOperationMove:
2190 return ASCIILiteral("move");
2191 case DragOperationLink:
2192 return ASCIILiteral("link");
2194 return ASCIILiteral("copy");
2198 static bool hasDropZoneType(DataTransfer& dataTransfer, const String& keyword)
2200 if (keyword.startsWith("file:"))
2201 return dataTransfer.hasFileOfType(keyword.substring(5));
2203 if (keyword.startsWith("string:"))
2204 return dataTransfer.hasStringOfType(keyword.substring(7));
2209 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
2212 Element* element = is<Element>(*target) ? downcast<Element>(target) : target->parentElement();
2213 for (; element; element = element->parentElement()) {
2214 SpaceSplitString keywords(element->attributeWithoutSynchronization(webkitdropzoneAttr), true);
2215 bool matched = false;
2216 DragOperation dragOperation = DragOperationNone;
2217 for (unsigned i = 0, size = keywords.size(); i < size; ++i) {
2218 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2219 if (op != DragOperationNone) {
2220 if (dragOperation == DragOperationNone)
2223 matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string());
2224 if (matched && dragOperation != DragOperationNone)
2228 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2235 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2237 Ref<Frame> protectedFrame(m_frame);
2239 bool accept = false;
2241 if (!m_frame.view())
2244 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
2245 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2247 RefPtr<Element> newTarget;
2248 if (Node* targetNode = mouseEvent.targetNode()) {
2249 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch)
2250 if (!is<Element>(*targetNode))
2251 newTarget = targetNode->parentOrShadowHostElement();
2253 newTarget = downcast<Element>(targetNode);
2256 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2258 if (m_dragTarget != newTarget) {
2259 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2260 // it is sometimes incorrect when dragging within subframes, as seen with
2261 // LayoutTests/fast/events/drag-in-frames.html.
2263 // 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>.
2265 if (targetIsFrame(newTarget.get(), targetFrame)) {
2267 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2268 } else if (newTarget) {
2269 // 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.
2270 if (dragState().source && dragState().shouldDispatchEvents) {
2271 // for now we don't care if event handler cancels default behavior, since there is none
2272 dispatchDragSrcEvent(eventNames().dragEvent, event);
2274 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, dataTransfer);
2276 accept = findDropZone(newTarget.get(), dataTransfer);
2279 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2281 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2282 } else if (m_dragTarget)
2283 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2286 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2287 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2288 m_shouldOnlyFireDragOverEvent = true;
2292 if (targetIsFrame(newTarget.get(), targetFrame)) {
2294 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2295 } else if (newTarget) {
2296 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2297 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
2298 // for now we don't care if event handler cancels default behavior, since there is none
2299 dispatchDragSrcEvent(eventNames().dragEvent, event);
2301 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, dataTransfer);
2303 accept = findDropZone(newTarget.get(), dataTransfer);
2304 m_shouldOnlyFireDragOverEvent = false;
2307 m_dragTarget = WTFMove(newTarget);
2311 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2313 Ref<Frame> protectedFrame(m_frame);
2316 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2318 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
2319 } else if (m_dragTarget) {
2320 if (dragState().source && dragState().shouldDispatchEvents)
2321 dispatchDragSrcEvent(eventNames().dragEvent, event);
2322 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2327 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2329 Ref<Frame> protectedFrame(m_frame);
2332 bool preventedDefault = false;
2333 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2335 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
2336 } else if (m_dragTarget)
2337 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer);
2339 return preventedDefault;
2342 void EventHandler::clearDragState()
2344 stopAutoscrollTimer();
2345 m_dragTarget = nullptr;
2346 m_capturingMouseEventsElement = nullptr;
2347 m_shouldOnlyFireDragOverEvent = false;
2349 m_sendingEventToSubview = false;
2352 #endif // ENABLE(DRAG_SUPPORT)
2354 void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element)
2356 m_capturingMouseEventsElement = element;
2357 m_eventHandlerWillResetCapturingMouseEventsElement = false;
2360 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent)
2362 Ref<Frame> protectedFrame(m_frame);
2363 ASSERT(m_frame.document());
2364 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mouseEvent.position()), mouseEvent);
2367 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
2372 for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
2373 for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
2374 if (currObj1 == currObj2)
2382 static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName)
2384 for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) {
2385 if (curr->hasCapturingEventListeners(eventName))
2391 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& platformMouseEvent, bool fireMouseOverOut)
2393 Ref<Frame> protectedFrame(m_frame);
2394 Element* targetElement = nullptr;
2396 // If we're capturing, we always go right to that element.
2397 if (m_capturingMouseEventsElement)
2398 targetElement = m_capturingMouseEventsElement.get();
2399 else if (targetNode) {
2400 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646>
2401 while (targetNode && !is<Element>(*targetNode))
2402 targetNode = targetNode->parentInComposedTree();
2403 targetElement = downcast<Element>(targetNode);
2406 m_elementUnderMouse = targetElement;
2408 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2409 if (fireMouseOverOut) {
2410 auto scrollableAreaForLastNode = enclosingScrollableArea(m_lastElementUnderMouse.get());
2411 auto scrollableAreaForNodeUnderMouse = enclosingScrollableArea(m_elementUnderMouse.get());
2412 Page* page = m_frame.page();
2414 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) {
2415 // The mouse has moved between frames.
2416 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2417 if (FrameView* frameView = frame->view())
2418 frameView->mouseExitedContentArea();
2420 } else if (page && (scrollableAreaForLastNode && (!scrollableAreaForNodeUnderMouse || scrollableAreaForNodeUnderMouse != scrollableAreaForLastNode))) {
2421 // The mouse has moved between layers.
2422 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2423 if (FrameView* frameView = frame->view()) {
2424 if (frameView->containsScrollableArea(scrollableAreaForLastNode))
2425 scrollableAreaForLastNode->mouseExitedContentArea();
2430 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) {
2431 // The mouse has moved between frames.
2432 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2433 if (FrameView* frameView = frame->view())
2434 frameView->mouseEnteredContentArea();
2436 } else if (page && (scrollableAreaForNodeUnderMouse && (!scrollableAreaForLastNode || scrollableAreaForNodeUnderMouse != scrollableAreaForLastNode))) {
2437 // The mouse has moved between layers.
2438 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2439 if (FrameView* frameView = frame->view()) {
2440 if (frameView->containsScrollableArea(scrollableAreaForNodeUnderMouse))
2441 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
2446 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) {
2447 m_lastElementUnderMouse = nullptr;
2448 m_lastScrollbarUnderMouse = nullptr;
2451 if (m_lastElementUnderMouse != m_elementUnderMouse) {
2452 // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor
2453 // or a normal eventhandler on the element itself (they don't bubble).
2454 // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks.
2455 bool hasCapturingMouseEnterListener = hierarchyHasCapturingEventListeners(m_elementUnderMouse.get(), eventNames().mouseenterEvent);
2456 bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent);
2458 RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr;
2459 RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr;
2460 RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer);
2462 Vector<Ref<Element>, 32> leftElementsChain;
2463 if (oldHoverRenderer) {
2464 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) {
2465 if (Element* element = curr->element())
2466 leftElementsChain.append(*element);
2469 // If the old hovered element is not null but it's renderer is, it was probably detached.
2470 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied.
2471 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement())
2472 leftElementsChain.append(*element);
2475 Vector<Ref<Element>, 32> enteredElementsChain;
2476 const Element* ancestorElement = ancestor ? ancestor->element() : nullptr;
2477 for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) {
2478 if (Element *element = curr->element()) {
2479 if (element == ancestorElement)
2481 enteredElementsChain.append(*element);
2485 // Send mouseout event to the old node.
2486 if (m_lastElementUnderMouse)
2487 m_lastElementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
2489 // Send mouseleave to the node hierarchy no longer under the mouse.
2490 for (auto& chain : leftElementsChain) {
2491 if (hasCapturingMouseLeaveListener || chain->hasEventListeners(eventNames().mouseleaveEvent))
2492 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseleaveEvent, 0, m_elementUnderMouse.get());
2495 // Send mouseover event to the new node.
2496 if (m_elementUnderMouse)
2497 m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
2499 // Send mouseleave event to the nodes hierarchy under the mouse.
2500 for (auto& chain : enteredElementsChain) {
2501 if (hasCapturingMouseEnterListener || chain->hasEventListeners(eventNames().mouseenterEvent))
2502 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseenterEvent, 0, m_lastElementUnderMouse.get());
2505 m_lastElementUnderMouse = m_elementUnderMouse;
2509 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
2511 Ref<Frame> protectedFrame(m_frame);
2513 if (auto* view = m_frame.view())
2514 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2516 updateMouseEventTargetNode(targetNode, platformMouseEvent, setUnder);
2518 if (m_elementUnderMouse && !m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventType, clickCount))
2521 if (eventType != eventNames().mousedownEvent)
2524 // If clicking on a frame scrollbar, do not make any change to which element is focused.
2525 auto* view = m_frame.view();
2526 if (view && view->scrollbarAtPoint(platformMouseEvent.position()))
2529 // The layout needs to be up to date to determine if an element is focusable.
2530 m_frame.document()->updateLayoutIgnorePendingStylesheets();
2532 // Remove focus from the currently focused element when a link or button is clicked.
2533 // This is expected by some sites that rely on change event handlers running
2534 // from form fields before the button click is processed, behavior that was inherited
2535 // from the user interface of Windows, where pushing a button moves focus to the button.
2537 // Walk up the DOM tree to search for an element to focus.
2539 for (element = m_elementUnderMouse.get(); element; element = element->parentOrShadowHostElement()) {
2540 if (element->isMouseFocusable())
2544 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus an
2545 // element on mouse down if it's selected and inside a focused element. It will be
2546 // focused if the user does a mouseup over it, however, because the mouseup
2547 // will set a selection inside it, which will also set the focused element.
2548 if (element && m_frame.selection().isRange()) {
2549 if (auto range = m_frame.selection().toNormalizedRange()) {
2550 auto result = range->compareNode(*element);
2551 if (!result.hasException() && result.releaseReturnValue() == Range::NODE_INSIDE && element->isDescendantOf(m_frame.document()->focusedElement()))
2556 // Only change the focus when clicking scrollbars if it can be transferred to a mouse focusable node.
2557 if (!element && isInsideScrollbar(platformMouseEvent.position()))
2560 // If focus shift is blocked, we eat the event.
2561 auto* page = m_frame.page();
2562 if (page && !page->focusController().setFocusedElement(element, &m_frame))
2568 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2570 if (RenderView* renderView = m_frame.contentRenderer()) {
2571 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
2572 HitTestResult result(windowPoint);
2573 renderView->hitTest(request, result);
2574 return result.scrollbar();
2582 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2591 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, WeakPtr<ScrollableArea>&, bool&)
2595 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event)
2597 m_frame.mainFrame().wheelEventDeltaFilter()->updateFromDelta(FloatSize(event.deltaX(), event.deltaY()));
2600 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, const WeakPtr<ScrollableArea>&)
2602 Ref<Frame> protectedFrame(m_frame);
2604 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2605 FrameView* view = m_frame.view();
2607 bool didHandleEvent = view ? view->wheelEvent(event) : false;
2608 m_isHandlingWheelEvent = false;
2609 return didHandleEvent;
2612 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode*)
2617 void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, const WeakPtr<ScrollableArea>&)
2621 IntPoint EventHandler::effectiveMousePositionForSelectionAutoscroll() const
2623 return m_lastKnownMousePosition;
2626 void EventHandler::clearOrScheduleClearingLatchedStateIfNeeded(const PlatformWheelEvent&)
2628 clearLatchedState();
2632 Widget* EventHandler::widgetForEventTarget(Element* eventTarget)
2637 auto* target = eventTarget->renderer();
2638 if (!is<RenderWidget>(target))
2641 return downcast<RenderWidget>(*target).widget();
2644 static WeakPtr<Widget> widgetForElement(const Element& element)
2646 auto target = element.renderer();
2647 if (!is<RenderWidget>(target) || !downcast<RenderWidget>(*target).widget())
2650 return downcast<RenderWidget>(*target).widget()->createWeakPtr();
2653 bool EventHandler::completeWidgetWheelEvent(const PlatformWheelEvent& event, const WeakPtr<Widget>& widget, const WeakPtr<ScrollableArea>& scrollableArea, ContainerNode* scrollableContainer)
2655 m_isHandlingWheelEvent = false;
2657 // We do another check on the widget because the event handler can run JS which results in the frame getting destroyed.
2662 scrollableArea->setScrolledProgrammatically(false);
2664 platformNotifyIfEndGesture(event, scrollableArea);
2666 if (!widget->platformWidget())
2669 return platformCompletePlatformWidgetWheelEvent(event, *widget.get(), scrollableContainer);
2672 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
2674 RenderView* renderView = m_frame.contentRenderer();
2678 Ref<Frame> protectedFrame(m_frame);
2679 RefPtr<FrameView> protector(m_frame.view());
2681 FrameView* view = m_frame.view();
2685 m_isHandlingWheelEvent = true;
2686 setFrameWasScrolledByUser();
2688 HitTestRequest request;
2689 HitTestResult result(view->windowToContents(event.position()));
2690 renderView->hitTest(request, result);
2692 RefPtr<Element> element = result.innerElement();
2693 RefPtr<ContainerNode> scrollableContainer;
2694 WeakPtr<ScrollableArea> scrollableArea;
2695 bool isOverWidget = result.isOverWidget();
2696 platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget);
2699 if (event.phase() == PlatformWheelEventPhaseNone && event.momentumPhase() == PlatformWheelEventPhaseNone)
2700 m_frame.mainFrame().resetLatchingState();
2703 // FIXME: It should not be necessary to do this mutation here.
2704 // Instead, the handlers should know convert vertical scrolls appropriately.
2705 PlatformWheelEvent adjustedEvent = event;
2706 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, event))
2707 adjustedEvent = event.copyTurningVerticalTicksIntoHorizontalTicks();
2709 platformRecordWheelEvent(adjustedEvent);
2713 if (WeakPtr<Widget> widget = widgetForElement(*element)) {
2714 if (widgetDidHandleWheelEvent(event, *widget.get()))
2715 return completeWidgetWheelEvent(adjustedEvent, widget, scrollableArea, scrollableContainer.get());
2719 if (!element->dispatchWheelEvent(adjustedEvent)) {
2720 m_isHandlingWheelEvent = false;
2721 if (scrollableArea && scrollableArea->isScrolledProgrammatically()) {
2722 // Web developer is controlling scrolling, so don't attempt to latch.
2723 clearLatchedState();
2724 scrollableArea->setScrolledProgrammatically(false);
2727 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2733 scrollableArea->setScrolledProgrammatically(false);
2735 bool handledEvent = platformCompleteWheelEvent(adjustedEvent, scrollableContainer.get(), scrollableArea);
2736 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2737 return handledEvent;
2740 void EventHandler::clearLatchedState()
2743 m_frame.mainFrame().resetLatchingState();
2745 if (auto filter = m_frame.mainFrame().wheelEventDeltaFilter())
2746 filter->endFilteringDeltas();
2749 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent& wheelEvent)
2754 Ref<Frame> protectedFrame(m_frame);
2756 FloatSize filteredPlatformDelta(wheelEvent.deltaX(), wheelEvent.deltaY());
2757 if (const PlatformWheelEvent* platformWheelEvent = wheelEvent.wheelEvent()) {
2758 filteredPlatformDelta.setWidth(platformWheelEvent->deltaX());
2759 filteredPlatformDelta.setHeight(platformWheelEvent->deltaY());
2763 ScrollLatchingState* latchedState = m_frame.mainFrame().latchingState();
2764 Element* stopElement = latchedState ? latchedState->previousWheelScrolledElement() : nullptr;
2766 if (m_frame.mainFrame().wheelEventDeltaFilter()->isFilteringDeltas())
2767 filteredPlatformDelta = m_frame.mainFrame().wheelEventDeltaFilter()->filteredDelta();
2769 Element* stopElement = nullptr;
2773 if (handleWheelEventInAppropriateEnclosingBox(startNode, wheelEvent, &stopElement, filteredPlatformDelta))
2774 wheelEvent.setDefaultHandled();
2777 if (latchedState && !latchedState->wheelEventElement())
2778 latchedState->setPreviousWheelScrolledElement(stopElement);
2782 #if ENABLE(CONTEXT_MENUS)
2783 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2785 Ref<Frame> protectedFrame(m_frame);
2787 Document* doc = m_frame.document();
2788 FrameView* view = m_frame.view();
2792 // Clear mouse press state to avoid initiating a drag while context menu is up.
2793 m_mousePressed = false;
2795 LayoutPoint viewportPos = view->windowToContents(event.position());
2796 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
2797 MouseEventWithHitTestResults mouseEvent = doc->prepareMouseEvent(request, viewportPos, event);
2799 // Do not show context menus when clicking on scrollbars.
2800 if (mouseEvent.scrollbar() || view->scrollbarAtPoint(event.position()))
2803 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick()
2804 && !m_frame.selection().contains(viewportPos)
2805 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2806 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2807 // available for text selections. But only if we're above text.
2808 && (m_frame.selection().selection().isContentEditable() || (mouseEvent.targetNode() && mouseEvent.targetNode()->isTextNode()))) {
2809 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2810 selectClosestContextualWordOrLinkFromMouseEvent(mouseEvent);
2813 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mouseEvent.targetNode(), true, 0, event, false);
2815 return swallowEvent;
2818 bool EventHandler::sendContextMenuEventForKey()
2820 Ref<Frame> protectedFrame(m_frame);
2822 FrameView* view = m_frame.view();
2826 Document* doc = m_frame.document();
2830 // Clear mouse press state to avoid initiating a drag while context menu is up.
2831 m_mousePressed = false;
2833 static const int kContextMenuMargin = 1;
2836 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2838 int rightAligned = 0;
2842 Element* focusedElement = doc->focusedElement();
2843 const VisibleSelection& selection = m_frame.selection().selection();
2844 Position start = selection.start();
2846 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2847 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2848 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get());
2850 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2851 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2852 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2853 location = IntPoint(x, y);
2854 } else if (focusedElement) {
2855 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2858 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2859 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2861 location = IntPoint(
2862 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2863 kContextMenuMargin);
2866 m_frame.view()->setCursor(pointerCursor());
2868 IntPoint position = view->contentsToRootView(location);
2869 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2871 Node* targetNode = doc->focusedElement();
2875 // Use the focused node as the target for hover and active.
2876 HitTestResult result(position);
2877 result.setInnerNode(targetNode);
2878 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.innerElement());
2880 // The contextmenu event is a mouse event even when invoked using the keyboard.
2881 // This is required for web compatibility.
2884 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2886 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2889 PlatformMouseEvent platformMouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime(), ForceAtClick, NoTap);
2891 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, platformMouseEvent, false);
2893 #endif // ENABLE(CONTEXT_MENUS)
2895 void EventHandler::scheduleHoverStateUpdate()
2897 if (!m_hoverTimer.isActive())
2898 m_hoverTimer.startOneShot(0);
2901 #if ENABLE(CURSOR_SUPPORT)
2902 void EventHandler::scheduleCursorUpdate()
2904 if (!m_cursorUpdateTimer.isActive())
2905 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2909 void EventHandler::dispatchFakeMouseMoveEventSoon()
2911 #if !ENABLE(IOS_TOUCH_EVENTS)
2915 if (m_mousePositionIsUnknown)
2918 if (Page* page = m_frame.page()) {
2919 if (!page->chrome().client().shouldDispatchFakeMouseMoveEvents())
2923 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2924 // reschedule the timer and use a longer time. This will cause the content
2925 // to receive these moves only after the user is done scrolling, reducing
2926 // pauses during the scroll.
2927 if (m_fakeMouseMoveEventTimer.isActive())
2928 m_fakeMouseMoveEventTimer.stop();
2929 m_fakeMouseMoveEventTimer.startOneShot(m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold ? fakeMouseMoveLongInterval : fakeMouseMoveShortInterval);
2933 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2935 #if ENABLE(IOS_TOUCH_EVENTS)
2938 FrameView* view = m_frame.view();
2942 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2945 dispatchFakeMouseMoveEventSoon();
2949 #if !ENABLE(IOS_TOUCH_EVENTS)
2950 void EventHandler::cancelFakeMouseMoveEvent()
2952 m_fakeMouseMoveEventTimer.stop();
2955 void EventHandler::fakeMouseMoveEventTimerFired()
2957 ASSERT(!m_mousePressed);
2959 FrameView* view = m_frame.view();
2963 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive())
2970 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2971 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime(), 0, NoTap);
2972 mouseMoved(fakeMouseMoveEvent);
2974 #endif // !ENABLE(IOS_TOUCH_EVENTS)
2976 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2978 m_frameSetBeingResized = frameSet;
2981 void EventHandler::resizeLayerDestroyed()
2983 ASSERT(m_resizeLayer);
2984 m_resizeLayer = nullptr;
2987 void EventHandler::hoverTimerFired()
2989 m_hoverTimer.stop();
2991 ASSERT(m_frame.document());
2993 Ref<Frame> protectedFrame(m_frame);
2995 if (RenderView* renderView = m_frame.contentRenderer()) {
2996 if (FrameView* view = m_frame.view()) {
2997 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
2998 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2999 renderView->hitTest(request, result);
3000 m_frame.document()->updateHoverActiveState(request, result.innerElement());
3005 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& event)
3007 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3008 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3009 // lower case variants are present in a document, the correct element is matched based on Shift key state.
3010 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3011 ASSERT(!accessKeyModifiers().contains(PlatformEvent::Modifier::ShiftKey));
3013 if ((event.modifiers() - PlatformEvent::Modifier::ShiftKey) != accessKeyModifiers())
3015 Element* element = m_frame.document()->getElementByAccessKey(event.unmodifiedText());
3018 element->accessKeyAction(false);
3023 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
3029 #if ENABLE(FULLSCREEN_API)
3030 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
3032 Document* document = m_frame.document();
3033 if (document->webkitFullScreenKeyboardInputAllowed())
3036 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3037 if (keyEvent.text().length() != 1)
3039 UChar character = keyEvent.text()[0];
3040 return character == ' ';
3043 int keyCode = keyEvent.windowsVirtualKeyCode();
3044 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3045 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3046 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3047 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3051 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3053 Ref<Frame> protectedFrame(m_frame);
3054 RefPtr<FrameView> protector(m_frame.view());
3056 LOG(Editing, "EventHandler %p keyEvent (text %s keyIdentifier %s)", this, initialKeyEvent.text().utf8().data(), initialKeyEvent.keyIdentifier().utf8().data());
3058 #if ENABLE(POINTER_LOCK)
3059 if (initialKeyEvent.type() == PlatformEvent::KeyDown && initialKeyEvent.windowsVirtualKeyCode() == VK_ESCAPE && m_frame.page()->pointerLockController().element()) {
3060 m_frame.page()->pointerLockController().requestPointerUnlock();
3065 #if ENABLE(FULLSCREEN_API)
3066 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
3070 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL) {
3071 if (auto* element = m_frame.document()->focusedElement()) {
3072 if (is<HTMLInputElement>(*element))
3073 downcast<HTMLInputElement>(*element).capsLockStateMayHaveChanged();
3077 #if ENABLE(PAN_SCROLLING)
3078 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) {
3079 // If a key is pressed while the panScroll is in progress then we want to stop
3080 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3081 stopAutoscrollTimer();
3083 // If we were in panscroll mode, we swallow the key event
3088 // Check for cases where we are too early for events -- possible unmatched key up
3089 // from pressing return in the location bar.
3090 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document());
3094 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
3095 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3097 if (FrameView* view = m_frame.view())
3098 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3100 // FIXME (bug 68185): this call should be made at another abstraction layer
3101 m_frame.loader().resetMultipleFormSubmissionProtection();
3103 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3104 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3105 // with access keys. Then we dispatch keydown, but suppress its default handling.
3106 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3107 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3108 bool matchedAnAccessKey = false;
3109 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3110 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3112 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3113 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3114 return !element->dispatchKeyEvent(initialKeyEvent);
3116 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3118 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3119 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3120 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3121 Ref<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3122 if (matchedAnAccessKey)
3123 keydown->setDefaultPrevented(true);
3124 keydown->setTarget(element);
3126 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3127 element->dispatchEvent(keydown);
3128 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3129 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3130 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3133 // Run input method in advance of DOM event handling. This may result in the IM
3134 // modifying the page prior the keydown event, but this behaviour is necessary
3135 // in order to match IE:
3136 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3137 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3138 m_frame.editor().handleInputMethodKeydown(keydown.get());
3140 bool handledByInputMethod = keydown->defaultHandled();
3142 if (handledByInputMethod) {
3143 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3144 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3145 keydown->setTarget(element);
3146 keydown->setDefaultHandled();
3149 if (accessibilityPreventsEventPropogation(keydown))
3150 keydown->stopPropagation();
3152 element->dispatchEvent(keydown);
3153 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3154 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3155 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3156 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3157 return keydownResult;
3159 // Focus may have changed during keydown handling, so refetch element.
3160 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element.
3161 if (!keydownResult) {
3162 element = eventTargetElementForDocument(m_frame.document());
3167 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3168 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3169 if (keyPressEvent.text().isEmpty())
3170 return keydownResult;
3171 Ref<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView());
3172 keypress->setTarget(element);
3174 keypress->setDefaultPrevented(true);
3176 keypress->keypressCommands() = keydown->keypressCommands();
3178 element->dispatchEvent(keypress);
3180 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3183 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3185 static NeverDestroyed<AtomicString> Down("Down", AtomicString::ConstructFromLiteral);
3186 static NeverDestroyed<AtomicString> Up("Up", AtomicString::ConstructFromLiteral);
3187 static NeverDestroyed<AtomicString> Left("Left", AtomicString::ConstructFromLiteral);
3188 static NeverDestroyed<AtomicString> Right("Right", AtomicString::ConstructFromLiteral);
3190 FocusDirection retVal = FocusDirectionNone;
3192 if (keyIdentifier == Down)
3193 retVal = FocusDirectionDown;
3194 else if (keyIdentifier == Up)
3195 retVal = FocusDirectionUp;
3196 else if (keyIdentifier == Left)
3197 retVal = FocusDirectionLeft;
3198 else if (keyIdentifier == Right)
3199 retVal = FocusDirectionRight;
3204 static void setInitialKeyboardSelection(Frame& frame, SelectionDirection direction)
3206 Document* document = frame.document();
3210 FrameSelection& selection = frame.selection();
3212 if (!selection.isNone())
3215 Element* focusedElement = document->focusedElement();
3216 VisiblePosition visiblePosition;
3218 switch (direction) {
3219 case DirectionBackward:
3222 visiblePosition = VisiblePosition(positionBeforeNode(focusedElement));
3224 visiblePosition = endOfDocument(document);
3226 case DirectionForward:
3227 case DirectionRight:
3229 visiblePosition = VisiblePosition(positionAfterNode(focusedElement));
3231 visiblePosition = startOfDocument(document);
3235 AXTextStateChangeIntent intent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, false });
3236 selection.setSelection(visiblePosition, FrameSelection::defaultSetSelectionOptions(UserTriggered), intent);
3239 static void handleKeyboardSelectionMovement(Frame& frame, KeyboardEvent& event)
3241 FrameSelection& selection = frame.selection();
3243 bool isCommanded = event.getModifierState("Meta");
3244 bool isOptioned = event.getModifierState("Alt");
3245 bool isSelection = !selection.isNone();
3247 FrameSelection::EAlteration alternation = event.getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3248 SelectionDirection direction = DirectionForward;
3249 TextGranularity granularity = CharacterGranularity;
3251 switch (focusDirectionForKey(event.keyIdentifier())) {
3252 case FocusDirectionNone:
3254 case FocusDirectionForward:
3255 case FocusDirectionBackward:
3256 ASSERT_NOT_REACHED();
3258 case FocusDirectionUp:
3259 direction = DirectionBackward;
3260 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3262 case FocusDirectionDown:
3263 direction = DirectionForward;
3264 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3266 case FocusDirectionLeft:
3267 direction = DirectionLeft;
3268 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3270 case FocusDirectionRight:
3271 direction = DirectionRight;
3272 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3277 selection.modify(alternation, direction, granularity, UserTriggered);
3279 setInitialKeyboardSelection(frame, direction);
3281 event.setDefaultHandled();
3284 void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent& event)
3286 if (event.type() == eventNames().keydownEvent) {
3287 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3288 handleKeyboardSelectionMovement(m_frame, event);
3292 bool EventHandler::accessibilityPreventsEventPropogation(KeyboardEvent& event)
3295 if (!AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3298 if (!m_frame.settings().preventKeyboardDOMEventDispatch())
3301 // Check for key events that are relevant to accessibility: tab and arrows keys that change focus
3302 if (event.keyIdentifier() == "U+0009")
3304 FocusDirection direction = focusDirectionForKey(event.keyIdentifier());
3305 if (direction != FocusDirectionNone)
3308 UNUSED_PARAM(event);
3313 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent& event)
3315 Ref<Frame> protectedFrame(m_frame);
3317 if (event.type() == eventNames().keydownEvent) {
3318 m_frame.editor().handleKeyboardEvent(event);
3319 if (event.defaultHandled())
3321 if (event.keyIdentifier() == "U+0009")
3322 defaultTabEventHandler(event);
3323 else if (event.keyIdentifier() == "U+0008")
3324 defaultBackspaceEventHandler(event);
3326 FocusDirection direction = focusDirectionForKey(event.keyIdentifier());
3327 if (direction != FocusDirectionNone)
3328 defaultArrowEventHandler(direction, event);
3331 handleKeyboardSelectionMovementForAccessibility(event);
3333 if (event.type() == eventNames().keypressEvent) {
3334 m_frame.editor().handleKeyboardEvent(event);
3335 if (event.defaultHandled())
3337 if (event.charCode() == ' ')
3338 defaultSpaceEventHandler(event);
3342 #if ENABLE(DRAG_SUPPORT)
3343 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3345 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3346 return dragHysteresisExceeded(dragViewportLocation);
3349 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3351 int threshold = GeneralDragHysteresis;
3352 switch (dragState().type) {
3353 case DragSourceActionSelection:
3354 threshold = TextDragHysteresis;
3356 case DragSourceActionImage:
3357 #if ENABLE(ATTACHMENT_ELEMENT)
3358 case DragSourceActionAttachment:
3360 threshold = ImageDragHysteresis;
3362 case DragSourceActionLink:
3363 threshold = LinkDragHysteresis;
3365 case DragSourceActionDHTML:
3367 case DragSourceActionNone:
3368 case DragSourceActionAny:
3369 ASSERT_NOT_REACHED();
3372 return mouseMovementExceedsThreshold(dragViewportLocation, threshold);
3375 void EventHandler::freeDataTransfer()
3377 if (!dragState().dataTransfer)
3379 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb);
3380 dragState().dataTransfer = nullptr;
3383 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3385 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3386 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
3387 prepareMouseEvent(request, event);
3389 if (dragState().source && dragState().shouldDispatchEvents) {
3390 dragState().dataTransfer->setDestinationOperation(operation);
3391 // For now we don't care if event handler cancels default behavior, since there is no default behavior.
3392 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3395 dragState().source = nullptr;
3396 // In case the drag was ended due to an escape key press we need to ensure
3397 // that consecutive mousemove events don't reinitiate the drag and drop.
3398 m_mouseDownMayStartDrag = false;
3401 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3403 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element.
3404 if (dragState().source && !dragState().source->inDocument())
3405 dragState().source = rootEditableElement;
3408 // Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
3409 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3411 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
3414 static bool ExactlyOneBitSet(DragSourceAction n)
3416 return n && !(n & (n - 1));
3419 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3421 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3422 // If we allowed the other side of the bridge to handle a drag
3423 // last time, then m_mousePressed might still be set. So we
3424 // clear it now to make sure the next move after a drag
3425 // doesn't look like a drag.
3426 m_mousePressed = false;
3430 Ref<Frame> protectedFrame(m_frame);
3432 if (eventLoopHandleMouseDragged(event))
3435 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3437 if (m_mouseDownMayStartDrag && !dragState().source) {
3438 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML);
3440 // try to find an element that wants to be dragged
3441 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowUserAgentShadowContent);
3442 HitTestResult result(m_mouseDownPos);
3443 m_frame.contentRenderer()->hitTest(request, result);
3445 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
3447 if (!dragState().source)
3448 m_mouseDownMayStartDrag = false; // no element is draggable
3450 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection);
3453 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3454 // or else we bail on the dragging stuff and allow selection to occur
3455 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3456 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3457 if ((dragState().type & DragSourceActionImage)) {
3458 // ... unless the mouse is over an image, then we start dragging just the image
3459 dragState().type = DragSourceActionImage;
3460 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) {
3461 // ... but only bail if we're not over an unselectable element.
3462 m_mouseDownMayStartDrag = false;
3463 dragState().source = nullptr;
3464 // ... but if this was the first click in the window, we don't even want to start selection
3465 if (eventActivatedView(event.event()))
3466 m_mouseDownMayStartSelect = false;
3468 // Prevent the following case from occuring:
3469 // 1. User starts a drag immediately after mouse down over an unselectable element.
3470 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag.
3471 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet.
3472 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag.
3473 m_dragMayStartSelectionInstead = false;
3477 if (!m_mouseDownMayStartDrag)
3478 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3480 if (!ExactlyOneBitSet(dragState().type)) {
3481 ASSERT((dragState().type & DragSourceActionSelection));
3482 #if ENABLE(ATTACHMENT_ELEMENT)
3483 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3484 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3485 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionAttachment
3486 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3488 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3489 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3490 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3492 dragState().type = DragSourceActionSelection;
3495 // We are starting a text/image/url drag, so the cursor should be an arrow
3496 if (FrameView* view = m_frame.view()) {
3497 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3498 view->setCursor(pointerCursor());
3501 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3504 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3507 DragOperation srcOp = DragOperationNone;
3509 // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old dataTransfer gets numbed.
3512 dragState().dataTransfer = createDraggingDataTransfer();
3514 if (dragState().shouldDispatchEvents) {
3515 // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset.
3516 if (dragState().type == DragSourceActionDHTML) {
3517 if (RenderObject* renderer = dragState().source->renderer()) {
3518 // FIXME: This doesn't work correctly with transforms.
3519 FloatPoint absPos = renderer->localToAbsolute();
3520 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3521 dragState().dataTransfer->setDragImage(dragState().source.get(), delta.width(), delta.height());
3523 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3524 // the element in some way. In this case we just kill the drag.
3525 m_mouseDownMayStartDrag = false;
3530 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3531 && !m_frame.selection().selection().isInPasswordField();
3533 // Invalidate dataTransfer here against anymore pasteboard writing for security. The drag
3534 // image can still be changed as we drag, but not the pasteboard data.
3535 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::ImageWritable);
3537 if (m_mouseDownMayStartDrag) {
3538 // Gather values from DHTML element, if it set any.
3539 srcOp = dragState().dataTransfer->sourceOperation();
3541 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3542 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3543 // started the drag when that happens. So we have to assume it's started before we kick it off.
3544 dragState().dataTransfer->setDragHasStarted();
3548 if (m_mouseDownMayStartDrag) {
3549 Page* page = m_frame.page();
3550 m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3551 // In WebKit2 we could re-enter this code and start another drag.
3552 // On OS X this causes problems with the ownership of the pasteboard and the promised types.
3553 if (m_didStartDrag) {
3554 m_mouseDownMayStartDrag = false;
3557 if (dragState().source && dragState().shouldDispatchEvents) {
3558 // Drag was canned at the last minute. We owe dragSource a dragend event.
3559 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3560 m_mouseDownMayStartDrag = false;
3565 if (!m_mouseDownMayStartDrag) {
3566 // Something failed to start the drag, clean up.
3568 dragState().source = nullptr;
3571 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3574 #endif // ENABLE(DRAG_SUPPORT)
3576 bool EventHandler::mouseMovementExceedsThreshold(const FloatPoint& viewportLocation, int pointsThreshold) const
3578 FrameView* view = m_frame.view();
3581 IntPoint location = view->windowToContents(flooredIntPoint(viewportLocation));
3582 IntSize delta = location - m_mouseDownPos;
3584 return abs(delta.width()) >= pointsThreshold || abs(delta.height()) >= pointsThreshold;
3587 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3589 LOG(Editing, "EventHandler %p handleTextInputEvent (text %s)", this, text.utf8().data());
3591 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3592 // and avoid dispatching text input events from keydown default handlers.
3593 ASSERT(!is<KeyboardEvent>(underlyingEvent) || downcast<KeyboardEvent>(*underlyingEvent).type() == eventNames().keypressEvent);
3595 Ref<Frame> protectedFrame(m_frame);
3597 EventTarget* target;
3598 if (underlyingEvent)
3599 target = underlyingEvent->target();
3601 target = eventTargetElementForDocument(m_frame.document());
3605 if (FrameView* view = m_frame.view())
3606 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3608 Ref<TextEvent> event = TextEvent::create(m_frame.document()->domWindow(), text, inputType);
3609 event->setUnderlyingEvent(underlyingEvent);
3611 target->dispatchEvent(event);
3612 return event->defaultHandled();
3615 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3618 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3620 && event->keyIdentifier() == "U+0009";
3623 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3625 #if PLATFORM(COCOA) || PLATFORM(EFL)
3626 return EventHandler::isKeyboardOptionTab(event);
3628 UNUSED_PARAM(event);
3633 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3635 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3637 Page* page = m_frame.page();
3641 bool tabsToLinksClientCallResult = page->chrome().client().keyboardUIMode() & KeyboardAccessTabsToLinks;
3642 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3645 void EventHandler::defaultTextInputEventHandler(TextEvent& event)
3647 if (m_frame.editor().handleTextEvent(event))
3648 event.setDefaultHandled();
3652 void EventHandler::defaultSpaceEventHandler(KeyboardEvent& event)
3654 Ref<Frame> protectedFrame(m_frame);
3656 ASSERT(event.type() == eventNames().keypressEvent);
3658 if (event.ctrlKey() || event.metaKey() || event.altKey() || event.altGraphKey())
3661 ScrollLogicalDirection direction = event.shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3662 if (logicalScrollOverflow(direction, ScrollByPage)) {
3663 event.setDefaultHandled();
3667 FrameView* view = m_frame.view();
3671 if (view->logicalScroll(direction, ScrollByPage))
3672 event.setDefaultHandled();
3675 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent& event)
3677 ASSERT(event.type() == eventNames().keydownEvent);
3679 if (event.ctrlKey() || event.metaKey() || event.altKey() || event.altGraphKey())
3682 if (!m_frame.editor().behavior().shouldNavigateBackOnBackspace())
3685 Page* page = m_frame.page();
3689 if (!m_frame.settings().backspaceKeyNavigationEnabled())
3692 bool handledEvent = false;
3694 if (event.shiftKey())
3695 handledEvent = page->backForward().goForward();
3697 handledEvent = page->backForward().goBack();
3700 event.setDefaultHandled();
3704 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent& event)
3706 ASSERT(event.type() == eventNames().keydownEvent);
3708 if (event.ctrlKey() || event.metaKey() || event.altGraphKey() || event.shiftKey())
3711 Page* page = m_frame.page();
3715 if (!isSpatialNavigationEnabled(&m_frame))
3718 // Arrows and other possible directional navigation keys can be used in design
3720 if (m_frame.document()->inDesignMode())
3723 if (page->focusController().advanceFocus(focusDirection, event))
3724 event.setDefaultHandled();
3727 void EventHandler::defaultTabEventHandler(KeyboardEvent& event)
3729 Ref<Frame> protectedFrame(m_frame);
3731 ASSERT(event.type() == eventNames().keydownEvent);
3733 // We should only advance focus on tabs if no special modifier keys are held down.
3734 if (event.ctrlKey() || event.metaKey() || event.altGraphKey())
3737 Page* page = m_frame.page();
3740 if (!page->tabKeyCyclesThroughElements())
3743 FocusDirection focusDirection = event.shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3745 // Tabs can be used in design mode editing.
3746 if (m_frame.document()->inDesignMode())
3749 if (page->focusController().advanceFocus(focusDirection, event))
3750 event.setDefaultHandled();
3753 void EventHandler::sendScrollEvent()
3755 Ref<Frame> protectedFrame(m_frame);
3756 setFrameWasScrolledByUser();
3757 if (m_frame.view() && m_frame.document())
3758 m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document());
3761 void EventHandler::setFrameWasScrolledByUser()
3763 FrameView* v = m_frame.view();
3765 v->setWasScrolledByUser(true);
3768 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mouseEvent, Scrollbar* scrollbar)
3770 if (!scrollbar || !scrollbar->enabled())
3772 setFrameWasScrolledByUser();
3773 return scrollbar->mouseDown(mouseEvent.event());
3776 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3777 // last to scrollbar if setLast is true; else set last to nullptr.
3778 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3780 if (m_lastScrollbarUnderMouse != scrollbar) {
3781 // Send mouse exited to the old scrollbar.
3782 if (m_lastScrollbarUnderMouse)
3783 m_lastScrollbarUnderMouse->mouseExited();
3785 // Send mouse entered if we're setting a new scrollbar.
3786 if (scrollbar && setLast)
3787 scrollbar->mouseEntered();
3789 if (setLast && scrollbar)
3790 m_lastScrollbarUnderMouse = scrollbar->createWeakPtr();
3792 m_lastScrollbarUnderMouse = nullptr;
3796 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
3797 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3800 case PlatformTouchPoint::TouchReleased:
3801 return eventNames().touchendEvent;
3802 case PlatformTouchPoint::TouchCancelled:
3803 return eventNames().touchcancelEvent;
3804 case PlatformTouchPoint::TouchPressed:
3805 return eventNames().touchstartEvent;
3806 case PlatformTouchPoint::TouchMoved:
3807 return eventNames().touchmoveEvent;
3808 case PlatformTouchPoint::TouchStationary:
3809 // TouchStationary state is not converted to touch events, so fall through to assert.
3811 ASSERT_NOT_REACHED();
3816 static HitTestResult hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3818 HitTestResult result(point);
3820 if (!frame || !frame->contentRenderer())
3823 if (frame->view()) {
3824 IntRect rect = frame->view()->visibleContentRect();
3825 if (!rect.contains(roundedIntPoint(point)))
3828 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3832 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3834 Ref<Frame> protectedFrame(m_frame);
3836 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3837 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3838 // for an overview of how these lists fit together.
3840 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3841 RefPtr<TouchList> touches = TouchList::create();
3843 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3844 // 'targetTouches' list in the JS event.
3845 typedef HashMap<EventTarget*, RefPtr<TouchList>> TargetTouchesMap;
3846 TargetTouchesMap touchesByTarget;
3848 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3849 typedef HashSet<RefPtr<EventTarget>> EventTargetSet;
3851 // The touches corresponding to the particular change state this struct instance represents.
3852 RefPtr<TouchList> m_touches;
3853 // Set of targets involved in m_touches.
3854 EventTargetSet m_targets;
3855 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3857 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3859 UserGestureIndicator gestureIndicator(ProcessingUserGesture, m_frame.document());
3861 bool freshTouchEvents = true;
3862 bool allTouchReleased = true;
3863 for (auto& point : points) {
3864 if (point.state() != PlatformTouchPoint::TouchPressed)
3865 freshTouchEvents = false;
3866 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3867 allTouchReleased = false;
3870 for (auto& point : points) {
3871 PlatformTouchPoint::State pointState = point.state();
3872 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3874 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3875 // The HitTestRequest types used for mouse events map quite adequately
3876 // to touch events. Note that in addition to meaning that the hit test
3877 // should affect the active state of the current node if necessary,
3878 // HitTestRequest::Active signifies that the hit test is taking place
3879 // with the mouse (or finger in this case) being pressed.
3880 switch (pointState) {
3881 case PlatformTouchPoint::TouchPressed:
3882 hitType |= HitTestRequest::Active;
3884 case PlatformTouchPoint::TouchMoved:
3885 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3887 case PlatformTouchPoint::TouchReleased:
3888 case PlatformTouchPoint::TouchCancelled:
3889 hitType |= HitTestRequest::Release;
3891 case PlatformTouchPoint::TouchStationary:
3892 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3895 ASSERT_NOT_REACHED();
3899 if (shouldGesturesTriggerActive())
3900 hitType |= HitTestRequest::ReadOnly;
3902 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3903 unsigned touchPointTargetKey = point.id() + 1;
3904 RefPtr<EventTarget> touchTarget;
3905 if (pointState == PlatformTouchPoint::TouchPressed) {
3906 HitTestResult result;
3907 if (freshTouchEvents) {
3908 result = hitTestResultAtPoint(pagePoint, hitType);
3909 m_originatingTouchPointTargetKey = touchPointTargetKey;
3910 } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) {
3911 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(*m_originatingTouchPointDocument->frame(), point.pos());
3912 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType);
3913 if (!result.innerNode())
3918 // FIXME: This code should use Element* instead of Node*.
3919 Node* node = result.innerElement();
3922 if (node && InspectorInstrumentation::handleTouchEvent(m_frame, *node))
3925 Document& doc = node->document();
3926 // Record the originating touch document even if it does not have a touch listener.
3927 if (freshTouchEvents) {
3928 m_originatingTouchPointDocument = &doc;
3929 freshTouchEvents = false;
3931 if (!doc.hasTouchEventHandlers())
3933 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3935 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3936 // No need to perform a hit-test since we only need to unset :hover and :active states.
3937 if (!shouldGesturesTriggerActive() && allTouchReleased)
3938 m_frame.document()->updateHoverActiveState(hitType, 0);
3939 if (touchPointTargetKey == m_originatingTouchPointTargetKey)
3940 m_originatingTouchPointTargetKey = 0;
3942 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3943 // we also remove it from the map.
3944 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3946 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3947 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3949 if (!touchTarget.get())
3951 Document& doc = touchTarget->toNode()->document();
3952 if (!doc.hasTouchEventHandlers())
3954 Frame* targetFrame = doc.frame();
3958 if (&m_frame != targetFrame) {
3959 // pagePoint should always be relative to the target elements containing frame.
3960 pagePoint = documentPointForWindowPoint(*targetFrame, point.pos());
3963 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor();
3965 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3966 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3968 auto touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3969 point.screenPos().x(), point.screenPos().y(), adjustedPageX, adjustedPageY,
3970 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3972 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3973 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3974 if (targetTouchesIterator == touchesByTarget.end())
3975 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3977 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3978 // released or cancelled it will only appear in the changedTouches list.
3979 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3980 touches->append(touch.copyRef());
3981 targetTouchesIterator->value->append(touch.copyRef());
3984 // Now build up the correct list for changedTouches.
3985 // Note that any touches that are in the TouchStationary state (e.g. if
3986 // the user had several points touched but did not move them all) should
3987 // never be in the changedTouches list so we do not handle them explicitly here.
3988 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3989 // about the TouchStationary state.
3990 if (pointState != PlatformTouchPoint::TouchStationary) {
3991 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3992 if (!changedTouches[pointState].m_touches)
3993 changedTouches[pointState].m_touches = TouchList::create();
3994 changedTouches[pointState].m_touches->append(WTFMove(touch));
3995 changedTouches[pointState].m_targets.add(touchTarget);
3998 m_touchPressed = touches->length() > 0;
3999 if (allTouchReleased)
4000 m_originatingTouchPointDocument = nullptr;
4002 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
4003 bool swallowedEvent = false;
4004 RefPtr<TouchList> emptyList = TouchList::create();
4005 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
4006 if (!changedTouches[state].m_touches)
4009 // When sending a touch cancel event, use empty touches and targetTouches lists.
4010 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
4011 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
4012 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
4014 for (auto& taget : changedTouches[state].m_targets) {
4015 EventTarget* touchEventTarget = taget.get();
4016 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
4017 ASSERT(targetTouches);
4019 Ref<TouchEvent> touchEvent =
4020 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
4021 stateName, touchEventTarget->toNode()->document().defaultView(),
4022 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
4023 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent);
4024 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
4028 return swallowedEvent;
4030 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
4032 #if ENABLE(TOUCH_EVENTS)
4033 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& platformMouseEvent)
4035 #if ENABLE(IOS_TOUCH_EVENTS)
4036 UNUSED_PARAM(platformMouseEvent);
4039 if (!m_frame.settings().isTouchEventEmulationEnabled())
4042 PlatformEvent::Type eventType = platformMouseEvent.type();
4043 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
4046 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
4047 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
4048 if (mouseEvent.scrollbar() || subframeForHitTestResult(mouseEvent))
4051 // The order is important. This check should follow the subframe test: http://webkit.org/b/111292.
4052 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
4055 SyntheticSingleTouchEvent touchEvent(platformMouseEvent);
4056 return handleTouchEvent(touchEvent);
4059 #endif // ENABLE(TOUCH_EVENTS)
4061 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
4063 m_mousePositionIsUnknown = false;
4064 m_lastKnownMousePosition = event.position();
4065 m_lastKnownMouseGlobalPosition = event.globalPosition();
4068 void EventHandler::setImmediateActionStage(ImmediateActionStage stage)
4070 m_immediateActionStage = stage;