2 * Copyright (C) 2006-2015 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 "htmlediting.h"
56 #include "HTMLFrameElementBase.h"
57 #include "HTMLFrameSetElement.h"
58 #include "HTMLInputElement.h"
59 #include "HTMLNames.h"
60 #include "HitTestRequest.h"
61 #include "HitTestResult.h"
63 #include "InspectorInstrumentation.h"
64 #include "KeyboardEvent.h"
65 #include "MainFrame.h"
66 #include "MouseEvent.h"
67 #include "MouseEventWithHitTestResults.h"
69 #include "PageOverlayController.h"
70 #include "PlatformEvent.h"
71 #include "PlatformKeyboardEvent.h"
72 #include "PlatformWheelEvent.h"
73 #include "PluginDocument.h"
74 #include "RenderFrameSet.h"
75 #include "RenderLayer.h"
76 #include "RenderListBox.h"
77 #include "RenderNamedFlowThread.h"
78 #include "RenderTextControlSingleLine.h"
79 #include "RenderView.h"
80 #include "RenderWidget.h"
81 #include "RuntimeApplicationChecks.h"
82 #include "SVGDocument.h"
84 #include "ScrollLatchingState.h"
85 #include "Scrollbar.h"
87 #include "ShadowRoot.h"
88 #include "SpatialNavigation.h"
89 #include "StyleCachedImage.h"
90 #include "TextEvent.h"
91 #include "TextIterator.h"
92 #include "UserGestureIndicator.h"
93 #include "UserTypingGestureIndicator.h"
94 #include "VisibleUnits.h"
95 #include "WheelEvent.h"
96 #include "WindowsKeyboardCodes.h"
97 #include <wtf/Assertions.h>
98 #include <wtf/CurrentTime.h>
99 #include <wtf/StdLibExtras.h>
100 #include <wtf/TemporaryChange.h>
101 #include <wtf/WeakPtr.h>
103 #if ENABLE(CSS_IMAGE_SET)
104 #include "StyleCachedImageSet.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 const std::chrono::milliseconds longMousePressRecognitionDelay = std::chrono::milliseconds(500);
139 const int maximumLongMousePressDragDistance = 5; // in points.
141 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
142 const float GestureUnknown = 0;
145 #if ENABLE(IOS_TOUCH_EVENTS)
146 // FIXME: Share this constant with EventHandler and SliderThumbElement.
147 const unsigned InvalidTouchIdentifier = 0;
150 // Match key code of composition keydown event on windows.
151 // IE sends VK_PROCESSKEY which has value 229;
152 const int CompositionEventKeyCode = 229;
154 using namespace SVGNames;
156 #if !ENABLE(IOS_TOUCH_EVENTS)
157 // The amount of time to wait before sending a fake mouse event, triggered
158 // during a scroll. The short interval is used if the content responds to the mouse events
159 // in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used.
160 const double fakeMouseMoveDurationThreshold = 0.01;
161 const double fakeMouseMoveShortInterval = 0.1;
162 const double fakeMouseMoveLongInterval = 0.25;
165 #if ENABLE(CURSOR_SUPPORT)
166 // The amount of time to wait for a cursor update on style and layout changes
167 // Set to 50Hz, no need to be faster than common screen refresh rate
168 const double cursorUpdateInterval = 0.02;
170 const int maximumCursorSize = 128;
173 #if ENABLE(MOUSE_CURSOR_SCALE)
174 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
175 // need to ensure here is that the scale isn't so small that integer overflow can occur when
176 // dividing cursor sizes (limited above) by the scale.
177 const double minimumCursorScale = 0.001;
180 enum NoCursorChangeType { NoCursorChange };
182 class OptionalCursor {
184 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
185 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
187 bool isCursorChange() const { return m_isCursorChange; }
188 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
191 bool m_isCursorChange;
195 class MaximumDurationTracker {
197 explicit MaximumDurationTracker(double *maxDuration)
198 : m_maxDuration(maxDuration)
199 , m_start(monotonicallyIncreasingTime())
203 ~MaximumDurationTracker()
205 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
209 double* m_maxDuration;
213 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
214 class SyntheticTouchPoint : public PlatformTouchPoint {
217 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
218 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
220 const static int idDefaultValue = 0;
221 const static int radiusYDefaultValue = 1;
222 const static int radiusXDefaultValue = 1;
223 const static float rotationAngleDefaultValue = 0.0f;
224 const static float forceDefaultValue = 1.0f;
226 m_id = idDefaultValue; // There is only one active TouchPoint.
227 m_screenPos = event.globalPosition();
228 m_pos = event.position();
229 m_radiusY = radiusYDefaultValue;
230 m_radiusX = radiusXDefaultValue;
231 m_rotationAngle = rotationAngleDefaultValue;
232 m_force = forceDefaultValue;
234 PlatformEvent::Type type = event.type();
235 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
238 case PlatformEvent::MouseMoved:
239 m_state = TouchMoved;
241 case PlatformEvent::MousePressed:
242 m_state = TouchPressed;
244 case PlatformEvent::MouseReleased:
245 m_state = TouchReleased;
248 ASSERT_NOT_REACHED();
254 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
256 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
258 switch (event.type()) {
259 case PlatformEvent::MouseMoved:
262 case PlatformEvent::MousePressed:
265 case PlatformEvent::MouseReleased:
269 ASSERT_NOT_REACHED();
273 m_timestamp = event.timestamp();
274 m_modifiers = event.modifiers();
275 m_touchPoints.append(SyntheticTouchPoint(event));
278 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
280 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
283 case WheelEvent::DOM_DELTA_PAGE:
285 case WheelEvent::DOM_DELTA_LINE:
287 case WheelEvent::DOM_DELTA_PIXEL:
288 return ScrollByPixel;
290 return ScrollByPixel;
294 static inline bool didScrollInScrollableArea(ScrollableArea* scrollableArea, WheelEvent* wheelEvent)
296 ScrollGranularity scrollGranularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
297 bool didHandleWheelEvent = false;
298 if (float absoluteDelta = std::abs(wheelEvent->deltaX()))
299 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent->deltaX() > 0 ? ScrollRight : ScrollLeft, scrollGranularity, absoluteDelta);
301 if (float absoluteDelta = std::abs(wheelEvent->deltaY()))
302 didHandleWheelEvent |= scrollableArea->scroll(wheelEvent->deltaY() > 0 ? ScrollDown : ScrollUp, scrollGranularity, absoluteDelta);
304 return didHandleWheelEvent;
307 static inline bool handleWheelEventInAppropriateEnclosingBox(Node* startNode, WheelEvent* wheelEvent, Element** stopElement, const FloatSize& filteredPlatformDelta)
309 bool shouldHandleEvent = wheelEvent->deltaX() || wheelEvent->deltaY();
311 shouldHandleEvent |= wheelEvent->phase() == PlatformWheelEventPhaseEnded;
312 #if ENABLE(CSS_SCROLL_SNAP)
313 shouldHandleEvent |= wheelEvent->momentumPhase() == PlatformWheelEventPhaseEnded;
316 if (!startNode->renderer() || !shouldHandleEvent)
319 RenderBox& initialEnclosingBox = startNode->renderer()->enclosingBox();
320 if (initialEnclosingBox.isListBox())
321 return didScrollInScrollableArea(static_cast<RenderListBox*>(&initialEnclosingBox), wheelEvent);
323 RenderBox* currentEnclosingBox = &initialEnclosingBox;
324 while (currentEnclosingBox) {
325 if (RenderLayer* boxLayer = currentEnclosingBox->layer()) {
326 const PlatformWheelEvent* platformEvent = wheelEvent->wheelEvent();
327 bool scrollingWasHandled;
328 if (platformEvent != nullptr)
329 scrollingWasHandled = boxLayer->handleWheelEvent(platformEvent->copyWithDeltas(filteredPlatformDelta.width(), filteredPlatformDelta.height()));
331 scrollingWasHandled = didScrollInScrollableArea(boxLayer, wheelEvent);
333 if (scrollingWasHandled) {
335 *stopElement = currentEnclosingBox->element();
340 if (stopElement && *stopElement && *stopElement == currentEnclosingBox->element())
343 currentEnclosingBox = currentEnclosingBox->containingBlock();
344 if (currentEnclosingBox && currentEnclosingBox->isRenderNamedFlowThread())
345 currentEnclosingBox = RenderNamedFlowThread::fragmentFromRenderBoxAsRenderBlock(currentEnclosingBox, roundedIntPoint(wheelEvent->absoluteLocation()), initialEnclosingBox);
346 if (!currentEnclosingBox || currentEnclosingBox->isRenderView())
352 #if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS))
353 static inline bool shouldGesturesTriggerActive()
355 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
356 // rely on them to set the active state. Unfortunately there's no generic way to
357 // know in advance what event types are supported.
364 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
369 #if ENABLE(DRAG_SUPPORT)
370 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
378 EventHandler::EventHandler(Frame& frame)
380 , m_hoverTimer(*this, &EventHandler::hoverTimerFired)
381 #if ENABLE(CURSOR_SUPPORT)
382 , m_cursorUpdateTimer(*this, &EventHandler::cursorUpdateTimerFired)
384 , m_longMousePressTimer(*this, &EventHandler::recognizeLongMousePress)
385 , m_autoscrollController(std::make_unique<AutoscrollController>())
386 #if !ENABLE(IOS_TOUCH_EVENTS)
387 , m_fakeMouseMoveEventTimer(*this, &EventHandler::fakeMouseMoveEventTimerFired)
389 #if ENABLE(CURSOR_VISIBILITY)
390 , m_autoHideCursorTimer(*this, &EventHandler::autoHideCursorTimerFired)
395 EventHandler::~EventHandler()
397 #if !ENABLE(IOS_TOUCH_EVENTS)
398 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
400 #if ENABLE(CURSOR_VISIBILITY)
401 ASSERT(!m_autoHideCursorTimer.isActive());
405 #if ENABLE(DRAG_SUPPORT)
406 DragState& EventHandler::dragState()
408 DEPRECATED_DEFINE_STATIC_LOCAL(DragState, state, ());
411 #endif // ENABLE(DRAG_SUPPORT)
413 void EventHandler::clear()
416 #if ENABLE(CURSOR_SUPPORT)
417 m_cursorUpdateTimer.stop();
419 #if !ENABLE(IOS_TOUCH_EVENTS)
420 m_fakeMouseMoveEventTimer.stop();
422 #if ENABLE(CURSOR_VISIBILITY)
423 cancelAutoHideCursorTimer();
425 clearLongMousePressState();
426 m_resizeLayer = nullptr;
427 m_elementUnderMouse = nullptr;
428 m_lastElementUnderMouse = nullptr;
429 m_lastMouseMoveEventSubframe = nullptr;
430 m_lastScrollbarUnderMouse = nullptr;
432 m_clickNode = nullptr;
433 #if ENABLE(IOS_GESTURE_EVENTS)
434 m_gestureInitialDiameter = GestureUnknown;
435 m_gestureInitialRotation = GestureUnknown;
437 #if ENABLE(IOS_GESTURE_EVENTS) || ENABLE(MAC_GESTURE_EVENTS)
438 m_gestureLastDiameter = GestureUnknown;
439 m_gestureLastRotation = GestureUnknown;
440 m_gestureTargets.clear();
442 #if ENABLE(IOS_TOUCH_EVENTS)
444 m_firstTouchID = InvalidTouchIdentifier;
445 m_touchEventTargetSubframe = nullptr;
447 m_frameSetBeingResized = nullptr;
448 #if ENABLE(DRAG_SUPPORT)
449 m_dragTarget = nullptr;
450 m_shouldOnlyFireDragOverEvent = false;
452 m_mousePositionIsUnknown = true;
453 m_lastKnownMousePosition = IntPoint();
454 m_lastKnownMouseGlobalPosition = IntPoint();
455 m_mousePressNode = nullptr;
456 m_mousePressed = false;
457 m_capturesDragging = false;
458 m_capturingMouseEventsElement = nullptr;
460 m_frame.mainFrame().resetLatchingState();
462 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
463 m_originatingTouchPointTargets.clear();
464 m_originatingTouchPointDocument = nullptr;
465 m_originatingTouchPointTargetKey = 0;
467 m_maxMouseMovedDuration = 0;
468 m_baseEventType = PlatformEvent::NoType;
469 m_didStartDrag = false;
470 m_didLongPressInvokeContextMenu = false;
473 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
475 if (nodeToBeRemoved.contains(m_clickNode.get()))
476 m_clickNode = nullptr;
479 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
481 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection))
482 selection.setSelection(newSelection);
485 static inline bool dispatchSelectStart(Node* node)
487 if (!node || !node->renderer())
490 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
493 static Node* nodeToSelectOnMouseDownForNode(Node& targetNode)
495 #if ENABLE(USERSELECT_ALL)
496 if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(&targetNode))
497 return rootUserSelectAll;
500 if (targetNode.shouldSelectOnMouseDown())
506 static VisibleSelection expandSelectionToRespectSelectOnMouseDown(Node& targetNode, const VisibleSelection& selection)
508 Node* nodeToSelect = nodeToSelectOnMouseDownForNode(targetNode);
512 VisibleSelection newSelection(selection);
513 newSelection.setBase(positionBeforeNode(nodeToSelect).upstream(CanCrossEditingBoundary));
514 newSelection.setExtent(positionAfterNode(nodeToSelect).downstream(CanCrossEditingBoundary));
519 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
521 if (Position::nodeIsUserSelectNone(targetNode))
524 if (!dispatchSelectStart(targetNode))
527 if (selection.isRange())
528 m_selectionInitiationState = ExtendedSelection;
530 granularity = CharacterGranularity;
531 m_selectionInitiationState = PlacedCaret;
534 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity);
539 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
541 Node* targetNode = result.targetNode();
542 VisibleSelection newSelection;
544 if (targetNode && targetNode->renderer()) {
545 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
546 if (pos.isNotNull()) {
547 newSelection = VisibleSelection(pos);
548 newSelection.expandUsingGranularity(WordGranularity);
551 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
552 newSelection.appendTrailingWhitespace();
554 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
558 static AppendTrailingWhitespace shouldAppendTrailingWhitespace(const MouseEventWithHitTestResults& result, const Frame& frame)
560 return (result.event().clickCount() == 2 && frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace;
563 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
565 if (m_mouseDownMayStartSelect)
566 selectClosestWordFromHitTestResult(result.hitTestResult(), shouldAppendTrailingWhitespace(result, m_frame));
570 VisibleSelection EventHandler::selectClosestWordFromHitTestResultBasedOnLookup(const HitTestResult&)
572 return VisibleSelection();
576 void EventHandler::selectClosestContextualWordFromMouseEvent(const MouseEventWithHitTestResults& mouseEvent)
578 Node* targetNode = mouseEvent.targetNode();
579 const HitTestResult& result = mouseEvent.hitTestResult();
580 VisibleSelection newSelection;
581 bool appendTrailingWhitespace = shouldAppendTrailingWhitespace(mouseEvent, m_frame);
583 if (targetNode && targetNode->renderer()) {
584 newSelection = selectClosestWordFromHitTestResultBasedOnLookup(result);
585 if (newSelection.isNone()) {
586 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
587 if (pos.isNotNull()) {
588 newSelection = VisibleSelection(pos);
589 newSelection.expandUsingGranularity(WordGranularity);
593 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
594 newSelection.appendTrailingWhitespace();
596 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
600 void EventHandler::selectClosestContextualWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
602 Element* urlElement = result.hitTestResult().URLElement();
603 if (!urlElement || !isDraggableLink(*urlElement)) {
604 if (Node* targetNode = result.targetNode()) {
605 if (isEditableNode(*targetNode))
606 return selectClosestWordFromMouseEvent(result);
609 return selectClosestContextualWordFromMouseEvent(result);
612 Node* targetNode = result.targetNode();
614 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) {
615 VisibleSelection newSelection;
616 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
617 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(urlElement))
618 newSelection = VisibleSelection::selectionFromContentsOfNode(urlElement);
620 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
624 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
626 if (event.event().button() != LeftButton)
629 if (m_frame.selection().isRange())
630 // A double-click when range is already selected
631 // should not change the selection. So, do not call
632 // selectClosestWordFromMouseEvent, but do set
633 // m_beganSelectingText to prevent handleMouseReleaseEvent
634 // from setting caret selection.
635 m_selectionInitiationState = ExtendedSelection;
637 selectClosestWordFromMouseEvent(event);
642 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
644 if (event.event().button() != LeftButton)
647 Node* targetNode = event.targetNode();
648 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
651 VisibleSelection newSelection;
652 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
653 if (pos.isNotNull()) {
654 newSelection = VisibleSelection(pos);
655 newSelection.expandUsingGranularity(ParagraphGranularity);
658 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), ParagraphGranularity);
661 static int textDistance(const Position& start, const Position& end)
663 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
664 return TextIterator::rangeLength(range.get(), true);
667 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
669 m_frame.document()->updateLayoutIgnorePendingStylesheets();
670 Node* targetNode = event.targetNode();
671 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
674 // Extend the selection if the Shift key is down, unless the click is in a link.
675 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
677 // Don't restart the selection when the mouse is pressed on an
678 // existing selection so we can allow for text dragging.
679 if (FrameView* view = m_frame.view()) {
680 LayoutPoint vPoint = view->windowToContents(event.event().position());
681 if (!extendSelection && m_frame.selection().contains(vPoint)) {
682 m_mouseDownWasSingleClickInSelection = true;
687 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
688 if (visiblePos.isNull())
689 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM);
690 Position pos = visiblePos.deepEquivalent();
692 VisibleSelection newSelection = m_frame.selection().selection();
693 TextGranularity granularity = CharacterGranularity;
695 if (extendSelection && newSelection.isCaretOrRange()) {
696 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectSelectOnMouseDown(*targetNode, VisibleSelection(pos));
697 if (selectionInUserSelectAll.isRange()) {
698 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
699 pos = selectionInUserSelectAll.start();
700 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
701 pos = selectionInUserSelectAll.end();
704 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) {
705 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
706 // was created right-to-left
707 Position start = newSelection.start();
708 Position end = newSelection.end();
709 int distanceToStart = textDistance(start, pos);
710 int distanceToEnd = textDistance(pos, end);
711 if (distanceToStart <= distanceToEnd)
712 newSelection = VisibleSelection(end, pos);
714 newSelection = VisibleSelection(start, pos);
716 newSelection.setExtent(pos);
718 if (m_frame.selection().granularity() != CharacterGranularity) {
719 granularity = m_frame.selection().granularity();
720 newSelection.expandUsingGranularity(m_frame.selection().granularity());
723 newSelection = expandSelectionToRespectSelectOnMouseDown(*targetNode, visiblePos);
725 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity);
727 if (event.event().button() == MiddleButton) {
728 // Ignore handled, since we want to paste to where the caret was placed anyway.
729 handled = handlePasteGlobalSelection(event.event()) || handled;
734 static inline bool canMouseDownStartSelect(Node* node)
736 if (!node || !node->renderer())
739 return node->canStartSelection() || Position::nodeIsUserSelectAll(node);
742 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
744 #if ENABLE(DRAG_SUPPORT)
746 dragState().source = nullptr;
749 #if !ENABLE(IOS_TOUCH_EVENTS)
750 cancelFakeMouseMoveEvent();
753 m_frame.document()->updateLayoutIgnorePendingStylesheets();
755 if (ScrollView* scrollView = m_frame.view()) {
756 if (scrollView->isPointInScrollbarCorner(event.event().position()))
760 bool singleClick = event.event().clickCount() <= 1;
762 // If we got the event back, that must mean it wasn't prevented,
763 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
764 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
766 #if ENABLE(DRAG_SUPPORT)
767 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
768 m_mouseDownMayStartDrag = singleClick;
771 m_mouseDownWasSingleClickInSelection = false;
773 m_mouseDown = event.event();
775 if (m_immediateActionStage != ImmediateActionStage::PerformedHitTest)
776 m_immediateActionStage = ImmediateActionStage::None;
778 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
781 if (is<SVGDocument>(*m_frame.document()) && downcast<SVGDocument>(*m_frame.document()).zoomAndPanEnabled()) {
782 if (event.event().shiftKey() && singleClick) {
784 downcast<SVGDocument>(*m_frame.document()).startPan(m_frame.view()->windowToContents(event.event().position()));
789 if (event.event().button() == LeftButton && event.isOverLink()) {
790 // FIXME 135703: Handle long press for more than just links.
791 beginTrackingPotentialLongMousePress(event.hitTestResult());
794 // We don't do this at the start of mouse down handling,
795 // because we don't want to do it until we know we didn't hit a widget.
799 m_mousePressNode = 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 if (handleDrag(event, ShouldCheckDragHysteresis))
830 Node* targetNode = event.targetNode();
831 if (event.event().button() != LeftButton || !targetNode)
834 RenderObject* renderer = targetNode->renderer();
836 Element* parent = targetNode->parentOrShadowHostElement();
840 renderer = parent->renderer();
841 if (!renderer || !renderer->isListBox())
845 #if PLATFORM(COCOA) // FIXME: Why does this assertion fire on other platforms?
846 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
849 m_mouseDownMayStartDrag = false;
851 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
852 m_autoscrollController->startAutoscrollForSelection(renderer);
853 m_mouseDownMayStartAutoscroll = false;
856 if (m_selectionInitiationState != ExtendedSelection) {
857 HitTestResult result(m_mouseDownPos);
858 m_frame.document()->renderView()->hitTest(HitTestRequest(), result);
860 updateSelectionForMouseDrag(result);
862 updateSelectionForMouseDrag(event.hitTestResult());
866 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
868 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
869 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
870 // in handleMousePressEvent
871 RenderView* renderView = m_frame.contentRenderer();
875 if (event.button() != LeftButton || event.clickCount() != 1)
878 if (m_didRecognizeLongMousePress)
881 FrameView* view = m_frame.view();
885 Page* page = m_frame.page();
889 updateDragSourceActionsAllowed();
890 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
891 HitTestResult result(view->windowToContents(event.position()));
892 renderView->hitTest(request, result);
894 return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
897 void EventHandler::updateSelectionForMouseDrag()
899 FrameView* view = m_frame.view();
902 RenderView* renderView = m_frame.contentRenderer();
906 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
907 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
908 renderView->hitTest(request, result);
909 updateSelectionForMouseDrag(result);
912 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
914 FloatPoint selectionEndPoint = localPoint;
915 Element* editableElement = selection.rootEditableElement();
917 if (!targetNode->renderer())
918 return VisiblePosition();
920 if (editableElement && !editableElement->contains(targetNode)) {
921 if (!editableElement->renderer())
922 return VisiblePosition();
924 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
925 selectionEndPoint = editableElement->renderer()->absoluteToLocal(absolutePoint);
926 targetNode = editableElement;
929 return targetNode->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr);
932 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
934 if (!m_mouseDownMayStartSelect)
937 Node* target = hitTestResult.targetNode();
941 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target);
943 // Don't modify the selection if we're not on a node.
944 if (targetPosition.isNull())
947 // Restart the selection if this is the first mouse move. This work is usually
948 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
949 VisibleSelection newSelection = m_frame.selection().selection();
951 // Special case to limit selection to the containing block for SVG text.
952 // FIXME: Isn't there a better non-SVG-specific way to do this?
953 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
954 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
955 if (selectionBaseRenderer->isSVGText())
956 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
959 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
962 if (m_selectionInitiationState != ExtendedSelection) {
963 // Always extend selection here because it's caused by a mouse drag
964 m_selectionInitiationState = ExtendedSelection;
965 newSelection = VisibleSelection(targetPosition);
968 #if ENABLE(USERSELECT_ALL)
969 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
970 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
971 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
972 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
974 // Reset base for user select all when base is inside user-select-all area and extent < base.
975 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
976 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
978 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
979 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
980 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
981 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
982 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
984 newSelection.setExtent(targetPosition);
987 newSelection.setExtent(targetPosition);
990 if (m_frame.selection().granularity() != CharacterGranularity)
991 newSelection.expandUsingGranularity(m_frame.selection().granularity());
993 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
994 FrameSelection::AdjustEndpointsAtBidiBoundary);
996 #endif // ENABLE(DRAG_SUPPORT)
998 void EventHandler::lostMouseCapture()
1000 m_frame.selection().setCaretBlinkingSuspended(false);
1003 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
1005 if (eventLoopHandleMouseUp(event))
1008 // If this was the first click in the window, we don't even want to clear the selection.
1009 // This case occurs when the user clicks on a draggable element, since we have to process
1010 // the mouse down and drag events to see if we might start a drag. For other first clicks
1011 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1012 // ignored upstream of this layer.
1013 return eventActivatedView(event.event());
1016 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1018 if (autoscrollInProgress())
1019 stopAutoscrollTimer();
1021 if (handleMouseUp(event))
1024 // Used to prevent mouseMoveEvent from initiating a drag before
1025 // the mouse is pressed again.
1026 m_mousePressed = false;
1027 m_capturesDragging = false;
1028 #if ENABLE(DRAG_SUPPORT)
1029 m_mouseDownMayStartDrag = false;
1031 m_mouseDownMayStartSelect = false;
1032 m_mouseDownMayStartAutoscroll = false;
1033 m_mouseDownWasInSubframe = false;
1035 bool handled = false;
1037 if (event.event().button() == LeftButton) {
1038 // FIXME 135767: Implement long mouse press for arbitrary mouse buttons.
1039 clearLongMousePressState();
1042 // Clear the selection if the mouse didn't move after the last mouse
1043 // press and it's not a context menu click. We do this so when clicking
1044 // on the selection, the selection goes away. However, if we are
1045 // editing, place the caret.
1046 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
1047 #if ENABLE(DRAG_SUPPORT)
1048 && m_dragStartPos == event.event().position()
1050 && m_frame.selection().isRange()
1051 && event.event().button() != RightButton) {
1052 VisibleSelection newSelection;
1053 Node* node = event.targetNode();
1054 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
1055 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
1056 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint(), nullptr);
1057 newSelection = VisibleSelection(pos);
1060 setSelectionIfNeeded(m_frame.selection(), newSelection);
1065 if (event.event().button() == MiddleButton) {
1066 // Ignore handled, since we want to paste to where the caret was placed anyway.
1067 handled = handlePasteGlobalSelection(event.event()) || handled;
1073 #if ENABLE(PAN_SCROLLING)
1075 void EventHandler::didPanScrollStart()
1077 m_autoscrollController->didPanScrollStart();
1080 void EventHandler::didPanScrollStop()
1082 m_autoscrollController->didPanScrollStop();
1085 void EventHandler::startPanScrolling(RenderElement* renderer)
1088 if (!is<RenderBox>(*renderer))
1090 m_autoscrollController->startPanScrolling(downcast<RenderBox>(renderer), lastKnownMousePosition());
1095 #endif // ENABLE(PAN_SCROLLING)
1097 RenderBox* EventHandler::autoscrollRenderer() const
1099 return m_autoscrollController->autoscrollRenderer();
1102 void EventHandler::updateAutoscrollRenderer()
1104 m_autoscrollController->updateAutoscrollRenderer();
1107 bool EventHandler::autoscrollInProgress() const
1109 return m_autoscrollController->autoscrollInProgress();
1112 bool EventHandler::panScrollInProgress() const
1114 return m_autoscrollController->panScrollInProgress();
1117 #if ENABLE(DRAG_SUPPORT)
1118 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1120 Page* page = m_frame.page();
1122 return DragSourceActionNone;
1124 FrameView* view = m_frame.view();
1126 return DragSourceActionNone;
1128 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1130 #endif // ENABLE(DRAG_SUPPORT)
1132 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
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 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
1148 RenderView* renderView = m_frame.contentRenderer();
1152 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
1153 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
1154 renderView->hitTest(request, result);
1155 if (!request.readOnly())
1156 m_frame.document()->updateHoverActiveState(request, result.innerElement());
1158 if (request.disallowsShadowContent())
1159 result.setToNonShadowAncestor();
1164 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1166 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed);
1169 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1171 Node* node = startingNode;
1174 node = m_frame.document()->focusedElement();
1177 node = m_mousePressNode.get();
1180 auto r = node->renderer();
1181 if (r && !r->isListBox() && r->enclosingBox().scroll(direction, granularity)) {
1182 setFrameWasScrolledByUser();
1190 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1192 Node* node = startingNode;
1195 node = m_frame.document()->focusedElement();
1198 node = m_mousePressNode.get();
1201 auto r = node->renderer();
1202 if (r && !r->isListBox() && r->enclosingBox().logicalScroll(direction, granularity)) {
1203 setFrameWasScrolledByUser();
1211 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1213 // The layout needs to be up to date to determine if we can scroll. We may be
1214 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1215 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1216 if (scrollOverflow(direction, granularity, startingNode))
1218 Frame* frame = &m_frame;
1219 FrameView* view = frame->view();
1220 if (view && view->scroll(direction, granularity))
1222 frame = frame->tree().parent();
1225 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement());
1228 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1230 // The layout needs to be up to date to determine if we can scroll. We may be
1231 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1232 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1233 if (logicalScrollOverflow(direction, granularity, startingNode))
1235 Frame* frame = &m_frame;
1236 FrameView* view = frame->view();
1238 bool scrolled = false;
1240 // Mac also resets the scroll position in the inline direction.
1241 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1244 if (view && view->logicalScroll(direction, granularity))
1250 frame = frame->tree().parent();
1254 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement());
1257 IntPoint EventHandler::lastKnownMousePosition() const
1259 return m_lastKnownMousePosition;
1262 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1264 if (!hitTestResult.isOverWidget())
1266 return subframeForTargetNode(hitTestResult.targetNode());
1269 Frame* EventHandler::subframeForTargetNode(Node* node)
1274 auto renderer = node->renderer();
1275 if (!is<RenderWidget>(renderer))
1278 Widget* widget = downcast<RenderWidget>(*renderer).widget();
1279 if (!is<FrameView>(widget))
1282 return &downcast<FrameView>(*widget).frame();
1285 #if ENABLE(CURSOR_SUPPORT)
1286 static bool isSubmitImage(Node* node)
1288 return is<HTMLInputElement>(node) && downcast<HTMLInputElement>(*node).isImageButton();
1291 // Returns true if the node's editable block is not current focused for editing
1292 static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame)
1294 return frame.selection().selection().rootEditableElement() != node.rootEditableElement();
1297 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1302 bool editable = node->hasEditableStyle();
1303 bool editableLinkEnabled = false;
1305 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1307 switch (m_frame.settings().editableLinkBehavior()) {
1309 case EditableLinkDefaultBehavior:
1310 case EditableLinkAlwaysLive:
1311 editableLinkEnabled = true;
1314 case EditableLinkNeverLive:
1315 editableLinkEnabled = false;
1318 case EditableLinkLiveWhenNotFocused:
1319 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey;
1322 case EditableLinkOnlyLiveWithShiftKey:
1323 editableLinkEnabled = shiftKey;
1328 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1331 void EventHandler::cursorUpdateTimerFired()
1333 ASSERT(m_frame.document());
1337 void EventHandler::updateCursor()
1339 if (m_mousePositionIsUnknown)
1342 FrameView* view = m_frame.view();
1346 RenderView* renderView = view->renderView();
1350 if (!view->shouldSetCursor())
1357 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1359 HitTestRequest request(HitTestRequest::ReadOnly);
1360 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1361 renderView->hitTest(request, result);
1363 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1364 if (optionalCursor.isCursorChange()) {
1365 m_currentMouseCursor = optionalCursor.cursor();
1366 view->setCursor(m_currentMouseCursor);
1370 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1372 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1373 return NoCursorChange;
1375 if (!m_frame.page())
1376 return NoCursorChange;
1378 #if ENABLE(PAN_SCROLLING)
1379 if (m_frame.mainFrame().eventHandler().panScrollInProgress())
1380 return NoCursorChange;
1383 Node* node = result.targetNode();
1385 return NoCursorChange;
1387 auto renderer = node->renderer();
1388 RenderStyle* style = renderer ? &renderer->style() : nullptr;
1389 bool horizontalText = !style || style->isHorizontalWritingMode();
1390 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1392 #if ENABLE(CURSOR_VISIBILITY)
1393 if (style && style->cursorVisibility() == CursorVisibilityAutoHide)
1394 startAutoHideCursorTimer();
1396 cancelAutoHideCursorTimer();
1400 Cursor overrideCursor;
1401 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1402 case SetCursorBasedOnStyle:
1405 return overrideCursor;
1406 case DoNotSetCursor:
1407 return NoCursorChange;
1411 if (style && style->cursors()) {
1412 const CursorList* cursors = style->cursors();
1413 for (unsigned i = 0; i < cursors->size(); ++i) {
1414 StyleImage* styleImage = (*cursors)[i].image();
1417 CachedImage* cachedImage = styleImage->cachedImage();
1420 float scale = styleImage->imageScaleFactor();
1421 // Get hotspot and convert from logical pixels to physical pixels.
1422 IntPoint hotSpot = (*cursors)[i].hotSpot();
1423 FloatSize size = cachedImage->imageForRenderer(renderer)->size();
1424 if (cachedImage->errorOccurred())
1426 // Limit the size of cursors (in UI pixels) so that they cannot be
1427 // used to cover UI elements in chrome.
1428 size.scale(1 / scale);
1429 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1432 Image* image = cachedImage->imageForRenderer(renderer);
1433 #if ENABLE(MOUSE_CURSOR_SCALE)
1434 // Ensure no overflow possible in calculations above.
1435 if (scale < minimumCursorScale)
1437 return Cursor(image, hotSpot, scale);
1440 return Cursor(image, hotSpot);
1441 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1445 // During selection, use an I-beam regardless of the content beneath the cursor.
1446 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1448 && m_mouseDownMayStartSelect
1449 #if ENABLE(DRAG_SUPPORT)
1450 && !m_mouseDownMayStartDrag
1452 && m_frame.selection().isCaretOrRange()
1453 && !m_capturingMouseEventsElement)
1456 switch (style ? style->cursor() : CursorAuto) {
1458 bool editable = node->hasEditableStyle();
1460 if (useHandCursor(node, result.isOverLink(), shiftKey))
1461 return handCursor();
1463 bool inResizer = false;
1465 if (RenderLayer* layer = renderer->enclosingLayer()) {
1466 if (FrameView* view = m_frame.view())
1467 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1471 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1473 return pointerCursor();
1476 return crossCursor();
1478 return handCursor();
1480 return moveCursor();
1481 case CursorAllScroll:
1482 return moveCursor();
1484 return eastResizeCursor();
1486 return westResizeCursor();
1488 return northResizeCursor();
1490 return southResizeCursor();
1491 case CursorNeResize:
1492 return northEastResizeCursor();
1493 case CursorSwResize:
1494 return southWestResizeCursor();
1495 case CursorNwResize:
1496 return northWestResizeCursor();
1497 case CursorSeResize:
1498 return southEastResizeCursor();
1499 case CursorNsResize:
1500 return northSouthResizeCursor();
1501 case CursorEwResize:
1502 return eastWestResizeCursor();
1503 case CursorNeswResize:
1504 return northEastSouthWestResizeCursor();
1505 case CursorNwseResize:
1506 return northWestSouthEastResizeCursor();
1507 case CursorColResize:
1508 return columnResizeCursor();
1509 case CursorRowResize:
1510 return rowResizeCursor();
1512 return iBeamCursor();
1514 return waitCursor();
1516 return helpCursor();
1517 case CursorVerticalText:
1518 return verticalTextCursor();
1520 return cellCursor();
1521 case CursorContextMenu:
1522 return contextMenuCursor();
1523 case CursorProgress:
1524 return progressCursor();
1526 return noDropCursor();
1528 return aliasCursor();
1530 return copyCursor();
1532 return noneCursor();
1533 case CursorNotAllowed:
1534 return notAllowedCursor();
1536 return pointerCursor();
1538 return zoomInCursor();
1540 return zoomOutCursor();
1541 case CursorWebkitGrab:
1542 return grabCursor();
1543 case CursorWebkitGrabbing:
1544 return grabbingCursor();
1546 return pointerCursor();
1548 #endif // ENABLE(CURSOR_SUPPORT)
1550 #if ENABLE(CURSOR_VISIBILITY)
1551 void EventHandler::startAutoHideCursorTimer()
1553 Page* page = m_frame.page();
1557 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
1559 #if !ENABLE(IOS_TOUCH_EVENTS)
1560 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1561 // so cancel any pending fake mouse moves.
1562 if (m_fakeMouseMoveEventTimer.isActive())
1563 m_fakeMouseMoveEventTimer.stop();
1567 void EventHandler::cancelAutoHideCursorTimer()
1569 if (m_autoHideCursorTimer.isActive())
1570 m_autoHideCursorTimer.stop();
1573 void EventHandler::autoHideCursorTimerFired()
1575 m_currentMouseCursor = noneCursor();
1576 FrameView* view = m_frame.view();
1577 if (view && view->isActive())
1578 view->setCursor(m_currentMouseCursor);
1582 void EventHandler::beginTrackingPotentialLongMousePress(const HitTestResult& hitTestResult)
1584 clearLongMousePressState();
1586 Page* page = m_frame.page();
1587 if (!(page && page->settings().longMousePressEnabled()))
1590 m_longMousePressTimer.startOneShot(longMousePressRecognitionDelay);
1592 page->chrome().didBeginTrackingPotentialLongMousePress(m_mouseDownPos, hitTestResult);
1595 void EventHandler::recognizeLongMousePress()
1597 Page* page = m_frame.page();
1601 m_didRecognizeLongMousePress = true;
1603 // Clear mouse state to avoid initiating a drag.
1604 m_mousePressed = false;
1607 page->chrome().didRecognizeLongMousePress();
1610 void EventHandler::cancelTrackingPotentialLongMousePress()
1612 if (!m_longMousePressTimer.isActive())
1615 clearLongMousePressState();
1617 Page* page = m_frame.page();
1621 page->chrome().didCancelTrackingPotentialLongMousePress();
1624 void EventHandler::clearLongMousePressState()
1626 m_longMousePressTimer.stop();
1627 m_didRecognizeLongMousePress = false;
1630 bool EventHandler::handleLongMousePressMouseMovedEvent(const PlatformMouseEvent& mouseEvent)
1632 if (mouseEvent.button() != LeftButton || mouseEvent.type() != PlatformEvent::MouseMoved)
1635 if (m_didRecognizeLongMousePress)
1638 if (!mouseMovementExceedsThreshold(mouseEvent.position(), maximumLongMousePressDragDistance))
1639 cancelTrackingPotentialLongMousePress();
1644 static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
1646 FrameView* view = frame.view();
1647 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1648 // Historically the code would just crash; this is clearly no worse than that.
1649 return view ? view->windowToContents(windowPoint) : windowPoint;
1652 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& platformMouseEvent)
1654 RefPtr<FrameView> protector(m_frame.view());
1656 if (InspectorInstrumentation::handleMousePress(m_frame)) {
1661 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
1664 #if ENABLE(TOUCH_EVENTS)
1665 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1666 if (defaultPrevented)
1670 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
1672 // FIXME (bug 68185): this call should be made at another abstraction layer
1673 m_frame.loader().resetMultipleFormSubmissionProtection();
1675 #if !ENABLE(IOS_TOUCH_EVENTS)
1676 cancelFakeMouseMoveEvent();
1678 m_mousePressed = true;
1679 m_capturesDragging = true;
1680 setLastKnownMousePosition(platformMouseEvent);
1681 m_mouseDownTimestamp = platformMouseEvent.timestamp();
1682 #if ENABLE(DRAG_SUPPORT)
1683 m_mouseDownMayStartDrag = false;
1685 m_mouseDownMayStartSelect = false;
1686 m_mouseDownMayStartAutoscroll = false;
1687 if (FrameView* view = m_frame.view())
1688 m_mouseDownPos = view->windowToContents(platformMouseEvent.position());
1693 m_mouseDownWasInSubframe = false;
1695 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1696 // Save the document point we generate in case the window coordinate is invalidated by what happens
1697 // when we dispatch the event.
1698 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, platformMouseEvent.position());
1699 MouseEventWithHitTestResults mouseEvent = m_frame.document()->prepareMouseEvent(request, documentPoint, platformMouseEvent);
1701 if (!mouseEvent.targetNode()) {
1706 m_mousePressNode = mouseEvent.targetNode();
1708 RefPtr<Frame> subframe = subframeForHitTestResult(mouseEvent);
1709 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe.get())) {
1710 // Start capturing future events for this frame. We only do this if we didn't clear
1711 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1712 m_capturesDragging = subframe->eventHandler().capturesDragging();
1713 if (m_mousePressed && m_capturesDragging) {
1714 m_capturingMouseEventsElement = subframe->ownerElement();
1715 m_eventHandlerWillResetCapturingMouseEventsElement = true;
1721 #if ENABLE(PAN_SCROLLING)
1722 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1723 // because it will set m_autoscrollType to NoAutoscroll on return.
1724 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress();
1725 stopAutoscrollTimer();
1726 if (isPanScrollInProgress) {
1727 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1728 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1734 m_clickCount = platformMouseEvent.clickCount();
1735 m_clickNode = mouseEvent.targetNode();
1742 if (FrameView* view = m_frame.view()) {
1743 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1744 IntPoint p = view->windowToContents(platformMouseEvent.position());
1745 if (layer && layer->isPointInResizeControl(p)) {
1746 layer->setInResizeMode(true);
1747 m_resizeLayer = layer;
1748 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1754 m_frame.selection().setCaretBlinkingSuspended(true);
1756 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1757 m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
1759 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1760 // in case the scrollbar widget was destroyed when the mouse event was handled.
1761 if (mouseEvent.scrollbar()) {
1762 const bool wasLastScrollBar = mouseEvent.scrollbar() == m_lastScrollbarUnderMouse.get();
1763 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1764 if (wasLastScrollBar && mouseEvent.scrollbar() != m_lastScrollbarUnderMouse.get())
1765 m_lastScrollbarUnderMouse = nullptr;
1769 // scrollbars should get events anyway, even disabled controls might be scrollable
1770 Scrollbar* scrollbar = mouseEvent.scrollbar();
1772 updateLastScrollbarUnderMouse(scrollbar, true);
1775 passMousePressEventToScrollbar(mouseEvent, scrollbar);
1777 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1778 // If a mouse event handler changes the input element type to one that has a widget associated,
1779 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1780 // event target node can't still be the shadow node.
1781 if (is<ShadowRoot>(*mouseEvent.targetNode()) && is<HTMLInputElement>(*downcast<ShadowRoot>(*mouseEvent.targetNode()).host()))
1782 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1784 FrameView* view = m_frame.view();
1785 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(platformMouseEvent.position()) : 0;
1787 scrollbar = mouseEvent.scrollbar();
1789 updateLastScrollbarUnderMouse(scrollbar, true);
1791 if (scrollbar && passMousePressEventToScrollbar(mouseEvent, scrollbar))
1792 swallowEvent = true;
1794 swallowEvent = handleMousePressEvent(mouseEvent);
1797 return swallowEvent;
1800 // This method only exists for platforms that don't know how to deliver
1801 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& platformMouseEvent)
1803 RefPtr<FrameView> protector(m_frame.view());
1805 m_frame.selection().setCaretBlinkingSuspended(false);
1807 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
1809 // We get this instead of a second mouse-up
1810 m_mousePressed = false;
1811 setLastKnownMousePosition(platformMouseEvent);
1813 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1814 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1815 Frame* subframe = subframeForHitTestResult(mouseEvent);
1816 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1817 m_capturingMouseEventsElement = nullptr;
1818 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe))
1821 m_clickCount = platformMouseEvent.clickCount();
1822 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
1824 bool swallowClickEvent = platformMouseEvent.button() != RightButton && mouseEvent.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1826 if (m_lastScrollbarUnderMouse)
1827 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
1829 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mouseEvent);
1833 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1836 static RenderLayer* layerForNode(Node* node)
1841 auto renderer = node->renderer();
1845 RenderLayer* layer = renderer->enclosingLayer();
1852 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1854 RefPtr<FrameView> protector(m_frame.view());
1855 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1857 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(event))
1860 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1861 bool result = handleMouseMoveEvent(event, &hoveredNode);
1863 Page* page = m_frame.page();
1867 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1868 if (FrameView* frameView = m_frame.view()) {
1869 if (frameView->containsScrollableArea(layer))
1870 layer->mouseMovedInContentArea();
1874 if (FrameView* frameView = m_frame.view())
1875 frameView->mouseMovedInContentArea();
1877 hoveredNode.setToNonShadowAncestor();
1878 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1879 page->chrome().setToolTip(hoveredNode);
1883 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1885 HitTestResult hoveredNode;
1886 return handleMouseMoveEvent(event, &hoveredNode, true);
1889 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1891 #if ENABLE(TOUCH_EVENTS)
1892 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1893 if (defaultPrevented)
1897 if (handleLongMousePressMouseMovedEvent(platformMouseEvent))
1900 RefPtr<FrameView> protector(m_frame.view());
1902 setLastKnownMousePosition(platformMouseEvent);
1904 if (m_hoverTimer.isActive())
1905 m_hoverTimer.stop();
1907 #if ENABLE(CURSOR_SUPPORT)
1908 m_cursorUpdateTimer.stop();
1911 #if !ENABLE(IOS_TOUCH_EVENTS)
1912 cancelFakeMouseMoveEvent();
1916 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1920 if (m_frameSetBeingResized)
1921 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, platformMouseEvent, false);
1923 // On iOS, our scrollbars are managed by UIKit.
1925 // Send events right to a scrollbar if the mouse is pressed.
1926 if (m_lastScrollbarUnderMouse && m_mousePressed)
1927 return m_lastScrollbarUnderMouse->mouseMoved(platformMouseEvent);
1930 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars;
1932 hitType |= HitTestRequest::Active;
1933 else if (onlyUpdateScrollbars) {
1934 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1935 // means that :hover and :active freeze in the state they were in, rather than updating
1936 // for nodes the mouse moves while the window is not key (which will be the case if
1937 // onlyUpdateScrollbars is true).
1938 hitType |= HitTestRequest::ReadOnly;
1941 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
1942 // Treat any mouse move events as readonly if the user is currently touching the screen.
1944 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1946 HitTestRequest request(hitType);
1947 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1949 *hoveredNode = mouseEvent.hitTestResult();
1951 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1952 m_resizeLayer->resize(platformMouseEvent, m_offsetFromResizeCorner);
1954 Scrollbar* scrollbar = mouseEvent.scrollbar();
1955 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1957 // On iOS, our scrollbars are managed by UIKit.
1959 if (!m_mousePressed && scrollbar)
1960 scrollbar->mouseMoved(platformMouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1962 if (onlyUpdateScrollbars)
1966 bool swallowEvent = false;
1967 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
1969 // 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.
1970 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1971 passMouseMoveEventToSubframe(mouseEvent, m_lastMouseMoveEventSubframe.get());
1974 // Update over/out state before passing the event to the subframe.
1975 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1977 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1978 // node to be detached from its FrameView, in which case the event should not be passed.
1979 if (newSubframe->view())
1980 swallowEvent |= passMouseMoveEventToSubframe(mouseEvent, newSubframe.get(), hoveredNode);
1981 #if ENABLE(CURSOR_SUPPORT)
1983 if (FrameView* view = m_frame.view()) {
1984 OptionalCursor optionalCursor = selectCursor(mouseEvent.hitTestResult(), platformMouseEvent.shiftKey());
1985 if (optionalCursor.isCursorChange()) {
1986 m_currentMouseCursor = optionalCursor.cursor();
1987 view->setCursor(m_currentMouseCursor);
1993 m_lastMouseMoveEventSubframe = newSubframe;
1998 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
1999 #if ENABLE(DRAG_SUPPORT)
2001 swallowEvent = handleMouseDraggedEvent(mouseEvent);
2002 #endif // ENABLE(DRAG_SUPPORT)
2004 return swallowEvent;
2007 void EventHandler::invalidateClick()
2010 m_clickNode = nullptr;
2013 static Node* targetNodeForClickEvent(Node* mousePressNode, Node* mouseReleaseNode)
2015 if (!mousePressNode || !mouseReleaseNode)
2018 if (mousePressNode == mouseReleaseNode)
2019 return mouseReleaseNode;
2021 Element* mouseReleaseShadowHost = mouseReleaseNode->shadowHost();
2022 if (mouseReleaseShadowHost && mouseReleaseShadowHost == mousePressNode->shadowHost()) {
2023 // We want to dispatch the click to the shadow tree host element to give listeners the illusion that the
2024 // shadom tree is a single element. For example, we want to give the illusion that <input type="range">
2025 // is a single element even though it is a composition of multiple shadom tree elements.
2026 return mouseReleaseShadowHost;
2031 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMouseEvent)
2033 RefPtr<FrameView> protector(m_frame.view());
2035 m_frame.selection().setCaretBlinkingSuspended(false);
2037 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
2040 #if ENABLE(TOUCH_EVENTS)
2041 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
2042 if (defaultPrevented)
2046 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
2048 #if ENABLE(PAN_SCROLLING)
2049 m_autoscrollController->handleMouseReleaseEvent(platformMouseEvent);
2052 m_mousePressed = false;
2053 setLastKnownMousePosition(platformMouseEvent);
2057 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
2061 if (m_frameSetBeingResized)
2062 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, platformMouseEvent, false);
2064 // If an immediate action began or was completed using this series of mouse events, then we should send mouseup to
2065 // the DOM and return now so that we don't perform our own default behaviors.
2066 if (m_immediateActionStage == ImmediateActionStage::ActionCompleted || m_immediateActionStage == ImmediateActionStage::ActionUpdated || m_immediateActionStage == ImmediateActionStage::ActionCancelledAfterUpdate) {
2067 m_immediateActionStage = ImmediateActionStage::None;
2068 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), true, m_clickCount, platformMouseEvent, false);
2070 m_immediateActionStage = ImmediateActionStage::None;
2072 if (m_lastScrollbarUnderMouse) {
2074 m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
2075 bool cancelable = true;
2076 bool setUnder = false;
2077 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
2080 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
2081 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
2082 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
2083 if (m_eventHandlerWillResetCapturingMouseEventsElement)
2084 m_capturingMouseEventsElement = nullptr;
2085 if (subframe && passMouseReleaseEventToSubframe(mouseEvent, subframe))
2088 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
2090 bool contextMenuEvent = platformMouseEvent.button() == RightButton;
2092 Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode());
2093 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true);
2095 if (m_resizeLayer) {
2096 m_resizeLayer->setInResizeMode(false);
2097 m_resizeLayer = nullptr;
2100 bool swallowMouseReleaseEvent = false;
2101 if (!swallowMouseUpEvent)
2102 swallowMouseReleaseEvent = handleMouseReleaseEvent(mouseEvent);
2106 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2109 #if ENABLE(MOUSE_FORCE_EVENTS)
2110 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& event)
2112 RefPtr<FrameView> protector(m_frame.view());
2114 setLastKnownMousePosition(event);
2116 HitTestRequest::HitTestRequestType hitType = HitTestRequest::DisallowShadowContent | HitTestRequest::Active;
2118 HitTestRequest request(hitType);
2119 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2121 bool swallowedEvent = !dispatchMouseEvent(eventNames().webkitmouseforcechangedEvent, mouseEvent.targetNode(), false, 0, event, false);
2122 if (event.type() == PlatformEvent::MouseForceDown)
2123 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforcedownEvent, mouseEvent.targetNode(), false, 0, event, false);
2124 if (event.type() == PlatformEvent::MouseForceUp)
2125 swallowedEvent |= !dispatchMouseEvent(eventNames().webkitmouseforceupEvent, mouseEvent.targetNode(), false, 0, event, false);
2127 return swallowedEvent;
2130 bool EventHandler::handleMouseForceEvent(const PlatformMouseEvent& )
2134 #endif // #if ENABLE(MOUSE_FORCE_EVENTS)
2136 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& platformMouseEvent)
2138 // If the event was a middle click, attempt to copy global selection in after
2139 // the newly set caret position.
2141 // This code is called from either the mouse up or mouse down handling. There
2142 // is some debate about when the global selection is pasted:
2143 // xterm: pastes on up.
2144 // GTK: pastes on down.
2145 // Qt: pastes on up.
2146 // Firefox: pastes on up.
2147 // Chromium: pastes on up.
2149 // There is something of a webcompat angle to this well, as highlighted by
2150 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
2151 // down then the text is pasted just before the onclick handler runs and
2152 // clears the text box. So it's important this happens after the event
2153 // handlers have been fired.
2155 if (platformMouseEvent.type() != PlatformEvent::MousePressed)
2158 if (platformMouseEvent.type() != PlatformEvent::MouseReleased)
2162 if (!m_frame.page())
2164 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame();
2165 // Do not paste here if the focus was moved somewhere else.
2166 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection())
2167 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute();
2172 #if ENABLE(DRAG_SUPPORT)
2174 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2176 FrameView* view = m_frame.view();
2178 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2182 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2183 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2184 true, true, event.timestamp(), m_frame.document()->defaultView(),
2185 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2186 #if ENABLE(POINTER_LOCK)
2187 event.movementDelta().x(), event.movementDelta().y(),
2189 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2190 0, 0, event.force(), dataTransfer);
2192 dragTarget.dispatchEvent(me.get(), IGNORE_EXCEPTION);
2193 return me->defaultPrevented();
2196 static bool targetIsFrame(Node* target, Frame*& frame)
2198 if (!is<HTMLFrameElementBase>(target))
2201 frame = downcast<HTMLFrameElementBase>(*target).contentFrame();
2205 static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation)
2207 if (dragOperation == "copy")
2208 return DragOperationCopy;
2209 if (dragOperation == "move")
2210 return DragOperationMove;
2211 if (dragOperation == "link")
2212 return DragOperationLink;
2213 return DragOperationNone;
2216 static String convertDragOperationToDropZoneOperation(DragOperation operation)
2218 switch (operation) {
2219 case DragOperationCopy:
2220 return ASCIILiteral("copy");
2221 case DragOperationMove:
2222 return ASCIILiteral("move");
2223 case DragOperationLink:
2224 return ASCIILiteral("link");
2226 return ASCIILiteral("copy");
2230 static bool hasDropZoneType(DataTransfer& dataTransfer, const String& keyword)
2232 if (keyword.startsWith("file:"))
2233 return dataTransfer.hasFileOfType(keyword.substring(5));
2235 if (keyword.startsWith("string:"))
2236 return dataTransfer.hasStringOfType(keyword.substring(7));
2241 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
2244 Element* element = is<Element>(*target) ? downcast<Element>(target) : target->parentElement();
2245 for (; element; element = element->parentElement()) {
2246 bool matched = false;
2247 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2249 if (dropZoneStr.isEmpty())
2252 dropZoneStr = dropZoneStr.lower();
2254 SpaceSplitString keywords(dropZoneStr, false);
2255 if (keywords.isEmpty())
2258 DragOperation dragOperation = DragOperationNone;
2259 for (unsigned int i = 0; i < keywords.size(); i++) {
2260 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2261 if (op != DragOperationNone) {
2262 if (dragOperation == DragOperationNone)
2265 matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string());
2267 if (matched && dragOperation != DragOperationNone)
2271 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2278 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2280 bool accept = false;
2282 if (!m_frame.view())
2285 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2286 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2288 RefPtr<Element> newTarget;
2289 if (Node* targetNode = mouseEvent.targetNode()) {
2290 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch)
2291 if (!is<Element>(*targetNode))
2292 newTarget = targetNode->parentOrShadowHostElement();
2294 newTarget = downcast<Element>(targetNode);
2297 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2299 if (m_dragTarget != newTarget) {
2300 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2301 // it is sometimes incorrect when dragging within subframes, as seen with
2302 // LayoutTests/fast/events/drag-in-frames.html.
2304 // 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>.
2306 if (targetIsFrame(newTarget.get(), targetFrame)) {
2308 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2309 } else if (newTarget) {
2310 // 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.
2311 if (dragState().source && dragState().shouldDispatchEvents) {
2312 // for now we don't care if event handler cancels default behavior, since there is none
2313 dispatchDragSrcEvent(eventNames().dragEvent, event);
2315 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, dataTransfer);
2317 accept = findDropZone(newTarget.get(), dataTransfer);
2320 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2322 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2323 } else if (m_dragTarget)
2324 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2327 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2328 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2329 m_shouldOnlyFireDragOverEvent = true;
2333 if (targetIsFrame(newTarget.get(), targetFrame)) {
2335 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2336 } else if (newTarget) {
2337 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2338 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
2339 // for now we don't care if event handler cancels default behavior, since there is none
2340 dispatchDragSrcEvent(eventNames().dragEvent, event);
2342 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, dataTransfer);
2344 accept = findDropZone(newTarget.get(), dataTransfer);
2345 m_shouldOnlyFireDragOverEvent = false;
2348 m_dragTarget = newTarget.release();
2352 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2355 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2357 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
2358 } else if (m_dragTarget) {
2359 if (dragState().source && dragState().shouldDispatchEvents)
2360 dispatchDragSrcEvent(eventNames().dragEvent, event);
2361 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2366 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2369 bool preventedDefault = false;
2370 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2372 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
2373 } else if (m_dragTarget)
2374 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer);
2376 return preventedDefault;
2379 void EventHandler::clearDragState()
2381 stopAutoscrollTimer();
2382 m_dragTarget = nullptr;
2383 m_capturingMouseEventsElement = nullptr;
2384 m_shouldOnlyFireDragOverEvent = false;
2386 m_sendingEventToSubview = false;
2389 #endif // ENABLE(DRAG_SUPPORT)
2391 void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element)
2393 m_capturingMouseEventsElement = element;
2394 m_eventHandlerWillResetCapturingMouseEventsElement = false;
2397 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent)
2399 ASSERT(m_frame.document());
2400 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mouseEvent.position()), mouseEvent);
2403 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
2408 for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
2409 for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
2410 if (currObj1 == currObj2)
2418 static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName)
2420 for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) {
2421 if (curr->hasCapturingEventListeners(eventName))
2427 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& platformMouseEvent, bool fireMouseOverOut)
2429 Element* targetElement = nullptr;
2431 // If we're capturing, we always go right to that element.
2432 if (m_capturingMouseEventsElement)
2433 targetElement = m_capturingMouseEventsElement.get();
2434 else if (targetNode) {
2435 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646>
2436 if (!is<Element>(*targetNode))
2437 targetElement = targetNode->parentOrShadowHostElement();
2439 targetElement = downcast<Element>(targetNode);
2442 m_elementUnderMouse = targetElement;
2444 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2445 if (fireMouseOverOut) {
2446 RenderLayer* layerForLastNode = layerForNode(m_lastElementUnderMouse.get());
2447 RenderLayer* layerForNodeUnderMouse = layerForNode(m_elementUnderMouse.get());
2448 Page* page = m_frame.page();
2450 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) {
2451 // The mouse has moved between frames.
2452 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2453 if (FrameView* frameView = frame->view())
2454 frameView->mouseExitedContentArea();
2456 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2457 // The mouse has moved between layers.
2458 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2459 if (FrameView* frameView = frame->view()) {
2460 if (frameView->containsScrollableArea(layerForLastNode))
2461 layerForLastNode->mouseExitedContentArea();
2466 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) {
2467 // The mouse has moved between frames.
2468 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2469 if (FrameView* frameView = frame->view())
2470 frameView->mouseEnteredContentArea();
2472 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2473 // The mouse has moved between layers.
2474 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2475 if (FrameView* frameView = frame->view()) {
2476 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2477 layerForNodeUnderMouse->mouseEnteredContentArea();
2482 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) {
2483 m_lastElementUnderMouse = nullptr;
2484 m_lastScrollbarUnderMouse = nullptr;
2487 if (m_lastElementUnderMouse != m_elementUnderMouse) {
2488 // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor
2489 // or a normal eventhandler on the element itself (they don't bubble).
2490 // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks.
2491 bool hasCapturingMouseEnterListener = hierarchyHasCapturingEventListeners(m_elementUnderMouse.get(), eventNames().mouseenterEvent);
2492 bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent);
2494 RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr;
2495 RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr;
2496 RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer);
2498 Vector<Ref<Element>, 32> leftElementsChain;
2499 if (oldHoverRenderer) {
2500 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) {
2501 if (Element* element = curr->element())
2502 leftElementsChain.append(*element);
2505 // If the old hovered element is not null but it's renderer is, it was probably detached.
2506 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied.
2507 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement())
2508 leftElementsChain.append(*element);
2511 Vector<Ref<Element>, 32> enteredElementsChain;
2512 const Element* ancestorElement = ancestor ? ancestor->element() : nullptr;
2513 for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) {
2514 if (Element *element = curr->element()) {
2515 if (element == ancestorElement)
2517 enteredElementsChain.append(*element);
2521 // Send mouseout event to the old node.
2522 if (m_lastElementUnderMouse)
2523 m_lastElementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
2525 // Send mouseleave to the node hierarchy no longer under the mouse.
2526 for (auto& chain : leftElementsChain) {
2527 if (hasCapturingMouseLeaveListener || chain->hasEventListeners(eventNames().mouseleaveEvent))
2528 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseleaveEvent, 0, m_elementUnderMouse.get());
2531 // Send mouseover event to the new node.
2532 if (m_elementUnderMouse)
2533 m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
2535 // Send mouseleave event to the nodes hierarchy under the mouse.
2536 for (auto& chain : enteredElementsChain) {
2537 if (hasCapturingMouseEnterListener || chain->hasEventListeners(eventNames().mouseenterEvent))
2538 chain->dispatchMouseEvent(platformMouseEvent, eventNames().mouseenterEvent, 0, m_lastElementUnderMouse.get());
2541 m_lastElementUnderMouse = m_elementUnderMouse;
2545 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
2547 if (FrameView* view = m_frame.view())
2548 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2550 updateMouseEventTargetNode(targetNode, platformMouseEvent, setUnder);
2552 bool swallowEvent = false;
2554 if (m_elementUnderMouse)
2555 swallowEvent = !(m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventType, clickCount));
2557 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2559 // If clicking on a frame scrollbar, do not mess up with content focus.
2560 if (FrameView* view = m_frame.view()) {
2561 if (view->scrollbarAtPoint(platformMouseEvent.position()))
2565 // The layout needs to be up to date to determine if an element is focusable.
2566 m_frame.document()->updateLayoutIgnorePendingStylesheets();
2568 // Blur current focus node when a link/button is clicked; this
2569 // is expected by some sites that rely on onChange handlers running
2570 // from form fields before the button click is processed.
2572 Element* element = m_elementUnderMouse.get();
2574 // Walk up the DOM tree to search for an element to focus.
2576 if (element->isMouseFocusable()) {
2577 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2578 // node on mouse down if it's selected and inside a focused node. It will be
2579 // focused if the user does a mouseup over it, however, because the mouseup
2580 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2581 if (m_frame.selection().isRange()
2582 && m_frame.selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2583 && element->isDescendantOf(m_frame.document()->focusedElement()))
2588 element = element->parentOrShadowHostElement();
2591 // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node.
2592 if ((!element || !element->isMouseFocusable()) && isInsideScrollbar(platformMouseEvent.position()))
2595 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2596 // if the page already set it (e.g., by canceling default behavior).
2597 if (Page* page = m_frame.page()) {
2598 if (element && element->isMouseFocusable()) {
2599 if (!page->focusController().setFocusedElement(element, &m_frame))
2600 swallowEvent = true;
2601 } else if (!element || !element->focused()) {
2602 if (!page->focusController().setFocusedElement(0, &m_frame))
2603 swallowEvent = true;
2608 return !swallowEvent;
2611 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2613 if (RenderView* renderView = m_frame.contentRenderer()) {
2614 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2615 HitTestResult result(windowPoint);
2616 renderView->hitTest(request, result);
2617 return result.scrollbar();
2625 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2634 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, ScrollableArea*&, bool&)
2638 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event)
2640 m_frame.mainFrame().wheelEventDeltaFilter()->updateFromDelta(FloatSize(event.deltaX(), event.deltaY()));
2643 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, ScrollableArea*)
2645 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2646 FrameView* view = m_frame.view();
2648 bool didHandleEvent = view ? view->wheelEvent(event) : false;
2649 m_isHandlingWheelEvent = false;
2650 return didHandleEvent;
2653 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode*)
2658 void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, ScrollableArea*)
2664 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
2666 RenderView* renderView = m_frame.contentRenderer();
2670 RefPtr<FrameView> protector(m_frame.view());
2672 FrameView* view = m_frame.view();
2676 m_isHandlingWheelEvent = true;
2677 setFrameWasScrolledByUser();
2679 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2680 HitTestResult result(view->windowToContents(event.position()));
2681 renderView->hitTest(request, result);
2683 RefPtr<Element> element = result.innerElement();
2684 RefPtr<ContainerNode> scrollableContainer;
2685 ScrollableArea* scrollableArea = nullptr;
2686 bool isOverWidget = result.isOverWidget();
2687 platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget);
2690 if (event.phase() == PlatformWheelEventPhaseNone && event.momentumPhase() == PlatformWheelEventPhaseNone)
2691 m_frame.mainFrame().resetLatchingState();
2694 // FIXME: It should not be necessary to do this mutation here.
2695 // Instead, the handlers should know convert vertical scrolls appropriately.
2696 PlatformWheelEvent adjustedEvent = event;
2697 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, event))
2698 adjustedEvent = event.copyTurningVerticalTicksIntoHorizontalTicks();
2700 platformRecordWheelEvent(adjustedEvent);
2704 RenderElement* target = element->renderer();
2705 if (is<RenderWidget>(target)) {
2706 Widget* widget = downcast<RenderWidget>(*target).widget();
2707 if (widget && passWheelEventToWidget(event, *widget)) {
2708 m_isHandlingWheelEvent = false;
2710 scrollableArea->setScrolledProgrammatically(false);
2711 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2712 if (!widget->platformWidget())
2714 return platformCompletePlatformWidgetWheelEvent(event, *widget, 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(event, scrollableContainer.get(), scrollableArea);
2736 platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
2737 return handledEvent;
2740 void EventHandler::clearLatchedState()
2743 m_frame.mainFrame().resetLatchingState();
2745 m_frame.mainFrame().wheelEventDeltaFilter()->endFilteringDeltas();
2748 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2750 if (!startNode || !wheelEvent)
2753 FloatSize filteredPlatformDelta(wheelEvent->deltaX(), wheelEvent->deltaY());
2754 if (const PlatformWheelEvent* platformWheelEvent = wheelEvent->wheelEvent()) {
2755 filteredPlatformDelta.setWidth(platformWheelEvent->deltaX());
2756 filteredPlatformDelta.setHeight(platformWheelEvent->deltaY());
2760 ScrollLatchingState* latchedState = m_frame.mainFrame().latchingState();
2761 Element* stopElement = latchedState ? latchedState->previousWheelScrolledElement() : nullptr;
2763 if (m_frame.mainFrame().wheelEventDeltaFilter()->isFilteringDeltas())
2764 filteredPlatformDelta = m_frame.mainFrame().wheelEventDeltaFilter()->filteredDelta();
2766 Element* stopElement = nullptr;
2770 if (handleWheelEventInAppropriateEnclosingBox(startNode, wheelEvent, &stopElement, filteredPlatformDelta))
2771 wheelEvent->setDefaultHandled();
2774 if (latchedState && !latchedState->wheelEventElement())
2775 latchedState->setPreviousWheelScrolledElement(stopElement);
2779 #if ENABLE(CONTEXT_MENUS)
2780 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2782 Document* doc = m_frame.document();
2783 FrameView* v = m_frame.view();
2787 // Clear mouse press state to avoid initiating a drag while context menu is up.
2788 m_mousePressed = false;
2790 LayoutPoint viewportPos = v->windowToContents(event.position());
2791 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
2792 MouseEventWithHitTestResults mouseEvent = doc->prepareMouseEvent(request, viewportPos, event);
2794 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick()
2795 && !m_frame.selection().contains(viewportPos)
2796 && !mouseEvent.scrollbar()
2797 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2798 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2799 // available for text selections. But only if we're above text.
2800 && (m_frame.selection().selection().isContentEditable() || (mouseEvent.targetNode() && mouseEvent.targetNode()->isTextNode()))) {
2801 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2802 selectClosestContextualWordOrLinkFromMouseEvent(mouseEvent);
2805 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mouseEvent.targetNode(), true, 0, event, false);
2807 return swallowEvent;
2810 bool EventHandler::sendContextMenuEventForKey()
2812 FrameView* view = m_frame.view();
2816 Document* doc = m_frame.document();
2820 // Clear mouse press state to avoid initiating a drag while context menu is up.
2821 m_mousePressed = false;
2823 static const int kContextMenuMargin = 1;
2826 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2828 int rightAligned = 0;
2832 Element* focusedElement = doc->focusedElement();
2833 const VisibleSelection& selection = m_frame.selection().selection();
2834 Position start = selection.start();
2836 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2837 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2838 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get());
2840 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2841 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2842 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2843 location = IntPoint(x, y);
2844 } else if (focusedElement) {
2845 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2848 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2849 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2851 location = IntPoint(
2852 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2853 kContextMenuMargin);
2856 m_frame.view()->setCursor(pointerCursor());
2858 IntPoint position = view->contentsToRootView(location);
2859 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2861 Node* targetNode = doc->focusedElement();
2865 // Use the focused node as the target for hover and active.
2866 HitTestResult result(position);
2867 result.setInnerNode(targetNode);
2868 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement());
2870 // The contextmenu event is a mouse event even when invoked using the keyboard.
2871 // This is required for web compatibility.
2874 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2876 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2879 PlatformMouseEvent platformMouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime(), ForceAtClick);
2881 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, platformMouseEvent, false);
2883 #endif // ENABLE(CONTEXT_MENUS)
2885 void EventHandler::scheduleHoverStateUpdate()
2887 if (!m_hoverTimer.isActive())
2888 m_hoverTimer.startOneShot(0);
2891 #if ENABLE(CURSOR_SUPPORT)
2892 void EventHandler::scheduleCursorUpdate()
2894 if (!m_cursorUpdateTimer.isActive())
2895 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2899 void EventHandler::dispatchFakeMouseMoveEventSoon()
2901 #if !ENABLE(IOS_TOUCH_EVENTS)
2905 if (m_mousePositionIsUnknown)
2908 if (Page* page = m_frame.page()) {
2909 if (!page->chrome().client().shouldDispatchFakeMouseMoveEvents())
2913 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2914 // reschedule the timer and use a longer time. This will cause the content
2915 // to receive these moves only after the user is done scrolling, reducing
2916 // pauses during the scroll.
2917 if (m_fakeMouseMoveEventTimer.isActive())
2918 m_fakeMouseMoveEventTimer.stop();
2919 m_fakeMouseMoveEventTimer.startOneShot(m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold ? fakeMouseMoveLongInterval : fakeMouseMoveShortInterval);
2923 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2925 #if ENABLE(IOS_TOUCH_EVENTS)
2928 FrameView* view = m_frame.view();
2932 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2935 dispatchFakeMouseMoveEventSoon();
2939 #if !ENABLE(IOS_TOUCH_EVENTS)
2940 void EventHandler::cancelFakeMouseMoveEvent()
2942 m_fakeMouseMoveEventTimer.stop();
2945 void EventHandler::fakeMouseMoveEventTimerFired()
2947 ASSERT(!m_mousePressed);
2949 FrameView* view = m_frame.view();
2953 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive())
2960 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2961 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime(), 0);
2962 mouseMoved(fakeMouseMoveEvent);
2964 #endif // !ENABLE(IOS_TOUCH_EVENTS)
2966 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2968 m_frameSetBeingResized = frameSet;
2971 void EventHandler::resizeLayerDestroyed()
2973 ASSERT(m_resizeLayer);
2974 m_resizeLayer = nullptr;
2977 void EventHandler::hoverTimerFired()
2979 m_hoverTimer.stop();
2981 ASSERT(m_frame.document());
2983 if (RenderView* renderView = m_frame.contentRenderer()) {
2984 if (FrameView* view = m_frame.view()) {
2985 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
2986 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2987 renderView->hitTest(request, result);
2988 m_frame.document()->updateHoverActiveState(request, result.innerElement());
2993 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2995 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2996 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2997 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2998 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2999 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
3000 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
3002 String key = evt.unmodifiedText();
3003 Element* elem = m_frame.document()->getElementByAccessKey(key.lower());
3006 elem->accessKeyAction(false);
3011 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
3017 #if ENABLE(FULLSCREEN_API)
3018 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
3020 Document* document = m_frame.document();
3021 if (document->webkitFullScreenKeyboardInputAllowed())
3024 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3025 if (keyEvent.text().length() != 1)
3027 UChar character = keyEvent.text()[0];
3028 return character == ' ';
3031 int keyCode = keyEvent.windowsVirtualKeyCode();
3032 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3033 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3034 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3035 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3039 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3041 RefPtr<FrameView> protector(m_frame.view());
3043 #if ENABLE(FULLSCREEN_API)
3044 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
3048 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL) {
3049 if (auto* element = m_frame.document()->focusedElement()) {
3050 if (is<HTMLInputElement>(*element))
3051 downcast<HTMLInputElement>(*element).capsLockStateMayHaveChanged();
3055 #if ENABLE(PAN_SCROLLING)
3056 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) {
3057 // If a key is pressed while the panScroll is in progress then we want to stop
3058 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3059 stopAutoscrollTimer();
3061 // If we were in panscroll mode, we swallow the key event
3066 // Check for cases where we are too early for events -- possible unmatched key up
3067 // from pressing return in the location bar.
3068 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document());
3072 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
3073 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3075 if (FrameView* view = m_frame.view())
3076 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3078 // FIXME (bug 68185): this call should be made at another abstraction layer
3079 m_frame.loader().resetMultipleFormSubmissionProtection();
3081 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3082 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3083 // with access keys. Then we dispatch keydown, but suppress its default handling.
3084 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3085 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3086 bool matchedAnAccessKey = false;
3087 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3088 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3090 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3091 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3092 return !element->dispatchKeyEvent(initialKeyEvent);
3094 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3096 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3097 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3098 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3099 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3100 if (matchedAnAccessKey)
3101 keydown->setDefaultPrevented(true);
3102 keydown->setTarget(element);
3104 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3105 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
3106 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3107 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3108 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3111 // Run input method in advance of DOM event handling. This may result in the IM
3112 // modifying the page prior the keydown event, but this behaviour is necessary
3113 // in order to match IE:
3114 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3115 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3116 m_frame.editor().handleInputMethodKeydown(keydown.get());
3118 bool handledByInputMethod = keydown->defaultHandled();
3120 if (handledByInputMethod) {
3121 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3122 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3123 keydown->setTarget(element);
3124 keydown->setDefaultHandled();
3127 if (accessibilityPreventsEventPropogation(keydown.get()))
3128 keydown->stopPropagation();
3130 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
3131 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3132 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3133 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3134 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3135 return keydownResult;
3137 // Focus may have changed during keydown handling, so refetch element.
3138 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element.
3139 if (!keydownResult) {
3140 element = eventTargetElementForDocument(m_frame.document());
3145 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3146 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3147 if (keyPressEvent.text().isEmpty())
3148 return keydownResult;
3149 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView());
3150 keypress->setTarget(element);
3152 keypress->setDefaultPrevented(true);
3154 keypress->keypressCommands() = keydown->keypressCommands();
3156 element->dispatchEvent(keypress, IGNORE_EXCEPTION);
3158 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3161 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3163 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3164 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3165 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3166 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3168 FocusDirection retVal = FocusDirectionNone;
3170 if (keyIdentifier == Down)
3171 retVal = FocusDirectionDown;
3172 else if (keyIdentifier == Up)
3173 retVal = FocusDirectionUp;
3174 else if (keyIdentifier == Left)
3175 retVal = FocusDirectionLeft;
3176 else if (keyIdentifier == Right)
3177 retVal = FocusDirectionRight;
3182 static void setInitialKeyboardSelection(Frame& frame, SelectionDirection direction)
3184 Document* document = frame.document();
3188 FrameSelection& selection = frame.selection();
3190 if (!selection.isNone())
3193 Element* focusedElement = document->focusedElement();
3194 VisiblePosition visiblePosition;
3196 switch (direction) {
3197 case DirectionBackward:
3200 visiblePosition = VisiblePosition(positionBeforeNode(focusedElement));
3202 visiblePosition = endOfDocument(document);
3204 case DirectionForward:
3205 case DirectionRight:
3207 visiblePosition = VisiblePosition(positionAfterNode(focusedElement));
3209 visiblePosition = startOfDocument(document);
3213 AXTextStateChangeIntent intent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, false });
3214 selection.setSelection(visiblePosition, FrameSelection::defaultSetSelectionOptions(UserTriggered), intent);
3217 static void handleKeyboardSelectionMovement(Frame& frame, KeyboardEvent* event)
3222 FrameSelection& selection = frame.selection();
3224 bool isCommanded = event->getModifierState("Meta");
3225 bool isOptioned = event->getModifierState("Alt");
3226 bool isSelection = !selection.isNone();
3228 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3229 SelectionDirection direction = DirectionForward;
3230 TextGranularity granularity = CharacterGranularity;
3232 switch (focusDirectionForKey(event->keyIdentifier())) {
3233 case FocusDirectionNone:
3235 case FocusDirectionForward:
3236 case FocusDirectionBackward:
3237 ASSERT_NOT_REACHED();
3239 case FocusDirectionUp:
3240 direction = DirectionBackward;
3241 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3243 case FocusDirectionDown:
3244 direction = DirectionForward;
3245 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3247 case FocusDirectionLeft:
3248 direction = DirectionLeft;
3249 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3251 case FocusDirectionRight:
3252 direction = DirectionRight;
3253 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3258 selection.modify(alternation, direction, granularity, UserTriggered);
3260 setInitialKeyboardSelection(frame, direction);
3262 event->setDefaultHandled();
3265 void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent* event)
3267 if (event->type() == eventNames().keydownEvent) {
3268 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3269 handleKeyboardSelectionMovement(m_frame, event);
3273 bool EventHandler::accessibilityPreventsEventPropogation(KeyboardEvent* event)
3276 if (!AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3279 if (!m_frame.settings().preventKeyboardDOMEventDispatch())
3282 // Check for key events that are relevant to accessibility: tab and arrows keys that change focus
3283 if (event->keyIdentifier() == "U+0009")
3285 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3286 if (direction != FocusDirectionNone)
3289 UNUSED_PARAM(event);
3294 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3296 if (event->type() == eventNames().keydownEvent) {
3297 m_frame.editor().handleKeyboardEvent(event);
3298 if (event->defaultHandled())
3300 if (event->keyIdentifier() == "U+0009")
3301 defaultTabEventHandler(event);
3302 else if (event->keyIdentifier() == "U+0008")
3303 defaultBackspaceEventHandler(event);
3305 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3306 if (direction != FocusDirectionNone)
3307 defaultArrowEventHandler(direction, event);
3310 handleKeyboardSelectionMovementForAccessibility(event);
3312 if (event->type() == eventNames().keypressEvent) {
3313 m_frame.editor().handleKeyboardEvent(event);
3314 if (event->defaultHandled())
3316 if (event->charCode() == ' ')
3317 defaultSpaceEventHandler(event);
3321 #if ENABLE(DRAG_SUPPORT)
3322 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3324 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3325 return dragHysteresisExceeded(dragViewportLocation);
3328 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3330 int threshold = GeneralDragHysteresis;
3331 switch (dragState().type) {
3332 case DragSourceActionSelection:
3333 threshold = TextDragHysteresis;
3335 case DragSourceActionImage:
3336 #if ENABLE(ATTACHMENT_ELEMENT)
3337 case DragSourceActionAttachment:
3339 threshold = ImageDragHysteresis;
3341 case DragSourceActionLink:
3342 threshold = LinkDragHysteresis;
3344 case DragSourceActionDHTML:
3346 case DragSourceActionNone:
3347 case DragSourceActionAny:
3348 ASSERT_NOT_REACHED();
3351 return mouseMovementExceedsThreshold(dragViewportLocation, threshold);
3354 void EventHandler::freeDataTransfer()
3356 if (!dragState().dataTransfer)
3358 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb);
3359 dragState().dataTransfer = nullptr;
3362 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3364 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3365 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
3366 prepareMouseEvent(request, event);
3368 if (dragState().source && dragState().shouldDispatchEvents) {
3369 dragState().dataTransfer->setDestinationOperation(operation);
3370 // For now we don't care if event handler cancels default behavior, since there is no default behavior.
3371 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3374 dragState().source = nullptr;
3375 // In case the drag was ended due to an escape key press we need to ensure
3376 // that consecutive mousemove events don't reinitiate the drag and drop.
3377 m_mouseDownMayStartDrag = false;
3380 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3382 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element.
3383 if (dragState().source && !dragState().source->inDocument())
3384 dragState().source = rootEditableElement;
3387 // Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
3388 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3390 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
3393 static bool ExactlyOneBitSet(DragSourceAction n)
3395 return n && !(n & (n - 1));
3398 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3400 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3401 // If we allowed the other side of the bridge to handle a drag
3402 // last time, then m_mousePressed might still be set. So we
3403 // clear it now to make sure the next move after a drag
3404 // doesn't look like a drag.
3405 m_mousePressed = false;
3409 if (eventLoopHandleMouseDragged(event))
3412 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3414 if (m_mouseDownMayStartDrag && !dragState().source) {
3415 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML);
3417 // try to find an element that wants to be dragged
3418 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
3419 HitTestResult result(m_mouseDownPos);
3420 m_frame.contentRenderer()->hitTest(request, result);
3422 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
3424 if (!dragState().source)
3425 m_mouseDownMayStartDrag = false; // no element is draggable
3427 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection);
3430 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3431 // or else we bail on the dragging stuff and allow selection to occur
3432 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3433 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3434 if ((dragState().type & DragSourceActionImage)) {
3435 // ... unless the mouse is over an image, then we start dragging just the image
3436 dragState().type = DragSourceActionImage;
3437 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) {
3438 // ... but only bail if we're not over an unselectable element.
3439 m_mouseDownMayStartDrag = false;
3440 dragState().source = nullptr;
3441 // ... but if this was the first click in the window, we don't even want to start selection
3442 if (eventActivatedView(event.event()))
3443 m_mouseDownMayStartSelect = false;
3445 // Prevent the following case from occuring:
3446 // 1. User starts a drag immediately after mouse down over an unselectable element.
3447 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag.
3448 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet.
3449 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag.
3450 m_dragMayStartSelectionInstead = false;
3454 if (!m_mouseDownMayStartDrag)
3455 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3457 if (!ExactlyOneBitSet(dragState().type)) {
3458 ASSERT((dragState().type & DragSourceActionSelection));
3459 #if ENABLE(ATTACHMENT_ELEMENT)
3460 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3461 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3462 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionAttachment
3463 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3465 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3466 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3467 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3469 dragState().type = DragSourceActionSelection;
3472 // We are starting a text/image/url drag, so the cursor should be an arrow
3473 if (FrameView* view = m_frame.view()) {
3474 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3475 view->setCursor(pointerCursor());
3478 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3481 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3484 DragOperation srcOp = DragOperationNone;
3486 // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old dataTransfer gets numbed.
3489 dragState().dataTransfer = createDraggingDataTransfer();
3491 if (dragState().shouldDispatchEvents) {
3492 // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset.
3493 if (dragState().type == DragSourceActionDHTML) {
3494 if (RenderObject* renderer = dragState().source->renderer()) {
3495 // FIXME: This doesn't work correctly with transforms.
3496 FloatPoint absPos = renderer->localToAbsolute();
3497 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3498 dragState().dataTransfer->setDragImage(dragState().source.get(), delta.width(), delta.height());
3500 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3501 // the element in some way. In this case we just kill the drag.
3502 m_mouseDownMayStartDrag = false;
3507 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3508 && !m_frame.selection().selection().isInPasswordField();
3510 // Invalidate dataTransfer here against anymore pasteboard writing for security. The drag
3511 // image can still be changed as we drag, but not the pasteboard data.
3512 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::ImageWritable);
3514 if (m_mouseDownMayStartDrag) {
3515 // Gather values from DHTML element, if it set any.
3516 srcOp = dragState().dataTransfer->sourceOperation();
3518 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3519 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3520 // started the drag when that happens. So we have to assume it's started before we kick it off.
3521 dragState().dataTransfer->setDragHasStarted();
3525 if (m_mouseDownMayStartDrag) {
3526 Page* page = m_frame.page();
3527 m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3528 // In WebKit2 we could re-enter this code and start another drag.
3529 // On OS X this causes problems with the ownership of the pasteboard and the promised types.
3530 if (m_didStartDrag) {
3531 m_mouseDownMayStartDrag = false;
3533 cancelTrackingPotentialLongMousePress();
3536 if (dragState().source && dragState().shouldDispatchEvents) {
3537 // Drag was canned at the last minute. We owe dragSource a dragend event.
3538 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3539 m_mouseDownMayStartDrag = false;
3544 if (!m_mouseDownMayStartDrag) {
3545 // Something failed to start the drag, clean up.
3547 dragState().source = nullptr;
3550 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3553 #endif // ENABLE(DRAG_SUPPORT)
3555 bool EventHandler::mouseMovementExceedsThreshold(const FloatPoint& viewportLocation, int pointsThreshold) const
3557 FrameView* view = m_frame.view();
3560 IntPoint location = view->windowToContents(flooredIntPoint(viewportLocation));
3561 IntSize delta = location - m_mouseDownPos;
3563 return abs(delta.width()) >= pointsThreshold || abs(delta.height()) >= pointsThreshold;
3566 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3568 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3569 // and avoid dispatching text input events from keydown default handlers.
3570 ASSERT(!is<KeyboardEvent>(underlyingEvent) || downcast<KeyboardEvent>(*underlyingEvent).type() == eventNames().keypressEvent);
3572 EventTarget* target;
3573 if (underlyingEvent)
3574 target = underlyingEvent->target();
3576 target = eventTargetElementForDocument(m_frame.document());
3580 if (FrameView* view = m_frame.view())
3581 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3583 RefPtr<TextEvent> event = TextEvent::create(m_frame.document()->domWindow(), text, inputType);
3584 event->setUnderlyingEvent(underlyingEvent);
3586 target->dispatchEvent(event, IGNORE_EXCEPTION);
3587 return event->defaultHandled();
3590 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3593 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3595 && event->keyIdentifier() == "U+0009";
3598 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3600 #if PLATFORM(COCOA) || PLATFORM(EFL)
3601 return EventHandler::isKeyboardOptionTab(event);
3603 UNUSED_PARAM(event);
3608 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3610 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3612 Page* page = m_frame.page();
3616 bool tabsToLinksClientCallResult = page->chrome().client().keyboardUIMode() & KeyboardAccessTabsToLinks;
3617 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3620 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3622 if (m_frame.editor().handleTextEvent(event))
3623 event->setDefaultHandled();
3627 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3629 ASSERT(event->type() == eventNames().keypressEvent);
3631 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3634 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3635 if (logicalScrollOverflow(direction, ScrollByPage)) {
3636 event->setDefaultHandled();
3640 FrameView* view = m_frame.view();
3644 if (view->logicalScroll(direction, ScrollByPage))
3645 event->setDefaultHandled();
3648 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3650 ASSERT(event->type() == eventNames().keydownEvent);
3652 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3655 if (!m_frame.editor().behavior().shouldNavigateBackOnBackspace())
3658 Page* page = m_frame.page();
3662 if (!m_frame.settings().backspaceKeyNavigationEnabled())
3665 bool handledEvent = false;
3667 if (event->shiftKey())
3668 handledEvent = page->backForward().goForward();
3670 handledEvent = page->backForward().goBack();
3673 event->setDefaultHandled();
3677 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3679 ASSERT(event->type() == eventNames().keydownEvent);
3681 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3684 Page* page = m_frame.page();
3688 if (!isSpatialNavigationEnabled(&m_frame))
3691 // Arrows and other possible directional navigation keys can be used in design
3693 if (m_frame.document()->inDesignMode())
3696 if (page->focusController().advanceFocus(focusDirection, event))
3697 event->setDefaultHandled();
3700 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3702 ASSERT(event->type() == eventNames().keydownEvent);
3704 // We should only advance focus on tabs if no special modifier keys are held down.
3705 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3708 Page* page = m_frame.page();
3711 if (!page->tabKeyCyclesThroughElements())
3714 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3716 // Tabs can be used in design mode editing.
3717 if (m_frame.document()->inDesignMode())
3720 if (page->focusController().advanceFocus(focusDirection, event))
3721 event->setDefaultHandled();
3724 void EventHandler::sendScrollEvent()
3726 setFrameWasScrolledByUser();
3727 if (m_frame.view() && m_frame.document())
3728 m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document());
3731 void EventHandler::setFrameWasScrolledByUser()
3733 FrameView* v = m_frame.view();
3735 v->setWasScrolledByUser(true);
3738 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mouseEvent, Scrollbar* scrollbar)
3740 if (!scrollbar || !scrollbar->enabled())
3742 setFrameWasScrolledByUser();
3743 return scrollbar->mouseDown(mouseEvent.event());
3746 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3747 // last to scrollbar if setLast is true; else set last to nullptr.
3748 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3750 if (m_lastScrollbarUnderMouse.get() != scrollbar) {
3751 // Send mouse exited to the old scrollbar.
3752 if (m_lastScrollbarUnderMouse)
3753 m_lastScrollbarUnderMouse->mouseExited();
3755 // Send mouse entered if we're setting a new scrollbar.
3756 if (scrollbar && setLast)
3757 scrollbar->mouseEntered();
3759 if (setLast && scrollbar)
3760 m_lastScrollbarUnderMouse = scrollbar->createWeakPtr();
3762 m_lastScrollbarUnderMouse = nullptr;
3766 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
3767 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3770 case PlatformTouchPoint::TouchReleased:
3771 return eventNames().touchendEvent;
3772 case PlatformTouchPoint::TouchCancelled:
3773 return eventNames().touchcancelEvent;
3774 case PlatformTouchPoint::TouchPressed:
3775 return eventNames().touchstartEvent;
3776 case PlatformTouchPoint::TouchMoved:
3777 return eventNames().touchmoveEvent;
3778 case PlatformTouchPoint::TouchStationary:
3779 // TouchStationary state is not converted to touch events, so fall through to assert.
3781 ASSERT_NOT_REACHED();
3786 static HitTestResult hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3788 HitTestResult result(point);
3790 if (!frame || !frame->contentRenderer())
3793 if (frame->view()) {
3794 IntRect rect = frame->view()->visibleContentRect();
3795 if (!rect.contains(roundedIntPoint(point)))
3798 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3802 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3804 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3805 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3806 // for an overview of how these lists fit together.
3808 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3809 RefPtr<TouchList> touches = TouchList::create();
3811 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3812 // 'targetTouches' list in the JS event.
3813 typedef HashMap<EventTarget*, RefPtr<TouchList>> TargetTouchesMap;
3814 TargetTouchesMap touchesByTarget;
3816 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3817 typedef HashSet<RefPtr<EventTarget>> EventTargetSet;
3819 // The touches corresponding to the particular change state this struct instance represents.
3820 RefPtr<TouchList> m_touches;
3821 // Set of targets involved in m_touches.
3822 EventTargetSet m_targets;
3823 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3825 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3827 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
3829 bool freshTouchEvents = true;
3830 bool allTouchReleased = true;
3831 for (auto& point : points) {
3832 if (point.state() != PlatformTouchPoint::TouchPressed)
3833 freshTouchEvents = false;
3834 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3835 allTouchReleased = false;
3838 for (auto& point : points) {
3839 PlatformTouchPoint::State pointState = point.state();
3840 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3842 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3843 // The HitTestRequest types used for mouse events map quite adequately
3844 // to touch events. Note that in addition to meaning that the hit test
3845 // should affect the active state of the current node if necessary,
3846 // HitTestRequest::Active signifies that the hit test is taking place
3847 // with the mouse (or finger in this case) being pressed.
3848 switch (pointState) {
3849 case PlatformTouchPoint::TouchPressed:
3850 hitType |= HitTestRequest::Active;
3852 case PlatformTouchPoint::TouchMoved:
3853 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3855 case PlatformTouchPoint::TouchReleased:
3856 case PlatformTouchPoint::TouchCancelled:
3857 hitType |= HitTestRequest::Release;
3859 case PlatformTouchPoint::TouchStationary:
3860 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3863 ASSERT_NOT_REACHED();
3867 if (shouldGesturesTriggerActive())
3868 hitType |= HitTestRequest::ReadOnly;
3870 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3871 unsigned touchPointTargetKey = point.id() + 1;
3872 RefPtr<EventTarget> touchTarget;
3873 if (pointState == PlatformTouchPoint::TouchPressed) {
3874 HitTestResult result;
3875 if (freshTouchEvents) {
3876 result = hitTestResultAtPoint(pagePoint, hitType);
3877 m_originatingTouchPointTargetKey = touchPointTargetKey;
3878 } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) {
3879 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(*m_originatingTouchPointDocument->frame(), point.pos());
3880 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType);
3881 if (!result.innerNode())
3886 // FIXME: This code should use Element* instead of Node*.
3887 Node* node = result.innerElement();
3890 if (node && InspectorInstrumentation::handleTouchEvent(m_frame, *node))
3893 Document& doc = node->document();
3894 // Record the originating touch document even if it does not have a touch listener.
3895 if (freshTouchEvents) {
3896 m_originatingTouchPointDocument = &doc;
3897 freshTouchEvents = false;
3899 if (!doc.hasTouchEventHandlers())
3901 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3903 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3904 // No need to perform a hit-test since we only need to unset :hover and :active states.
3905 if (!shouldGesturesTriggerActive() && allTouchReleased)
3906 m_frame.document()->updateHoverActiveState(hitType, 0);
3907 if (touchPointTargetKey == m_originatingTouchPointTargetKey)
3908 m_originatingTouchPointTargetKey = 0;
3910 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3911 // we also remove it from the map.
3912 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3914 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3915 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3917 if (!touchTarget.get())
3919 Document& doc = touchTarget->toNode()->document();
3920 if (!doc.hasTouchEventHandlers())
3922 Frame* targetFrame = doc.frame();
3926 if (&m_frame != targetFrame) {
3927 // pagePoint should always be relative to the target elements containing frame.
3928 pagePoint = documentPointForWindowPoint(*targetFrame, point.pos());
3931 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor();
3933 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3934 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3936 RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3937 point.screenPos().x(), point.screenPos().y(),
3938 adjustedPageX, adjustedPageY,
3939 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3941 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3942 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3943 if (targetTouchesIterator == touchesByTarget.end())
3944 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3946 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3947 // released or cancelled it will only appear in the changedTouches list.
3948 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3949 touches->append(touch);
3950 targetTouchesIterator->value->append(touch);
3953 // Now build up the correct list for changedTouches.
3954 // Note that any touches that are in the TouchStationary state (e.g. if
3955 // the user had several points touched but did not move them all) should
3956 // never be in the changedTouches list so we do not handle them explicitly here.
3957 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3958 // about the TouchStationary state.
3959 if (pointState != PlatformTouchPoint::TouchStationary) {
3960 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3961 if (!changedTouches[pointState].m_touches)
3962 changedTouches[pointState].m_touches = TouchList::create();
3963 changedTouches[pointState].m_touches->append(touch);
3964 changedTouches[pointState].m_targets.add(touchTarget);
3967 m_touchPressed = touches->length() > 0;
3968 if (allTouchReleased)
3969 m_originatingTouchPointDocument = nullptr;
3971 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3972 bool swallowedEvent = false;
3973 RefPtr<TouchList> emptyList = TouchList::create();
3974 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3975 if (!changedTouches[state].m_touches)
3978 // When sending a touch cancel event, use empty touches and targetTouches lists.
3979 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3980 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3981 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3983 for (auto& taget : changedTouches[state].m_targets) {
3984 EventTarget* touchEventTarget = taget.get();
3985 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3986 ASSERT(targetTouches);
3988 RefPtr<TouchEvent> touchEvent =
3989 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3990 stateName, touchEventTarget->toNode()->document().defaultView(),
3991 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3992 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3993 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3997 return swallowedEvent;
3999 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
4001 #if ENABLE(TOUCH_EVENTS)
4002 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& platformMouseEvent)
4004 #if ENABLE(IOS_TOUCH_EVENTS)
4005 UNUSED_PARAM(platformMouseEvent);
4008 if (!m_frame.settings().isTouchEventEmulationEnabled())
4011 PlatformEvent::Type eventType = platformMouseEvent.type();
4012 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
4015 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
4016 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
4017 if (mouseEvent.scrollbar() || subframeForHitTestResult(mouseEvent))
4020 // The order is important. This check should follow the subframe test: http://webkit.org/b/111292.
4021 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
4024 SyntheticSingleTouchEvent touchEvent(platformMouseEvent);
4025 return handleTouchEvent(touchEvent);
4028 #endif // ENABLE(TOUCH_EVENTS)
4030 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
4032 m_mousePositionIsUnknown = false;
4033 m_lastKnownMousePosition = event.position();
4034 m_lastKnownMouseGlobalPosition = event.globalPosition();
4037 void EventHandler::setImmediateActionStage(ImmediateActionStage stage)
4039 m_immediateActionStage = stage;
4042 } // namespace WebCore