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"
122 using namespace HTMLNames;
124 #if ENABLE(DRAG_SUPPORT)
125 // The link drag hysteresis is much larger than the others because there
126 // needs to be enough space to cancel the link press without starting a link drag,
127 // and because dragging links is rare.
128 const int LinkDragHysteresis = 40;
129 const int ImageDragHysteresis = 5;
130 const int TextDragHysteresis = 3;
131 const int GeneralDragHysteresis = 3;
132 #endif // ENABLE(DRAG_SUPPORT)
134 const std::chrono::milliseconds longMousePressRecognitionDelay = std::chrono::milliseconds(500);
135 const int maximumLongMousePressDragDistance = 5; // in points.
137 #if ENABLE(IOS_GESTURE_EVENTS)
138 const float GestureUnknown = 0;
141 #if ENABLE(IOS_TOUCH_EVENTS)
142 // FIXME: Share this constant with EventHandler and SliderThumbElement.
143 const unsigned InvalidTouchIdentifier = 0;
146 // Match key code of composition keydown event on windows.
147 // IE sends VK_PROCESSKEY which has value 229;
148 const int CompositionEventKeyCode = 229;
150 using namespace SVGNames;
152 #if !ENABLE(IOS_TOUCH_EVENTS)
153 // The amount of time to wait before sending a fake mouse event, triggered
154 // during a scroll. The short interval is used if the content responds to the mouse events
155 // in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used.
156 const double fakeMouseMoveDurationThreshold = 0.01;
157 const double fakeMouseMoveShortInterval = 0.1;
158 const double fakeMouseMoveLongInterval = 0.25;
161 #if ENABLE(CURSOR_SUPPORT)
162 // The amount of time to wait for a cursor update on style and layout changes
163 // Set to 50Hz, no need to be faster than common screen refresh rate
164 const double cursorUpdateInterval = 0.02;
166 const int maximumCursorSize = 128;
169 #if ENABLE(MOUSE_CURSOR_SCALE)
170 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
171 // need to ensure here is that the scale isn't so small that integer overflow can occur when
172 // dividing cursor sizes (limited above) by the scale.
173 const double minimumCursorScale = 0.001;
176 enum NoCursorChangeType { NoCursorChange };
178 class OptionalCursor {
180 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
181 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
183 bool isCursorChange() const { return m_isCursorChange; }
184 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
187 bool m_isCursorChange;
191 class MaximumDurationTracker {
193 explicit MaximumDurationTracker(double *maxDuration)
194 : m_maxDuration(maxDuration)
195 , m_start(monotonicallyIncreasingTime())
199 ~MaximumDurationTracker()
201 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
205 double* m_maxDuration;
209 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
210 class SyntheticTouchPoint : public PlatformTouchPoint {
213 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
214 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
216 const static int idDefaultValue = 0;
217 const static int radiusYDefaultValue = 1;
218 const static int radiusXDefaultValue = 1;
219 const static float rotationAngleDefaultValue = 0.0f;
220 const static float forceDefaultValue = 1.0f;
222 m_id = idDefaultValue; // There is only one active TouchPoint.
223 m_screenPos = event.globalPosition();
224 m_pos = event.position();
225 m_radiusY = radiusYDefaultValue;
226 m_radiusX = radiusXDefaultValue;
227 m_rotationAngle = rotationAngleDefaultValue;
228 m_force = forceDefaultValue;
230 PlatformEvent::Type type = event.type();
231 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
234 case PlatformEvent::MouseMoved:
235 m_state = TouchMoved;
237 case PlatformEvent::MousePressed:
238 m_state = TouchPressed;
240 case PlatformEvent::MouseReleased:
241 m_state = TouchReleased;
244 ASSERT_NOT_REACHED();
250 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
252 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
254 switch (event.type()) {
255 case PlatformEvent::MouseMoved:
258 case PlatformEvent::MousePressed:
261 case PlatformEvent::MouseReleased:
265 ASSERT_NOT_REACHED();
269 m_timestamp = event.timestamp();
270 m_modifiers = event.modifiers();
271 m_touchPoints.append(SyntheticTouchPoint(event));
274 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
276 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
279 case WheelEvent::DOM_DELTA_PAGE:
281 case WheelEvent::DOM_DELTA_LINE:
283 case WheelEvent::DOM_DELTA_PIXEL:
284 return ScrollByPixel;
286 return ScrollByPixel;
290 static inline bool didScrollInScrollableAreaForSingleAxis(ScrollableArea* scrollableArea, WheelEvent* wheelEvent, ScrollEventAxis axis)
292 float delta = axis == ScrollEventAxis::Vertical ? wheelEvent->deltaY() : wheelEvent->deltaX();
293 ScrollDirection negativeDirection = axis == ScrollEventAxis::Vertical ? ScrollUp : ScrollLeft;
294 ScrollDirection positiveDirection = axis == ScrollEventAxis::Vertical ? ScrollDown : ScrollRight;
295 return scrollableArea->scroll(delta < 0 ? negativeDirection : positiveDirection, wheelGranularityToScrollGranularity(wheelEvent->deltaMode()), delta > 0 ? delta : -delta);
298 static inline bool handleWheelEventInAppropriateEnclosingBoxForSingleAxis(Node* startNode, WheelEvent* wheelEvent, Element** stopElement, ScrollEventAxis axis)
300 bool shouldHandleEvent = (axis == ScrollEventAxis::Vertical && wheelEvent->deltaY()) || (axis == ScrollEventAxis::Horizontal && wheelEvent->deltaX());
302 shouldHandleEvent |= wheelEvent->phase() == PlatformWheelEventPhaseEnded;
303 #if ENABLE(CSS_SCROLL_SNAP)
304 shouldHandleEvent |= wheelEvent->momentumPhase() == PlatformWheelEventPhaseEnded;
307 if (!startNode->renderer() || !shouldHandleEvent)
310 RenderBox& initialEnclosingBox = startNode->renderer()->enclosingBox();
311 if (initialEnclosingBox.isListBox())
312 return didScrollInScrollableAreaForSingleAxis(static_cast<RenderListBox*>(&initialEnclosingBox), wheelEvent, axis);
314 RenderBox* currentEnclosingBox = &initialEnclosingBox;
315 while (currentEnclosingBox) {
316 if (RenderLayer* boxLayer = currentEnclosingBox->layer()) {
317 const PlatformWheelEvent* platformEvent = wheelEvent->wheelEvent();
318 bool scrollingWasHandled;
319 if (platformEvent != nullptr)
320 scrollingWasHandled = boxLayer->handleWheelEvent(axis == ScrollEventAxis::Vertical ? platformEvent->copyIgnoringHorizontalDelta() : platformEvent->copyIgnoringVerticalDelta());
322 scrollingWasHandled = didScrollInScrollableAreaForSingleAxis(boxLayer, wheelEvent, axis);
324 if (scrollingWasHandled) {
326 *stopElement = currentEnclosingBox->element();
331 if (stopElement && *stopElement && *stopElement == currentEnclosingBox->element())
334 currentEnclosingBox = currentEnclosingBox->containingBlock();
335 if (currentEnclosingBox && currentEnclosingBox->isRenderNamedFlowThread())
336 currentEnclosingBox = RenderNamedFlowThread::fragmentFromRenderBoxAsRenderBlock(currentEnclosingBox, roundedIntPoint(wheelEvent->absoluteLocation()), initialEnclosingBox);
337 if (!currentEnclosingBox || currentEnclosingBox->isRenderView())
343 #if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS))
344 static inline bool shouldGesturesTriggerActive()
346 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
347 // rely on them to set the active state. Unfortunately there's no generic way to
348 // know in advance what event types are supported.
355 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
360 #if ENABLE(DRAG_SUPPORT)
361 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
369 EventHandler::EventHandler(Frame& frame)
371 , m_mousePressed(false)
372 , m_capturesDragging(false)
373 , m_mouseDownMayStartSelect(false)
374 #if ENABLE(DRAG_SUPPORT)
375 , m_mouseDownMayStartDrag(false)
376 , m_dragMayStartSelectionInstead(false)
378 , m_mouseDownWasSingleClickInSelection(false)
379 , m_selectionInitiationState(HaveNotStartedSelection)
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_didRecognizeLongMousePress(false)
386 , m_autoscrollController(std::make_unique<AutoscrollController>())
387 , m_mouseDownMayStartAutoscroll(false)
388 , m_mouseDownWasInSubframe(false)
389 #if !ENABLE(IOS_TOUCH_EVENTS)
390 , m_fakeMouseMoveEventTimer(*this, &EventHandler::fakeMouseMoveEventTimerFired)
394 , m_eventHandlerWillResetCapturingMouseEventsElement(nullptr)
396 #if ENABLE(IOS_GESTURE_EVENTS)
397 , m_gestureInitialDiameter(GestureUnknown)
398 , m_gestureLastDiameter(GestureUnknown)
399 , m_gestureInitialRotation(GestureUnknown)
400 , m_gestureLastRotation(GestureUnknown)
402 #if ENABLE(IOS_TOUCH_EVENTS)
403 , m_firstTouchID(InvalidTouchIdentifier)
405 , m_mousePositionIsUnknown(true)
406 , m_mouseDownTimestamp(0)
408 , m_mouseDownView(nil)
409 , m_sendingEventToSubview(false)
411 , m_activationEventNumber(-1)
412 #endif // !PLATFORM(IOS)
414 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
415 , m_originatingTouchPointTargetKey(0)
416 , m_touchPressed(false)
418 , m_maxMouseMovedDuration(0)
419 , m_baseEventType(PlatformEvent::NoType)
420 , m_didStartDrag(false)
421 , m_didLongPressInvokeContextMenu(false)
422 , m_isHandlingWheelEvent(false)
423 #if ENABLE(CURSOR_VISIBILITY)
424 , m_autoHideCursorTimer(*this, &EventHandler::autoHideCursorTimerFired)
429 EventHandler::~EventHandler()
431 #if !ENABLE(IOS_TOUCH_EVENTS)
432 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
434 #if ENABLE(CURSOR_VISIBILITY)
435 ASSERT(!m_autoHideCursorTimer.isActive());
439 #if ENABLE(DRAG_SUPPORT)
440 DragState& EventHandler::dragState()
442 DEPRECATED_DEFINE_STATIC_LOCAL(DragState, state, ());
445 #endif // ENABLE(DRAG_SUPPORT)
447 void EventHandler::clear()
450 #if ENABLE(CURSOR_SUPPORT)
451 m_cursorUpdateTimer.stop();
453 #if !ENABLE(IOS_TOUCH_EVENTS)
454 m_fakeMouseMoveEventTimer.stop();
456 #if ENABLE(CURSOR_VISIBILITY)
457 cancelAutoHideCursorTimer();
459 clearLongMousePressState();
460 m_resizeLayer = nullptr;
461 m_elementUnderMouse = nullptr;
462 m_lastElementUnderMouse = nullptr;
463 m_lastMouseMoveEventSubframe = nullptr;
464 m_lastScrollbarUnderMouse = nullptr;
466 m_clickNode = nullptr;
467 #if ENABLE(IOS_GESTURE_EVENTS)
468 m_gestureInitialDiameter = GestureUnknown;
469 m_gestureLastDiameter = GestureUnknown;
470 m_gestureInitialRotation = GestureUnknown;
471 m_gestureLastRotation = GestureUnknown;
472 m_gestureTargets.clear();
474 #if ENABLE(IOS_TOUCH_EVENTS)
476 m_firstTouchID = InvalidTouchIdentifier;
477 m_touchEventTargetSubframe = nullptr;
479 m_frameSetBeingResized = nullptr;
480 #if ENABLE(DRAG_SUPPORT)
481 m_dragTarget = nullptr;
482 m_shouldOnlyFireDragOverEvent = false;
484 m_mousePositionIsUnknown = true;
485 m_lastKnownMousePosition = IntPoint();
486 m_lastKnownMouseGlobalPosition = IntPoint();
487 m_mousePressNode = 0;
488 m_mousePressed = false;
489 m_capturesDragging = false;
490 m_capturingMouseEventsElement = nullptr;
492 m_frame.mainFrame().resetLatchingState();
494 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
495 m_originatingTouchPointTargets.clear();
496 m_originatingTouchPointDocument.clear();
497 m_originatingTouchPointTargetKey = 0;
499 m_maxMouseMovedDuration = 0;
500 m_baseEventType = PlatformEvent::NoType;
501 m_didStartDrag = false;
502 m_didLongPressInvokeContextMenu = false;
505 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
507 if (nodeToBeRemoved.contains(m_clickNode.get()))
508 m_clickNode = nullptr;
511 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
513 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection))
514 selection.setSelection(newSelection);
517 static inline bool dispatchSelectStart(Node* node)
519 if (!node || !node->renderer())
522 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
525 static Node* nodeToSelectOnMouseDownForNode(Node& targetNode)
527 #if ENABLE(USERSELECT_ALL)
528 if (Node* rootUserSelectAll = Position::rootUserSelectAllForNode(&targetNode))
529 return rootUserSelectAll;
532 if (targetNode.shouldSelectOnMouseDown())
538 static VisibleSelection expandSelectionToRespectSelectOnMouseDown(Node& targetNode, const VisibleSelection& selection)
540 Node* nodeToSelect = nodeToSelectOnMouseDownForNode(targetNode);
544 VisibleSelection newSelection(selection);
545 newSelection.setBase(positionBeforeNode(nodeToSelect).upstream(CanCrossEditingBoundary));
546 newSelection.setExtent(positionAfterNode(nodeToSelect).downstream(CanCrossEditingBoundary));
551 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
553 if (Position::nodeIsUserSelectNone(targetNode))
556 if (!dispatchSelectStart(targetNode))
559 if (selection.isRange())
560 m_selectionInitiationState = ExtendedSelection;
562 granularity = CharacterGranularity;
563 m_selectionInitiationState = PlacedCaret;
566 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity);
571 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
573 Node* targetNode = result.targetNode();
574 VisibleSelection newSelection;
576 if (targetNode && targetNode->renderer()) {
577 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
578 if (pos.isNotNull()) {
579 newSelection = VisibleSelection(pos);
580 newSelection.expandUsingGranularity(WordGranularity);
583 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
584 newSelection.appendTrailingWhitespace();
586 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
590 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
592 if (m_mouseDownMayStartSelect) {
593 selectClosestWordFromHitTestResult(result.hitTestResult(),
594 (result.event().clickCount() == 2 && m_frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
598 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
600 if (!result.hitTestResult().isLiveLink())
601 return selectClosestWordFromMouseEvent(result);
603 Node* targetNode = result.targetNode();
605 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) {
606 VisibleSelection newSelection;
607 Element* URLElement = result.hitTestResult().URLElement();
608 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint(), nullptr));
609 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
610 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
612 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), WordGranularity);
616 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
618 if (event.event().button() != LeftButton)
621 if (m_frame.selection().isRange())
622 // A double-click when range is already selected
623 // should not change the selection. So, do not call
624 // selectClosestWordFromMouseEvent, but do set
625 // m_beganSelectingText to prevent handleMouseReleaseEvent
626 // from setting caret selection.
627 m_selectionInitiationState = ExtendedSelection;
629 selectClosestWordFromMouseEvent(event);
634 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
636 if (event.event().button() != LeftButton)
639 Node* targetNode = event.targetNode();
640 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
643 VisibleSelection newSelection;
644 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
645 if (pos.isNotNull()) {
646 newSelection = VisibleSelection(pos);
647 newSelection.expandUsingGranularity(ParagraphGranularity);
650 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectSelectOnMouseDown(*targetNode, newSelection), ParagraphGranularity);
653 static int textDistance(const Position& start, const Position& end)
655 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
656 return TextIterator::rangeLength(range.get(), true);
659 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
661 m_frame.document()->updateLayoutIgnorePendingStylesheets();
662 Node* targetNode = event.targetNode();
663 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
666 // Extend the selection if the Shift key is down, unless the click is in a link.
667 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
669 // Don't restart the selection when the mouse is pressed on an
670 // existing selection so we can allow for text dragging.
671 if (FrameView* view = m_frame.view()) {
672 LayoutPoint vPoint = view->windowToContents(event.event().position());
673 if (!extendSelection && m_frame.selection().contains(vPoint)) {
674 m_mouseDownWasSingleClickInSelection = true;
679 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint(), nullptr));
680 if (visiblePos.isNull())
681 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM);
682 Position pos = visiblePos.deepEquivalent();
684 VisibleSelection newSelection = m_frame.selection().selection();
685 TextGranularity granularity = CharacterGranularity;
687 if (extendSelection && newSelection.isCaretOrRange()) {
688 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectSelectOnMouseDown(*targetNode, VisibleSelection(pos));
689 if (selectionInUserSelectAll.isRange()) {
690 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
691 pos = selectionInUserSelectAll.start();
692 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
693 pos = selectionInUserSelectAll.end();
696 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) {
697 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
698 // was created right-to-left
699 Position start = newSelection.start();
700 Position end = newSelection.end();
701 int distanceToStart = textDistance(start, pos);
702 int distanceToEnd = textDistance(pos, end);
703 if (distanceToStart <= distanceToEnd)
704 newSelection = VisibleSelection(end, pos);
706 newSelection = VisibleSelection(start, pos);
708 newSelection.setExtent(pos);
710 if (m_frame.selection().granularity() != CharacterGranularity) {
711 granularity = m_frame.selection().granularity();
712 newSelection.expandUsingGranularity(m_frame.selection().granularity());
715 newSelection = expandSelectionToRespectSelectOnMouseDown(*targetNode, visiblePos);
717 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity);
719 if (event.event().button() == MiddleButton) {
720 // Ignore handled, since we want to paste to where the caret was placed anyway.
721 handled = handlePasteGlobalSelection(event.event()) || handled;
726 static inline bool canMouseDownStartSelect(Node* node)
728 if (!node || !node->renderer())
731 return node->canStartSelection() || Position::nodeIsUserSelectAll(node);
734 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
736 #if ENABLE(DRAG_SUPPORT)
738 dragState().source = nullptr;
741 #if !ENABLE(IOS_TOUCH_EVENTS)
742 cancelFakeMouseMoveEvent();
745 m_frame.document()->updateLayoutIgnorePendingStylesheets();
747 if (ScrollView* scrollView = m_frame.view()) {
748 if (scrollView->isPointInScrollbarCorner(event.event().position()))
752 bool singleClick = event.event().clickCount() <= 1;
754 // If we got the event back, that must mean it wasn't prevented,
755 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
756 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
758 #if ENABLE(DRAG_SUPPORT)
759 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
760 m_mouseDownMayStartDrag = singleClick;
763 m_mouseDownWasSingleClickInSelection = false;
765 m_mouseDown = event.event();
767 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
770 if (is<SVGDocument>(*m_frame.document()) && downcast<SVGDocument>(*m_frame.document()).zoomAndPanEnabled()) {
771 if (event.event().shiftKey() && singleClick) {
773 downcast<SVGDocument>(*m_frame.document()).startPan(m_frame.view()->windowToContents(event.event().position()));
778 if (event.event().button() == LeftButton && event.isOverLink()) {
779 // FIXME 135703: Handle long press for more than just links.
780 beginTrackingPotentialLongMousePress(event.hitTestResult());
783 // We don't do this at the start of mouse down handling,
784 // because we don't want to do it until we know we didn't hit a widget.
788 m_mousePressNode = event.targetNode();
789 #if ENABLE(DRAG_SUPPORT)
790 m_dragStartPos = event.event().position();
793 bool swallowEvent = false;
794 m_mousePressed = true;
795 m_selectionInitiationState = HaveNotStartedSelection;
797 if (event.event().clickCount() == 2)
798 swallowEvent = handleMousePressEventDoubleClick(event);
799 else if (event.event().clickCount() >= 3)
800 swallowEvent = handleMousePressEventTripleClick(event);
802 swallowEvent = handleMousePressEventSingleClick(event);
804 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
805 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
810 #if ENABLE(DRAG_SUPPORT)
811 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
816 if (handleDrag(event, ShouldCheckDragHysteresis))
819 Node* targetNode = event.targetNode();
820 if (event.event().button() != LeftButton || !targetNode)
823 RenderObject* renderer = targetNode->renderer();
825 Element* parent = targetNode->parentOrShadowHostElement();
829 renderer = parent->renderer();
830 if (!renderer || !renderer->isListBox())
834 #if PLATFORM(COCOA) // FIXME: Why does this assertion fire on other platforms?
835 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
838 m_mouseDownMayStartDrag = false;
840 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
841 m_autoscrollController->startAutoscrollForSelection(renderer);
842 m_mouseDownMayStartAutoscroll = false;
845 if (m_selectionInitiationState != ExtendedSelection) {
846 HitTestResult result(m_mouseDownPos);
847 m_frame.document()->renderView()->hitTest(HitTestRequest(), result);
849 updateSelectionForMouseDrag(result);
851 updateSelectionForMouseDrag(event.hitTestResult());
855 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
857 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
858 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
859 // in handleMousePressEvent
860 RenderView* renderView = m_frame.contentRenderer();
864 if (event.button() != LeftButton || event.clickCount() != 1)
867 if (m_didRecognizeLongMousePress)
870 FrameView* view = m_frame.view();
874 Page* page = m_frame.page();
878 updateDragSourceActionsAllowed();
879 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
880 HitTestResult result(view->windowToContents(event.position()));
881 renderView->hitTest(request, result);
883 return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
886 void EventHandler::updateSelectionForMouseDrag()
888 FrameView* view = m_frame.view();
891 RenderView* renderView = m_frame.contentRenderer();
895 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
896 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
897 renderView->hitTest(request, result);
898 updateSelectionForMouseDrag(result);
901 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
903 FloatPoint selectionEndPoint = localPoint;
904 Element* editableElement = selection.rootEditableElement();
906 if (!targetNode->renderer())
907 return VisiblePosition();
909 if (editableElement && !editableElement->contains(targetNode)) {
910 if (!editableElement->renderer())
911 return VisiblePosition();
913 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
914 selectionEndPoint = editableElement->renderer()->absoluteToLocal(absolutePoint);
915 targetNode = editableElement;
918 return targetNode->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr);
921 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
923 if (!m_mouseDownMayStartSelect)
926 Node* target = hitTestResult.targetNode();
930 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target);
932 // Don't modify the selection if we're not on a node.
933 if (targetPosition.isNull())
936 // Restart the selection if this is the first mouse move. This work is usually
937 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
938 VisibleSelection newSelection = m_frame.selection().selection();
940 // Special case to limit selection to the containing block for SVG text.
941 // FIXME: Isn't there a better non-SVG-specific way to do this?
942 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
943 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
944 if (selectionBaseRenderer->isSVGText())
945 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
948 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
951 if (m_selectionInitiationState != ExtendedSelection) {
952 // Always extend selection here because it's caused by a mouse drag
953 m_selectionInitiationState = ExtendedSelection;
954 newSelection = VisibleSelection(targetPosition);
957 #if ENABLE(USERSELECT_ALL)
958 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
959 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
960 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
961 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
963 // Reset base for user select all when base is inside user-select-all area and extent < base.
964 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
965 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
967 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
968 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint(), nullptr), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos, nullptr)) < 0)
969 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
970 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
971 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
973 newSelection.setExtent(targetPosition);
976 newSelection.setExtent(targetPosition);
979 if (m_frame.selection().granularity() != CharacterGranularity)
980 newSelection.expandUsingGranularity(m_frame.selection().granularity());
982 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
983 FrameSelection::AdjustEndpointsAtBidiBoundary);
985 #endif // ENABLE(DRAG_SUPPORT)
987 void EventHandler::lostMouseCapture()
989 m_frame.selection().setCaretBlinkingSuspended(false);
992 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
994 if (eventLoopHandleMouseUp(event))
997 // If this was the first click in the window, we don't even want to clear the selection.
998 // This case occurs when the user clicks on a draggable element, since we have to process
999 // the mouse down and drag events to see if we might start a drag. For other first clicks
1000 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
1001 // ignored upstream of this layer.
1002 return eventActivatedView(event.event());
1005 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1007 if (autoscrollInProgress())
1008 stopAutoscrollTimer();
1010 if (handleMouseUp(event))
1013 // Used to prevent mouseMoveEvent from initiating a drag before
1014 // the mouse is pressed again.
1015 m_mousePressed = false;
1016 m_capturesDragging = false;
1017 #if ENABLE(DRAG_SUPPORT)
1018 m_mouseDownMayStartDrag = false;
1020 m_mouseDownMayStartSelect = false;
1021 m_mouseDownMayStartAutoscroll = false;
1022 m_mouseDownWasInSubframe = false;
1024 bool handled = false;
1026 if (event.event().button() == LeftButton) {
1027 // FIXME 135767: Implement long mouse press for arbitrary mouse buttons.
1028 clearLongMousePressState();
1031 // Clear the selection if the mouse didn't move after the last mouse
1032 // press and it's not a context menu click. We do this so when clicking
1033 // on the selection, the selection goes away. However, if we are
1034 // editing, place the caret.
1035 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
1036 #if ENABLE(DRAG_SUPPORT)
1037 && m_dragStartPos == event.event().position()
1039 && m_frame.selection().isRange()
1040 && event.event().button() != RightButton) {
1041 VisibleSelection newSelection;
1042 Node* node = event.targetNode();
1043 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
1044 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
1045 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint(), nullptr);
1046 newSelection = VisibleSelection(pos);
1049 setSelectionIfNeeded(m_frame.selection(), newSelection);
1054 if (event.event().button() == MiddleButton) {
1055 // Ignore handled, since we want to paste to where the caret was placed anyway.
1056 handled = handlePasteGlobalSelection(event.event()) || handled;
1062 #if ENABLE(PAN_SCROLLING)
1064 void EventHandler::didPanScrollStart()
1066 m_autoscrollController->didPanScrollStart();
1069 void EventHandler::didPanScrollStop()
1071 m_autoscrollController->didPanScrollStop();
1074 void EventHandler::startPanScrolling(RenderElement* renderer)
1077 if (!is<RenderBox>(*renderer))
1079 m_autoscrollController->startPanScrolling(downcast<RenderBox>(renderer), lastKnownMousePosition());
1084 #endif // ENABLE(PAN_SCROLLING)
1086 RenderBox* EventHandler::autoscrollRenderer() const
1088 return m_autoscrollController->autoscrollRenderer();
1091 void EventHandler::updateAutoscrollRenderer()
1093 m_autoscrollController->updateAutoscrollRenderer();
1096 bool EventHandler::autoscrollInProgress() const
1098 return m_autoscrollController->autoscrollInProgress();
1101 bool EventHandler::panScrollInProgress() const
1103 return m_autoscrollController->panScrollInProgress();
1106 #if ENABLE(DRAG_SUPPORT)
1107 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1109 Page* page = m_frame.page();
1111 return DragSourceActionNone;
1113 FrameView* view = m_frame.view();
1115 return DragSourceActionNone;
1117 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1119 #endif // ENABLE(DRAG_SUPPORT)
1121 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1123 // We always send hitTestResultAtPoint to the main frame if we have one,
1124 // otherwise we might hit areas that are obscured by higher frames.
1125 if (!m_frame.isMainFrame()) {
1126 Frame& mainFrame = m_frame.mainFrame();
1127 FrameView* frameView = m_frame.view();
1128 FrameView* mainView = mainFrame.view();
1129 if (frameView && mainView) {
1130 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
1131 return mainFrame.eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
1135 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
1137 RenderView* renderView = m_frame.contentRenderer();
1141 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
1142 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
1143 renderView->hitTest(request, result);
1144 if (!request.readOnly())
1145 m_frame.document()->updateHoverActiveState(request, result.innerElement());
1147 if (request.disallowsShadowContent())
1148 result.setToNonShadowAncestor();
1153 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1155 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed);
1158 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1160 Node* node = startingNode;
1163 node = m_frame.document()->focusedElement();
1166 node = m_mousePressNode.get();
1169 auto r = node->renderer();
1170 if (r && !r->isListBox() && r->enclosingBox().scroll(direction, granularity)) {
1171 setFrameWasScrolledByUser();
1179 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1181 Node* node = startingNode;
1184 node = m_frame.document()->focusedElement();
1187 node = m_mousePressNode.get();
1190 auto r = node->renderer();
1191 if (r && !r->isListBox() && r->enclosingBox().logicalScroll(direction, granularity)) {
1192 setFrameWasScrolledByUser();
1200 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1202 // The layout needs to be up to date to determine if we can scroll. We may be
1203 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1204 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1205 if (scrollOverflow(direction, granularity, startingNode))
1207 Frame* frame = &m_frame;
1208 FrameView* view = frame->view();
1209 if (view && view->scroll(direction, granularity))
1211 frame = frame->tree().parent();
1214 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement());
1217 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1219 // The layout needs to be up to date to determine if we can scroll. We may be
1220 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1221 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1222 if (logicalScrollOverflow(direction, granularity, startingNode))
1224 Frame* frame = &m_frame;
1225 FrameView* view = frame->view();
1227 bool scrolled = false;
1229 // Mac also resets the scroll position in the inline direction.
1230 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1233 if (view && view->logicalScroll(direction, granularity))
1239 frame = frame->tree().parent();
1243 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement());
1246 IntPoint EventHandler::lastKnownMousePosition() const
1248 return m_lastKnownMousePosition;
1251 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1253 if (!hitTestResult.isOverWidget())
1255 return subframeForTargetNode(hitTestResult.targetNode());
1258 Frame* EventHandler::subframeForTargetNode(Node* node)
1263 auto renderer = node->renderer();
1264 if (!is<RenderWidget>(renderer))
1267 Widget* widget = downcast<RenderWidget>(*renderer).widget();
1268 if (!is<FrameView>(widget))
1271 return &downcast<FrameView>(*widget).frame();
1274 #if ENABLE(CURSOR_SUPPORT)
1275 static bool isSubmitImage(Node* node)
1277 return is<HTMLInputElement>(node) && downcast<HTMLInputElement>(*node).isImageButton();
1280 // Returns true if the node's editable block is not current focused for editing
1281 static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame)
1283 return frame.selection().selection().rootEditableElement() != node.rootEditableElement();
1286 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1291 bool editable = node->hasEditableStyle();
1292 bool editableLinkEnabled = false;
1294 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1296 switch (m_frame.settings().editableLinkBehavior()) {
1298 case EditableLinkDefaultBehavior:
1299 case EditableLinkAlwaysLive:
1300 editableLinkEnabled = true;
1303 case EditableLinkNeverLive:
1304 editableLinkEnabled = false;
1307 case EditableLinkLiveWhenNotFocused:
1308 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey;
1311 case EditableLinkOnlyLiveWithShiftKey:
1312 editableLinkEnabled = shiftKey;
1317 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1320 void EventHandler::cursorUpdateTimerFired()
1322 ASSERT(m_frame.document());
1326 void EventHandler::updateCursor()
1328 if (m_mousePositionIsUnknown)
1331 FrameView* view = m_frame.view();
1335 RenderView* renderView = view->renderView();
1339 if (!view->shouldSetCursor())
1346 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1348 HitTestRequest request(HitTestRequest::ReadOnly);
1349 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1350 renderView->hitTest(request, result);
1352 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1353 if (optionalCursor.isCursorChange()) {
1354 m_currentMouseCursor = optionalCursor.cursor();
1355 view->setCursor(m_currentMouseCursor);
1359 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1361 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1362 return NoCursorChange;
1364 if (!m_frame.page())
1365 return NoCursorChange;
1367 #if ENABLE(PAN_SCROLLING)
1368 if (m_frame.mainFrame().eventHandler().panScrollInProgress())
1369 return NoCursorChange;
1372 Node* node = result.targetNode();
1374 return NoCursorChange;
1376 auto renderer = node->renderer();
1377 RenderStyle* style = renderer ? &renderer->style() : nullptr;
1378 bool horizontalText = !style || style->isHorizontalWritingMode();
1379 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1381 #if ENABLE(CURSOR_VISIBILITY)
1382 if (style && style->cursorVisibility() == CursorVisibilityAutoHide)
1383 startAutoHideCursorTimer();
1385 cancelAutoHideCursorTimer();
1389 Cursor overrideCursor;
1390 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1391 case SetCursorBasedOnStyle:
1394 return overrideCursor;
1395 case DoNotSetCursor:
1396 return NoCursorChange;
1400 if (style && style->cursors()) {
1401 const CursorList* cursors = style->cursors();
1402 for (unsigned i = 0; i < cursors->size(); ++i) {
1403 StyleImage* styleImage = (*cursors)[i].image();
1406 CachedImage* cachedImage = styleImage->cachedImage();
1409 float scale = styleImage->imageScaleFactor();
1410 // Get hotspot and convert from logical pixels to physical pixels.
1411 IntPoint hotSpot = (*cursors)[i].hotSpot();
1412 hotSpot.scale(scale, scale);
1413 FloatSize size = cachedImage->imageForRenderer(renderer)->size();
1414 if (cachedImage->errorOccurred())
1416 // Limit the size of cursors (in UI pixels) so that they cannot be
1417 // used to cover UI elements in chrome.
1418 size.scale(1 / scale);
1419 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1422 Image* image = cachedImage->imageForRenderer(renderer);
1423 #if ENABLE(MOUSE_CURSOR_SCALE)
1424 // Ensure no overflow possible in calculations above.
1425 if (scale < minimumCursorScale)
1427 return Cursor(image, hotSpot, scale);
1430 return Cursor(image, hotSpot);
1431 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1435 // During selection, use an I-beam regardless of the content beneath the cursor.
1436 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1438 && m_mouseDownMayStartSelect
1439 #if ENABLE(DRAG_SUPPORT)
1440 && !m_mouseDownMayStartDrag
1442 && m_frame.selection().isCaretOrRange()
1443 && !m_capturingMouseEventsElement)
1446 switch (style ? style->cursor() : CursorAuto) {
1448 bool editable = node->hasEditableStyle();
1450 if (useHandCursor(node, result.isOverLink(), shiftKey))
1451 return handCursor();
1453 bool inResizer = false;
1455 if (RenderLayer* layer = renderer->enclosingLayer()) {
1456 if (FrameView* view = m_frame.view())
1457 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1461 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1463 return pointerCursor();
1466 return crossCursor();
1468 return handCursor();
1470 return moveCursor();
1471 case CursorAllScroll:
1472 return moveCursor();
1474 return eastResizeCursor();
1476 return westResizeCursor();
1478 return northResizeCursor();
1480 return southResizeCursor();
1481 case CursorNeResize:
1482 return northEastResizeCursor();
1483 case CursorSwResize:
1484 return southWestResizeCursor();
1485 case CursorNwResize:
1486 return northWestResizeCursor();
1487 case CursorSeResize:
1488 return southEastResizeCursor();
1489 case CursorNsResize:
1490 return northSouthResizeCursor();
1491 case CursorEwResize:
1492 return eastWestResizeCursor();
1493 case CursorNeswResize:
1494 return northEastSouthWestResizeCursor();
1495 case CursorNwseResize:
1496 return northWestSouthEastResizeCursor();
1497 case CursorColResize:
1498 return columnResizeCursor();
1499 case CursorRowResize:
1500 return rowResizeCursor();
1502 return iBeamCursor();
1504 return waitCursor();
1506 return helpCursor();
1507 case CursorVerticalText:
1508 return verticalTextCursor();
1510 return cellCursor();
1511 case CursorContextMenu:
1512 return contextMenuCursor();
1513 case CursorProgress:
1514 return progressCursor();
1516 return noDropCursor();
1518 return aliasCursor();
1520 return copyCursor();
1522 return noneCursor();
1523 case CursorNotAllowed:
1524 return notAllowedCursor();
1526 return pointerCursor();
1528 return zoomInCursor();
1530 return zoomOutCursor();
1531 case CursorWebkitGrab:
1532 return grabCursor();
1533 case CursorWebkitGrabbing:
1534 return grabbingCursor();
1536 return pointerCursor();
1538 #endif // ENABLE(CURSOR_SUPPORT)
1540 #if ENABLE(CURSOR_VISIBILITY)
1541 void EventHandler::startAutoHideCursorTimer()
1543 Page* page = m_frame.page();
1547 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
1549 #if !ENABLE(IOS_TOUCH_EVENTS)
1550 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1551 // so cancel any pending fake mouse moves.
1552 if (m_fakeMouseMoveEventTimer.isActive())
1553 m_fakeMouseMoveEventTimer.stop();
1557 void EventHandler::cancelAutoHideCursorTimer()
1559 if (m_autoHideCursorTimer.isActive())
1560 m_autoHideCursorTimer.stop();
1563 void EventHandler::autoHideCursorTimerFired()
1565 m_currentMouseCursor = noneCursor();
1566 FrameView* view = m_frame.view();
1567 if (view && view->isActive())
1568 view->setCursor(m_currentMouseCursor);
1572 void EventHandler::beginTrackingPotentialLongMousePress(const HitTestResult& hitTestResult)
1574 clearLongMousePressState();
1576 Page* page = m_frame.page();
1577 if (!(page && page->settings().longMousePressEnabled()))
1580 m_longMousePressTimer.startOneShot(longMousePressRecognitionDelay);
1582 page->chrome().didBeginTrackingPotentialLongMousePress(m_mouseDownPos, hitTestResult);
1585 void EventHandler::recognizeLongMousePress()
1587 Page* page = m_frame.page();
1591 m_didRecognizeLongMousePress = true;
1593 // Clear mouse state to avoid initiating a drag.
1594 m_mousePressed = false;
1597 page->chrome().didRecognizeLongMousePress();
1600 void EventHandler::cancelTrackingPotentialLongMousePress()
1602 if (!m_longMousePressTimer.isActive())
1605 clearLongMousePressState();
1607 Page* page = m_frame.page();
1611 page->chrome().didCancelTrackingPotentialLongMousePress();
1614 void EventHandler::clearLongMousePressState()
1616 m_longMousePressTimer.stop();
1617 m_didRecognizeLongMousePress = false;
1620 bool EventHandler::handleLongMousePressMouseMovedEvent(const PlatformMouseEvent& mouseEvent)
1622 if (mouseEvent.button() != LeftButton || mouseEvent.type() != PlatformEvent::MouseMoved)
1625 if (m_didRecognizeLongMousePress)
1628 if (!mouseMovementExceedsThreshold(mouseEvent.position(), maximumLongMousePressDragDistance))
1629 cancelTrackingPotentialLongMousePress();
1634 static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
1636 FrameView* view = frame.view();
1637 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1638 // Historically the code would just crash; this is clearly no worse than that.
1639 return view ? view->windowToContents(windowPoint) : windowPoint;
1642 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& platformMouseEvent)
1644 RefPtr<FrameView> protector(m_frame.view());
1646 if (InspectorInstrumentation::handleMousePress(m_frame)) {
1651 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
1654 #if ENABLE(TOUCH_EVENTS)
1655 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1656 if (defaultPrevented)
1660 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
1662 // FIXME (bug 68185): this call should be made at another abstraction layer
1663 m_frame.loader().resetMultipleFormSubmissionProtection();
1665 #if !ENABLE(IOS_TOUCH_EVENTS)
1666 cancelFakeMouseMoveEvent();
1668 m_mousePressed = true;
1669 m_capturesDragging = true;
1670 setLastKnownMousePosition(platformMouseEvent);
1671 m_mouseDownTimestamp = platformMouseEvent.timestamp();
1672 #if ENABLE(DRAG_SUPPORT)
1673 m_mouseDownMayStartDrag = false;
1675 m_mouseDownMayStartSelect = false;
1676 m_mouseDownMayStartAutoscroll = false;
1677 if (FrameView* view = m_frame.view())
1678 m_mouseDownPos = view->windowToContents(platformMouseEvent.position());
1683 m_mouseDownWasInSubframe = false;
1685 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1686 // Save the document point we generate in case the window coordinate is invalidated by what happens
1687 // when we dispatch the event.
1688 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, platformMouseEvent.position());
1689 MouseEventWithHitTestResults mouseEvent = m_frame.document()->prepareMouseEvent(request, documentPoint, platformMouseEvent);
1691 if (!mouseEvent.targetNode()) {
1696 m_mousePressNode = mouseEvent.targetNode();
1698 RefPtr<Frame> subframe = subframeForHitTestResult(mouseEvent);
1699 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe.get())) {
1700 // Start capturing future events for this frame. We only do this if we didn't clear
1701 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1702 m_capturesDragging = subframe->eventHandler().capturesDragging();
1703 if (m_mousePressed && m_capturesDragging) {
1704 m_capturingMouseEventsElement = subframe->ownerElement();
1705 m_eventHandlerWillResetCapturingMouseEventsElement = true;
1711 #if ENABLE(PAN_SCROLLING)
1712 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1713 // because it will set m_autoscrollType to NoAutoscroll on return.
1714 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress();
1715 stopAutoscrollTimer();
1716 if (isPanScrollInProgress) {
1717 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1718 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1724 m_clickCount = platformMouseEvent.clickCount();
1725 m_clickNode = mouseEvent.targetNode();
1732 if (FrameView* view = m_frame.view()) {
1733 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1734 IntPoint p = view->windowToContents(platformMouseEvent.position());
1735 if (layer && layer->isPointInResizeControl(p)) {
1736 layer->setInResizeMode(true);
1737 m_resizeLayer = layer;
1738 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1744 m_frame.selection().setCaretBlinkingSuspended(true);
1746 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1747 m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
1749 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1750 // in case the scrollbar widget was destroyed when the mouse event was handled.
1751 if (mouseEvent.scrollbar()) {
1752 const bool wasLastScrollBar = mouseEvent.scrollbar() == m_lastScrollbarUnderMouse.get();
1753 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1754 if (wasLastScrollBar && mouseEvent.scrollbar() != m_lastScrollbarUnderMouse.get())
1755 m_lastScrollbarUnderMouse = nullptr;
1759 // scrollbars should get events anyway, even disabled controls might be scrollable
1760 Scrollbar* scrollbar = mouseEvent.scrollbar();
1762 updateLastScrollbarUnderMouse(scrollbar, true);
1765 passMousePressEventToScrollbar(mouseEvent, scrollbar);
1767 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1768 // If a mouse event handler changes the input element type to one that has a widget associated,
1769 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1770 // event target node can't still be the shadow node.
1771 if (is<ShadowRoot>(*mouseEvent.targetNode()) && is<HTMLInputElement>(*downcast<ShadowRoot>(*mouseEvent.targetNode()).hostElement()))
1772 mouseEvent = m_frame.document()->prepareMouseEvent(HitTestRequest(), documentPoint, platformMouseEvent);
1774 FrameView* view = m_frame.view();
1775 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(platformMouseEvent.position()) : 0;
1777 scrollbar = mouseEvent.scrollbar();
1779 updateLastScrollbarUnderMouse(scrollbar, true);
1781 if (scrollbar && passMousePressEventToScrollbar(mouseEvent, scrollbar))
1782 swallowEvent = true;
1784 swallowEvent = handleMousePressEvent(mouseEvent);
1787 return swallowEvent;
1790 // This method only exists for platforms that don't know how to deliver
1791 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& platformMouseEvent)
1793 RefPtr<FrameView> protector(m_frame.view());
1795 m_frame.selection().setCaretBlinkingSuspended(false);
1797 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
1799 // We get this instead of a second mouse-up
1800 m_mousePressed = false;
1801 setLastKnownMousePosition(platformMouseEvent);
1803 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1804 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1805 Frame* subframe = subframeForHitTestResult(mouseEvent);
1806 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1807 m_capturingMouseEventsElement = nullptr;
1808 if (subframe && passMousePressEventToSubframe(mouseEvent, subframe))
1811 m_clickCount = platformMouseEvent.clickCount();
1812 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
1814 bool swallowClickEvent = platformMouseEvent.button() != RightButton && mouseEvent.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
1816 if (m_lastScrollbarUnderMouse)
1817 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
1819 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mouseEvent);
1823 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1826 static RenderLayer* layerForNode(Node* node)
1831 auto renderer = node->renderer();
1835 RenderLayer* layer = renderer->enclosingLayer();
1842 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1844 RefPtr<FrameView> protector(m_frame.view());
1845 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1847 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(event))
1850 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1851 bool result = handleMouseMoveEvent(event, &hoveredNode);
1853 Page* page = m_frame.page();
1857 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1858 if (FrameView* frameView = m_frame.view()) {
1859 if (frameView->containsScrollableArea(layer))
1860 layer->mouseMovedInContentArea();
1864 if (FrameView* frameView = m_frame.view())
1865 frameView->mouseMovedInContentArea();
1867 hoveredNode.setToNonShadowAncestor();
1868 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1869 page->chrome().setToolTip(hoveredNode);
1873 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1875 HitTestResult hoveredNode;
1876 return handleMouseMoveEvent(event, &hoveredNode, true);
1879 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1881 #if ENABLE(TOUCH_EVENTS)
1882 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
1883 if (defaultPrevented)
1887 if (handleLongMousePressMouseMovedEvent(platformMouseEvent))
1890 RefPtr<FrameView> protector(m_frame.view());
1892 setLastKnownMousePosition(platformMouseEvent);
1894 if (m_hoverTimer.isActive())
1895 m_hoverTimer.stop();
1897 #if ENABLE(CURSOR_SUPPORT)
1898 m_cursorUpdateTimer.stop();
1901 #if !ENABLE(IOS_TOUCH_EVENTS)
1902 cancelFakeMouseMoveEvent();
1906 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1910 if (m_frameSetBeingResized)
1911 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, platformMouseEvent, false);
1913 // On iOS, our scrollbars are managed by UIKit.
1915 // Send events right to a scrollbar if the mouse is pressed.
1916 if (m_lastScrollbarUnderMouse && m_mousePressed)
1917 return m_lastScrollbarUnderMouse->mouseMoved(platformMouseEvent);
1920 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars;
1922 hitType |= HitTestRequest::Active;
1923 else if (onlyUpdateScrollbars) {
1924 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1925 // means that :hover and :active freeze in the state they were in, rather than updating
1926 // for nodes the mouse moves while the window is not key (which will be the case if
1927 // onlyUpdateScrollbars is true).
1928 hitType |= HitTestRequest::ReadOnly;
1931 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
1932 // Treat any mouse move events as readonly if the user is currently touching the screen.
1934 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1936 HitTestRequest request(hitType);
1937 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
1939 *hoveredNode = mouseEvent.hitTestResult();
1941 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1942 m_resizeLayer->resize(platformMouseEvent, m_offsetFromResizeCorner);
1944 Scrollbar* scrollbar = mouseEvent.scrollbar();
1945 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1947 // On iOS, our scrollbars are managed by UIKit.
1949 if (!m_mousePressed && scrollbar)
1950 scrollbar->mouseMoved(platformMouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1952 if (onlyUpdateScrollbars)
1956 bool swallowEvent = false;
1957 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
1959 // 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.
1960 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1961 passMouseMoveEventToSubframe(mouseEvent, m_lastMouseMoveEventSubframe.get());
1964 // Update over/out state before passing the event to the subframe.
1965 updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, true);
1967 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1968 // node to be detached from its FrameView, in which case the event should not be passed.
1969 if (newSubframe->view())
1970 swallowEvent |= passMouseMoveEventToSubframe(mouseEvent, newSubframe.get(), hoveredNode);
1971 #if ENABLE(CURSOR_SUPPORT)
1973 if (FrameView* view = m_frame.view()) {
1974 OptionalCursor optionalCursor = selectCursor(mouseEvent.hitTestResult(), platformMouseEvent.shiftKey());
1975 if (optionalCursor.isCursorChange()) {
1976 m_currentMouseCursor = optionalCursor.cursor();
1977 view->setCursor(m_currentMouseCursor);
1983 m_lastMouseMoveEventSubframe = newSubframe;
1988 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
1989 #if ENABLE(DRAG_SUPPORT)
1991 swallowEvent = handleMouseDraggedEvent(mouseEvent);
1992 #endif // ENABLE(DRAG_SUPPORT)
1994 return swallowEvent;
1997 void EventHandler::invalidateClick()
2000 m_clickNode = nullptr;
2003 inline static bool mouseIsReleasedOnPressedElement(Node* targetNode, Node* clickNode)
2005 if (targetNode == clickNode)
2011 ShadowRoot* containingShadowRoot = targetNode->containingShadowRoot();
2012 if (!containingShadowRoot)
2015 // FIXME: When an element in UA ShadowDOM (e.g. inner element in <input>) is clicked,
2016 // we assume that the host element is clicked. This is necessary for implementing <input type="range"> etc.
2017 // However, we should not check ShadowRoot type basically.
2018 // https://bugs.webkit.org/show_bug.cgi?id=108047
2019 if (containingShadowRoot->type() != ShadowRoot::UserAgentShadowRoot)
2022 Node* adjustedTargetNode = targetNode->shadowHost();
2023 Node* adjustedClickNode = clickNode ? clickNode->shadowHost() : 0;
2024 return adjustedTargetNode == adjustedClickNode;
2027 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMouseEvent)
2029 RefPtr<FrameView> protector(m_frame.view());
2031 m_frame.selection().setCaretBlinkingSuspended(false);
2033 if (m_frame.mainFrame().pageOverlayController().handleMouseEvent(platformMouseEvent))
2036 #if ENABLE(TOUCH_EVENTS)
2037 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(platformMouseEvent);
2038 if (defaultPrevented)
2042 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
2044 #if ENABLE(PAN_SCROLLING)
2045 m_autoscrollController->handleMouseReleaseEvent(platformMouseEvent);
2048 m_mousePressed = false;
2049 setLastKnownMousePosition(platformMouseEvent);
2053 downcast<SVGDocument>(*m_frame.document()).updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
2057 if (m_frameSetBeingResized)
2058 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, platformMouseEvent, false);
2060 if (m_lastScrollbarUnderMouse) {
2062 m_lastScrollbarUnderMouse->mouseUp(platformMouseEvent);
2063 bool cancelable = true;
2064 bool setUnder = false;
2065 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
2068 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
2069 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
2070 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
2071 if (m_eventHandlerWillResetCapturingMouseEventsElement)
2072 m_capturingMouseEventsElement = nullptr;
2073 if (subframe && passMouseReleaseEventToSubframe(mouseEvent, subframe))
2076 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, false);
2078 bool contextMenuEvent = platformMouseEvent.button() == RightButton;
2080 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && mouseIsReleasedOnPressedElement(mouseEvent.targetNode(), m_clickNode.get()) && !dispatchMouseEvent(eventNames().clickEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
2082 if (m_resizeLayer) {
2083 m_resizeLayer->setInResizeMode(false);
2084 m_resizeLayer = nullptr;
2087 bool swallowMouseReleaseEvent = false;
2088 if (!swallowMouseUpEvent)
2089 swallowMouseReleaseEvent = handleMouseReleaseEvent(mouseEvent);
2093 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2096 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& platformMouseEvent)
2098 // If the event was a middle click, attempt to copy global selection in after
2099 // the newly set caret position.
2101 // This code is called from either the mouse up or mouse down handling. There
2102 // is some debate about when the global selection is pasted:
2103 // xterm: pastes on up.
2104 // GTK: pastes on down.
2105 // Qt: pastes on up.
2106 // Firefox: pastes on up.
2107 // Chromium: pastes on up.
2109 // There is something of a webcompat angle to this well, as highlighted by
2110 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
2111 // down then the text is pasted just before the onclick handler runs and
2112 // clears the text box. So it's important this happens after the event
2113 // handlers have been fired.
2115 if (platformMouseEvent.type() != PlatformEvent::MousePressed)
2118 if (platformMouseEvent.type() != PlatformEvent::MouseReleased)
2122 if (!m_frame.page())
2124 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame();
2125 // Do not paste here if the focus was moved somewhere else.
2126 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection())
2127 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute();
2132 #if ENABLE(DRAG_SUPPORT)
2134 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2136 FrameView* view = m_frame.view();
2138 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2142 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2143 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2144 true, true, event.timestamp(), m_frame.document()->defaultView(),
2145 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2146 #if ENABLE(POINTER_LOCK)
2147 event.movementDelta().x(), event.movementDelta().y(),
2149 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2150 0, 0, dataTransfer);
2152 dragTarget.dispatchEvent(me.get(), IGNORE_EXCEPTION);
2153 return me->defaultPrevented();
2156 static bool targetIsFrame(Node* target, Frame*& frame)
2158 if (!is<HTMLFrameElementBase>(target))
2161 frame = downcast<HTMLFrameElementBase>(*target).contentFrame();
2165 static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation)
2167 if (dragOperation == "copy")
2168 return DragOperationCopy;
2169 if (dragOperation == "move")
2170 return DragOperationMove;
2171 if (dragOperation == "link")
2172 return DragOperationLink;
2173 return DragOperationNone;
2176 static String convertDragOperationToDropZoneOperation(DragOperation operation)
2178 switch (operation) {
2179 case DragOperationCopy:
2180 return ASCIILiteral("copy");
2181 case DragOperationMove:
2182 return ASCIILiteral("move");
2183 case DragOperationLink:
2184 return ASCIILiteral("link");
2186 return ASCIILiteral("copy");
2190 static bool hasDropZoneType(DataTransfer& dataTransfer, const String& keyword)
2192 if (keyword.startsWith("file:"))
2193 return dataTransfer.hasFileOfType(keyword.substring(5));
2195 if (keyword.startsWith("string:"))
2196 return dataTransfer.hasStringOfType(keyword.substring(7));
2201 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
2204 Element* element = is<Element>(*target) ? downcast<Element>(target) : target->parentElement();
2205 for (; element; element = element->parentElement()) {
2206 bool matched = false;
2207 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2209 if (dropZoneStr.isEmpty())
2212 dropZoneStr = dropZoneStr.lower();
2214 SpaceSplitString keywords(dropZoneStr, false);
2215 if (keywords.isEmpty())
2218 DragOperation dragOperation = DragOperationNone;
2219 for (unsigned int i = 0; i < keywords.size(); i++) {
2220 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2221 if (op != DragOperationNone) {
2222 if (dragOperation == DragOperationNone)
2225 matched = matched || hasDropZoneType(*dataTransfer, keywords[i].string());
2227 if (matched && dragOperation != DragOperationNone)
2231 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2238 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2240 bool accept = false;
2242 if (!m_frame.view())
2245 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2246 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, event);
2248 RefPtr<Element> newTarget;
2249 if (Node* targetNode = mouseEvent.targetNode()) {
2250 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch)
2251 if (!is<Element>(*targetNode))
2252 newTarget = targetNode->parentOrShadowHostElement();
2254 newTarget = downcast<Element>(targetNode);
2257 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2259 if (m_dragTarget != newTarget) {
2260 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2261 // it is sometimes incorrect when dragging within subframes, as seen with
2262 // LayoutTests/fast/events/drag-in-frames.html.
2264 // 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>.
2266 if (targetIsFrame(newTarget.get(), targetFrame)) {
2268 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2269 } else if (newTarget) {
2270 // 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.
2271 if (dragState().source && dragState().shouldDispatchEvents) {
2272 // for now we don't care if event handler cancels default behavior, since there is none
2273 dispatchDragSrcEvent(eventNames().dragEvent, event);
2275 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, dataTransfer);
2277 accept = findDropZone(newTarget.get(), dataTransfer);
2280 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2282 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2283 } else if (m_dragTarget)
2284 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2287 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2288 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2289 m_shouldOnlyFireDragOverEvent = true;
2293 if (targetIsFrame(newTarget.get(), targetFrame)) {
2295 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
2296 } else if (newTarget) {
2297 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2298 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
2299 // for now we don't care if event handler cancels default behavior, since there is none
2300 dispatchDragSrcEvent(eventNames().dragEvent, event);
2302 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, dataTransfer);
2304 accept = findDropZone(newTarget.get(), dataTransfer);
2305 m_shouldOnlyFireDragOverEvent = false;
2308 m_dragTarget = newTarget.release();
2312 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2315 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2317 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
2318 } else if (m_dragTarget) {
2319 if (dragState().source && dragState().shouldDispatchEvents)
2320 dispatchDragSrcEvent(eventNames().dragEvent, event);
2321 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, dataTransfer);
2326 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
2329 bool preventedDefault = false;
2330 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2332 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
2333 } else if (m_dragTarget)
2334 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, dataTransfer);
2336 return preventedDefault;
2339 void EventHandler::clearDragState()
2341 stopAutoscrollTimer();
2342 m_dragTarget = nullptr;
2343 m_capturingMouseEventsElement = nullptr;
2344 m_shouldOnlyFireDragOverEvent = false;
2346 m_sendingEventToSubview = false;
2349 #endif // ENABLE(DRAG_SUPPORT)
2351 void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element)
2353 m_capturingMouseEventsElement = element;
2354 m_eventHandlerWillResetCapturingMouseEventsElement = false;
2357 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent)
2359 ASSERT(m_frame.document());
2360 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mouseEvent.position()), mouseEvent);
2363 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
2368 for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
2369 for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
2370 if (currObj1 == currObj2)
2378 static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName)
2380 for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) {
2381 if (curr->hasCapturingEventListeners(eventName))
2387 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& platformMouseEvent, bool fireMouseOverOut)
2389 Element* targetElement = nullptr;
2391 // If we're capturing, we always go right to that element.
2392 if (m_capturingMouseEventsElement)
2393 targetElement = m_capturingMouseEventsElement.get();
2394 else if (targetNode) {
2395 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646>
2396 if (!is<Element>(*targetNode))
2397 targetElement = targetNode->parentOrShadowHostElement();
2399 targetElement = downcast<Element>(targetNode);
2402 m_elementUnderMouse = targetElement;
2404 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2405 if (fireMouseOverOut) {
2406 RenderLayer* layerForLastNode = layerForNode(m_lastElementUnderMouse.get());
2407 RenderLayer* layerForNodeUnderMouse = layerForNode(m_elementUnderMouse.get());
2408 Page* page = m_frame.page();
2410 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) {
2411 // The mouse has moved between frames.
2412 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2413 if (FrameView* frameView = frame->view())
2414 frameView->mouseExitedContentArea();
2416 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2417 // The mouse has moved between layers.
2418 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2419 if (FrameView* frameView = frame->view()) {
2420 if (frameView->containsScrollableArea(layerForLastNode))
2421 layerForLastNode->mouseExitedContentArea();
2426 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) {
2427 // The mouse has moved between frames.
2428 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2429 if (FrameView* frameView = frame->view())
2430 frameView->mouseEnteredContentArea();
2432 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2433 // The mouse has moved between layers.
2434 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2435 if (FrameView* frameView = frame->view()) {
2436 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2437 layerForNodeUnderMouse->mouseEnteredContentArea();
2442 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) {
2443 m_lastElementUnderMouse = nullptr;
2444 m_lastScrollbarUnderMouse = nullptr;
2447 if (m_lastElementUnderMouse != m_elementUnderMouse) {
2448 // mouseenter and mouseleave events are only dispatched if there is a capturing eventhandler on an ancestor
2449 // or a normal eventhandler on the element itself (they don't bubble).
2450 // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks.
2451 bool hasCapturingMouseEnterListener = hierarchyHasCapturingEventListeners(m_elementUnderMouse.get(), eventNames().mouseenterEvent);
2452 bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent);
2454 RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr;
2455 RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr;
2456 RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer);
2458 Vector<Ref<Element>, 32> leftElementsChain;
2459 if (oldHoverRenderer) {
2460 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) {
2461 if (Element* element = curr->element())
2462 leftElementsChain.append(*element);
2465 // If the old hovered element is not null but it's renderer is, it was probably detached.
2466 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied.
2467 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement())
2468 leftElementsChain.append(*element);
2471 Vector<Ref<Element>, 32> enteredElementsChain;
2472 const Element* ancestorElement = ancestor ? ancestor->element() : nullptr;
2473 for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) {
2474 if (Element *element = curr->element()) {
2475 if (element == ancestorElement)
2477 enteredElementsChain.append(*element);
2481 // Send mouseout event to the old node.
2482 if (m_lastElementUnderMouse)
2483 m_lastElementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
2485 // Send mouseleave to the node hierarchy no longer under the mouse.
2486 for (size_t i = 0; i < leftElementsChain.size(); ++i) {
2487 if (hasCapturingMouseLeaveListener || leftElementsChain[i]->hasEventListeners(eventNames().mouseleaveEvent))
2488 leftElementsChain[i]->dispatchMouseEvent(platformMouseEvent, eventNames().mouseleaveEvent, 0, m_elementUnderMouse.get());
2491 // Send mouseover event to the new node.
2492 if (m_elementUnderMouse)
2493 m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
2495 // Send mouseleave event to the nodes hierarchy under the mouse.
2496 for (size_t i = 0, size = enteredElementsChain.size(); i < size; ++i) {
2497 if (hasCapturingMouseEnterListener || enteredElementsChain[i]->hasEventListeners(eventNames().mouseenterEvent))
2498 enteredElementsChain[i]->dispatchMouseEvent(platformMouseEvent, eventNames().mouseenterEvent, 0, m_lastElementUnderMouse.get());
2501 m_lastElementUnderMouse = m_elementUnderMouse;
2505 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
2507 if (FrameView* view = m_frame.view())
2508 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2510 updateMouseEventTargetNode(targetNode, platformMouseEvent, setUnder);
2512 bool swallowEvent = false;
2514 if (m_elementUnderMouse)
2515 swallowEvent = !(m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventType, clickCount));
2517 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2519 // If clicking on a frame scrollbar, do not mess up with content focus.
2520 if (FrameView* view = m_frame.view()) {
2521 if (view->scrollbarAtPoint(platformMouseEvent.position()))
2525 // The layout needs to be up to date to determine if an element is focusable.
2526 m_frame.document()->updateLayoutIgnorePendingStylesheets();
2528 // Blur current focus node when a link/button is clicked; this
2529 // is expected by some sites that rely on onChange handlers running
2530 // from form fields before the button click is processed.
2532 Element* element = m_elementUnderMouse.get();
2534 // Walk up the DOM tree to search for an element to focus.
2536 if (element->isMouseFocusable()) {
2537 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2538 // node on mouse down if it's selected and inside a focused node. It will be
2539 // focused if the user does a mouseup over it, however, because the mouseup
2540 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2541 if (m_frame.selection().isRange()
2542 && m_frame.selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2543 && element->isDescendantOf(m_frame.document()->focusedElement()))
2548 element = element->parentOrShadowHostElement();
2551 // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node.
2552 if ((!element || !element->isMouseFocusable()) && isInsideScrollbar(platformMouseEvent.position()))
2555 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2556 // if the page already set it (e.g., by canceling default behavior).
2557 if (Page* page = m_frame.page()) {
2558 if (element && element->isMouseFocusable()) {
2559 if (!page->focusController().setFocusedElement(element, &m_frame))
2560 swallowEvent = true;
2561 } else if (!element || !element->focused()) {
2562 if (!page->focusController().setFocusedElement(0, &m_frame))
2563 swallowEvent = true;
2568 return !swallowEvent;
2571 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2573 if (RenderView* renderView = m_frame.contentRenderer()) {
2574 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2575 HitTestResult result(windowPoint);
2576 renderView->hitTest(request, result);
2577 return result.scrollbar();
2585 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2594 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, ScrollableArea*&, bool&)
2598 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event)
2600 m_frame.mainFrame().wheelEventDeltaTracker()->recordWheelEventDelta(event);
2603 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, Element*, ContainerNode*, ScrollableArea*)
2605 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2606 FrameView* view = m_frame.view();
2608 bool didHandleEvent = view ? view->wheelEvent(event) : false;
2609 m_isHandlingWheelEvent = false;
2610 return didHandleEvent;
2613 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode*)
2618 #if ENABLE(CSS_SCROLL_SNAP)
2619 void EventHandler::platformNotifySnapIfNecessary(const PlatformWheelEvent&, ScrollableArea&)
2626 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
2628 RenderView* renderView = m_frame.contentRenderer();
2632 RefPtr<FrameView> protector(m_frame.view());
2634 FrameView* view = m_frame.view();
2638 m_isHandlingWheelEvent = true;
2639 setFrameWasScrolledByUser();
2641 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2642 HitTestResult result(view->windowToContents(event.position()));
2643 renderView->hitTest(request, result);
2645 RefPtr<Element> element = result.innerElement();
2646 RefPtr<ContainerNode> scrollableContainer;
2647 ScrollableArea* scrollableArea = nullptr;
2648 bool isOverWidget = result.isOverWidget();
2649 platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget);
2652 if (event.phase() == PlatformWheelEventPhaseNone && event.momentumPhase() == PlatformWheelEventPhaseNone)
2653 m_frame.mainFrame().resetLatchingState();
2656 // FIXME: It should not be necessary to do this mutation here.
2657 // Instead, the handlers should know convert vertical scrolls appropriately.
2658 PlatformWheelEvent adjustedEvent = event;
2659 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, event))
2660 adjustedEvent = event.copyTurningVerticalTicksIntoHorizontalTicks();
2662 platformRecordWheelEvent(adjustedEvent);
2666 RenderElement* target = element->renderer();
2667 if (is<RenderWidget>(target)) {
2668 Widget* widget = downcast<RenderWidget>(*target).widget();
2669 if (widget && passWheelEventToWidget(event, *widget)) {
2670 m_isHandlingWheelEvent = false;
2672 scrollableArea->setScrolledProgrammatically(false);
2673 if (!widget->platformWidget())
2675 return platformCompletePlatformWidgetWheelEvent(event, *widget, scrollableContainer.get());
2680 if (!element->dispatchWheelEvent(adjustedEvent)) {
2681 m_isHandlingWheelEvent = false;
2682 if (scrollableArea && scrollableArea->isScrolledProgrammatically()) {
2683 // Web developer is controlling scrolling, so don't attempt to latch.
2684 clearLatchedState();
2685 scrollableArea->setScrolledProgrammatically(false);
2688 #if ENABLE(CSS_SCROLL_SNAP)
2690 platformNotifySnapIfNecessary(adjustedEvent, *scrollableArea);
2697 scrollableArea->setScrolledProgrammatically(false);
2699 return platformCompleteWheelEvent(event, element.get(), scrollableContainer.get(), scrollableArea);
2702 void EventHandler::clearLatchedState()
2705 m_frame.mainFrame().resetLatchingState();
2707 m_frame.mainFrame().wheelEventDeltaTracker()->endTrackingDeltas();
2710 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2712 if (!startNode || !wheelEvent)
2715 DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None;
2718 ScrollLatchingState* latchedState = m_frame.mainFrame().latchingState();
2719 Element* stopElement = latchedState ? latchedState->previousWheelScrolledElement() : nullptr;
2721 // Workaround for scrolling issues <rdar://problem/14758615>.
2722 if (m_frame.mainFrame().wheelEventDeltaTracker()->isTrackingDeltas())
2723 dominantDirection = m_frame.mainFrame().wheelEventDeltaTracker()->dominantScrollGestureDirection();
2725 Element* stopElement = nullptr;
2728 // Break up into two scrolls if we need to. Diagonal movement on
2729 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2730 if (dominantDirection != DominantScrollGestureDirection::Vertical && handleWheelEventInAppropriateEnclosingBoxForSingleAxis(startNode, wheelEvent, &stopElement, ScrollEventAxis::Horizontal))
2731 wheelEvent->setDefaultHandled();
2733 if (dominantDirection != DominantScrollGestureDirection::Horizontal && handleWheelEventInAppropriateEnclosingBoxForSingleAxis(startNode, wheelEvent, &stopElement, ScrollEventAxis::Vertical))
2734 wheelEvent->setDefaultHandled();
2737 if (latchedState && !latchedState->wheelEventElement())
2738 latchedState->setPreviousWheelScrolledElement(stopElement);
2742 #if ENABLE(CONTEXT_MENUS)
2743 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2745 Document* doc = m_frame.document();
2746 FrameView* v = m_frame.view();
2750 // Clear mouse press state to avoid initiating a drag while context menu is up.
2751 m_mousePressed = false;
2753 LayoutPoint viewportPos = v->windowToContents(event.position());
2754 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
2755 MouseEventWithHitTestResults mouseEvent = doc->prepareMouseEvent(request, viewportPos, event);
2757 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick()
2758 && !m_frame.selection().contains(viewportPos)
2759 && !mouseEvent.scrollbar()
2760 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2761 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2762 // available for text selections. But only if we're above text.
2763 && (m_frame.selection().selection().isContentEditable() || (mouseEvent.targetNode() && mouseEvent.targetNode()->isTextNode()))) {
2764 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2765 selectClosestWordOrLinkFromMouseEvent(mouseEvent);
2768 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mouseEvent.targetNode(), true, 0, event, false);
2770 return swallowEvent;
2773 bool EventHandler::sendContextMenuEventForKey()
2775 FrameView* view = m_frame.view();
2779 Document* doc = m_frame.document();
2783 // Clear mouse press state to avoid initiating a drag while context menu is up.
2784 m_mousePressed = false;
2786 static const int kContextMenuMargin = 1;
2789 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2791 int rightAligned = 0;
2795 Element* focusedElement = doc->focusedElement();
2796 const VisibleSelection& selection = m_frame.selection().selection();
2797 Position start = selection.start();
2799 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2800 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2801 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get());
2803 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2804 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2805 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2806 location = IntPoint(x, y);
2807 } else if (focusedElement) {
2808 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2811 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2812 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2814 location = IntPoint(
2815 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2816 kContextMenuMargin);
2819 m_frame.view()->setCursor(pointerCursor());
2821 IntPoint position = view->contentsToRootView(location);
2822 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2824 Node* targetNode = doc->focusedElement();
2828 // Use the focused node as the target for hover and active.
2829 HitTestResult result(position);
2830 result.setInnerNode(targetNode);
2831 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement());
2833 // The contextmenu event is a mouse event even when invoked using the keyboard.
2834 // This is required for web compatibility.
2837 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2839 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2842 PlatformMouseEvent platformMouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2844 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, platformMouseEvent, false);
2846 #endif // ENABLE(CONTEXT_MENUS)
2848 void EventHandler::scheduleHoverStateUpdate()
2850 if (!m_hoverTimer.isActive())
2851 m_hoverTimer.startOneShot(0);
2854 #if ENABLE(CURSOR_SUPPORT)
2855 void EventHandler::scheduleCursorUpdate()
2857 if (!m_cursorUpdateTimer.isActive())
2858 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2862 void EventHandler::dispatchFakeMouseMoveEventSoon()
2864 #if !ENABLE(IOS_TOUCH_EVENTS)
2868 if (m_mousePositionIsUnknown)
2871 if (Page* page = m_frame.page()) {
2872 if (!page->chrome().client().shouldDispatchFakeMouseMoveEvents())
2876 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2877 // reschedule the timer and use a longer time. This will cause the content
2878 // to receive these moves only after the user is done scrolling, reducing
2879 // pauses during the scroll.
2880 if (m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold) {
2881 if (m_fakeMouseMoveEventTimer.isActive())
2882 m_fakeMouseMoveEventTimer.stop();
2883 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2885 if (!m_fakeMouseMoveEventTimer.isActive())
2886 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2891 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2893 #if ENABLE(IOS_TOUCH_EVENTS)
2896 FrameView* view = m_frame.view();
2900 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2903 dispatchFakeMouseMoveEventSoon();
2907 #if !ENABLE(IOS_TOUCH_EVENTS)
2908 void EventHandler::cancelFakeMouseMoveEvent()
2910 m_fakeMouseMoveEventTimer.stop();
2913 void EventHandler::fakeMouseMoveEventTimerFired()
2915 ASSERT(!m_mousePressed);
2917 FrameView* view = m_frame.view();
2921 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive())
2928 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2929 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2930 mouseMoved(fakeMouseMoveEvent);
2932 #endif // !ENABLE(IOS_TOUCH_EVENTS)
2934 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2936 m_frameSetBeingResized = frameSet;
2939 void EventHandler::resizeLayerDestroyed()
2941 ASSERT(m_resizeLayer);
2945 void EventHandler::hoverTimerFired()
2947 m_hoverTimer.stop();
2949 ASSERT(m_frame.document());
2951 if (RenderView* renderView = m_frame.contentRenderer()) {
2952 if (FrameView* view = m_frame.view()) {
2953 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
2954 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2955 renderView->hitTest(request, result);
2956 m_frame.document()->updateHoverActiveState(request, result.innerElement());
2961 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2963 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2964 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2965 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2966 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2967 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2968 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2970 String key = evt.unmodifiedText();
2971 Element* elem = m_frame.document()->getElementByAccessKey(key.lower());
2974 elem->accessKeyAction(false);
2979 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2985 #if ENABLE(FULLSCREEN_API)
2986 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2988 Document* document = m_frame.document();
2989 if (document->webkitFullScreenKeyboardInputAllowed())
2992 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2993 if (keyEvent.text().length() != 1)
2995 UChar character = keyEvent.text()[0];
2996 return character == ' ';
2999 int keyCode = keyEvent.windowsVirtualKeyCode();
3000 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3001 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3002 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3003 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3007 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3009 RefPtr<FrameView> protector(m_frame.view());
3011 #if ENABLE(FULLSCREEN_API)
3012 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
3016 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3017 capsLockStateMayHaveChanged();
3019 #if ENABLE(PAN_SCROLLING)
3020 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) {
3021 // If a key is pressed while the panScroll is in progress then we want to stop
3022 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3023 stopAutoscrollTimer();
3025 // If we were in panscroll mode, we swallow the key event
3030 // Check for cases where we are too early for events -- possible unmatched key up
3031 // from pressing return in the location bar.
3032 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document());
3036 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
3037 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3039 if (FrameView* view = m_frame.view())
3040 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3042 // FIXME (bug 68185): this call should be made at another abstraction layer
3043 m_frame.loader().resetMultipleFormSubmissionProtection();
3045 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3046 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3047 // with access keys. Then we dispatch keydown, but suppress its default handling.
3048 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3049 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3050 bool matchedAnAccessKey = false;
3051 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3052 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3054 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3055 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3056 return !element->dispatchKeyEvent(initialKeyEvent);
3058 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3060 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3061 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3062 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3063 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3064 if (matchedAnAccessKey)
3065 keydown->setDefaultPrevented(true);
3066 keydown->setTarget(element);
3068 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3069 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
3070 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3071 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3072 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3075 // Run input method in advance of DOM event handling. This may result in the IM
3076 // modifying the page prior the keydown event, but this behaviour is necessary
3077 // in order to match IE:
3078 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3079 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3080 m_frame.editor().handleInputMethodKeydown(keydown.get());
3082 bool handledByInputMethod = keydown->defaultHandled();
3084 if (handledByInputMethod) {
3085 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3086 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
3087 keydown->setTarget(element);
3088 keydown->setDefaultHandled();
3091 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
3092 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3093 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
3094 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3095 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3096 return keydownResult;
3098 // Focus may have changed during keydown handling, so refetch element.
3099 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element.
3100 if (!keydownResult) {
3101 element = eventTargetElementForDocument(m_frame.document());
3106 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3107 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3108 if (keyPressEvent.text().isEmpty())
3109 return keydownResult;
3110 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView());
3111 keypress->setTarget(element);
3113 keypress->setDefaultPrevented(true);
3115 keypress->keypressCommands() = keydown->keypressCommands();
3117 element->dispatchEvent(keypress, IGNORE_EXCEPTION);
3119 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3122 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3124 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3125 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3126 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3127 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3129 FocusDirection retVal = FocusDirectionNone;
3131 if (keyIdentifier == Down)
3132 retVal = FocusDirectionDown;
3133 else if (keyIdentifier == Up)
3134 retVal = FocusDirectionUp;
3135 else if (keyIdentifier == Left)
3136 retVal = FocusDirectionLeft;
3137 else if (keyIdentifier == Right)
3138 retVal = FocusDirectionRight;
3143 static void setInitialKeyboardSelection(Frame& frame, SelectionDirection direction)
3145 Document* document = frame.document();
3149 FrameSelection& selection = frame.selection();
3151 if (!selection.isNone())
3154 Element* focusedElement = document->focusedElement();
3155 VisiblePosition visiblePosition;
3157 switch (direction) {
3158 case DirectionBackward:
3161 visiblePosition = VisiblePosition(positionBeforeNode(focusedElement));
3163 visiblePosition = endOfDocument(document);
3165 case DirectionForward:
3166 case DirectionRight:
3168 visiblePosition = VisiblePosition(positionAfterNode(focusedElement));
3170 visiblePosition = startOfDocument(document);
3174 selection.setSelection(visiblePosition, FrameSelection::defaultSetSelectionOptions(UserTriggered));
3177 static void handleKeyboardSelectionMovement(Frame& frame, KeyboardEvent* event)
3182 FrameSelection& selection = frame.selection();
3184 bool isCommanded = event->getModifierState("Meta");
3185 bool isOptioned = event->getModifierState("Alt");
3186 bool isSelection = !selection.isNone();
3188 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3189 SelectionDirection direction = DirectionForward;
3190 TextGranularity granularity = CharacterGranularity;
3192 switch (focusDirectionForKey(event->keyIdentifier())) {
3193 case FocusDirectionNone:
3195 case FocusDirectionForward:
3196 case FocusDirectionBackward:
3197 ASSERT_NOT_REACHED();
3199 case FocusDirectionUp:
3200 direction = DirectionBackward;
3201 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3203 case FocusDirectionDown:
3204 direction = DirectionForward;
3205 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3207 case FocusDirectionLeft:
3208 direction = DirectionLeft;
3209 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3211 case FocusDirectionRight:
3212 direction = DirectionRight;
3213 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3218 selection.modify(alternation, direction, granularity, UserTriggered);
3220 setInitialKeyboardSelection(frame, direction);
3222 event->setDefaultHandled();
3225 void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent* event)
3227 if (event->type() == eventNames().keydownEvent) {
3228 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3229 handleKeyboardSelectionMovement(m_frame, event);
3233 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3235 if (event->type() == eventNames().keydownEvent) {
3236 m_frame.editor().handleKeyboardEvent(event);
3237 if (event->defaultHandled())
3239 if (event->keyIdentifier() == "U+0009")
3240 defaultTabEventHandler(event);
3241 else if (event->keyIdentifier() == "U+0008")
3242 defaultBackspaceEventHandler(event);
3244 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3245 if (direction != FocusDirectionNone)
3246 defaultArrowEventHandler(direction, event);
3249 handleKeyboardSelectionMovementForAccessibility(event);
3251 if (event->type() == eventNames().keypressEvent) {
3252 m_frame.editor().handleKeyboardEvent(event);
3253 if (event->defaultHandled())
3255 if (event->charCode() == ' ')
3256 defaultSpaceEventHandler(event);
3260 #if ENABLE(DRAG_SUPPORT)
3261 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3263 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3264 return dragHysteresisExceeded(dragViewportLocation);
3267 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3269 int threshold = GeneralDragHysteresis;
3270 switch (dragState().type) {
3271 case DragSourceActionSelection:
3272 threshold = TextDragHysteresis;
3274 case DragSourceActionImage:
3275 threshold = ImageDragHysteresis;
3277 case DragSourceActionLink:
3278 threshold = LinkDragHysteresis;
3280 case DragSourceActionDHTML:
3282 case DragSourceActionNone:
3283 case DragSourceActionAny:
3284 ASSERT_NOT_REACHED();
3287 return mouseMovementExceedsThreshold(dragViewportLocation, threshold);
3290 void EventHandler::freeDataTransfer()
3292 if (!dragState().dataTransfer)
3294 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::Numb);
3295 dragState().dataTransfer = 0;
3298 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3300 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3301 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
3302 prepareMouseEvent(request, event);
3304 if (dragState().source && dragState().shouldDispatchEvents) {
3305 dragState().dataTransfer->setDestinationOperation(operation);
3306 // For now we don't care if event handler cancels default behavior, since there is no default behavior.
3307 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3310 dragState().source = 0;
3311 // In case the drag was ended due to an escape key press we need to ensure
3312 // that consecutive mousemove events don't reinitiate the drag and drop.
3313 m_mouseDownMayStartDrag = false;
3316 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3318 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element.
3319 if (dragState().source && !dragState().source->inDocument())
3320 dragState().source = rootEditableElement;
3323 // Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
3324 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3326 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
3329 static bool ExactlyOneBitSet(DragSourceAction n)
3331 return n && !(n & (n - 1));
3334 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3336 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3337 // If we allowed the other side of the bridge to handle a drag
3338 // last time, then m_mousePressed might still be set. So we
3339 // clear it now to make sure the next move after a drag
3340 // doesn't look like a drag.
3341 m_mousePressed = false;
3345 if (eventLoopHandleMouseDragged(event))
3348 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3350 if (m_mouseDownMayStartDrag && !dragState().source) {
3351 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML);
3353 // try to find an element that wants to be dragged
3354 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
3355 HitTestResult result(m_mouseDownPos);
3356 m_frame.contentRenderer()->hitTest(request, result);
3358 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
3360 if (!dragState().source)
3361 m_mouseDownMayStartDrag = false; // no element is draggable
3363 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection);
3366 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3367 // or else we bail on the dragging stuff and allow selection to occur
3368 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3369 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3370 if ((dragState().type & DragSourceActionImage)) {
3371 // ... unless the mouse is over an image, then we start dragging just the image
3372 dragState().type = DragSourceActionImage;
3373 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) {
3374 // ... but only bail if we're not over an unselectable element.
3375 m_mouseDownMayStartDrag = false;
3376 dragState().source = 0;
3377 // ... but if this was the first click in the window, we don't even want to start selection
3378 if (eventActivatedView(event.event()))
3379 m_mouseDownMayStartSelect = false;
3381 // Prevent the following case from occuring:
3382 // 1. User starts a drag immediately after mouse down over an unselectable element.
3383 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag.
3384 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet.
3385 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag.
3386 m_dragMayStartSelectionInstead = false;
3390 if (!m_mouseDownMayStartDrag)
3391 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3393 if (!ExactlyOneBitSet(dragState().type)) {
3394 ASSERT((dragState().type & DragSourceActionSelection));
3395 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3396 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3397 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3398 dragState().type = DragSourceActionSelection;
3401 // We are starting a text/image/url drag, so the cursor should be an arrow
3402 if (FrameView* view = m_frame.view()) {
3403 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3404 view->setCursor(pointerCursor());
3407 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3410 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3413 DragOperation srcOp = DragOperationNone;
3415 // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old dataTransfer gets numbed.
3418 dragState().dataTransfer = createDraggingDataTransfer();
3420 if (dragState().shouldDispatchEvents) {
3421 // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset.
3422 if (dragState().type == DragSourceActionDHTML) {
3423 if (RenderObject* renderer = dragState().source->renderer()) {
3424 // FIXME: This doesn't work correctly with transforms.
3425 FloatPoint absPos = renderer->localToAbsolute();
3426 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3427 dragState().dataTransfer->setDragImage(dragState().source.get(), delta.width(), delta.height());
3429 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3430 // the element in some way. In this case we just kill the drag.
3431 m_mouseDownMayStartDrag = false;
3436 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3437 && !m_frame.selection().selection().isInPasswordField();
3439 // Invalidate dataTransfer here against anymore pasteboard writing for security. The drag
3440 // image can still be changed as we drag, but not the pasteboard data.
3441 dragState().dataTransfer->setAccessPolicy(DataTransferAccessPolicy::ImageWritable);
3443 if (m_mouseDownMayStartDrag) {
3444 // Gather values from DHTML element, if it set any.
3445 srcOp = dragState().dataTransfer->sourceOperation();
3447 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3448 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3449 // started the drag when that happens. So we have to assume it's started before we kick it off.
3450 dragState().dataTransfer->setDragHasStarted();
3454 if (m_mouseDownMayStartDrag) {
3455 Page* page = m_frame.page();
3456 m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3457 // In WebKit2 we could re-enter this code and start another drag.
3458 // On OS X this causes problems with the ownership of the pasteboard and the promised types.
3459 if (m_didStartDrag) {
3460 m_mouseDownMayStartDrag = false;
3462 cancelTrackingPotentialLongMousePress();
3465 if (dragState().source && dragState().shouldDispatchEvents) {
3466 // Drag was canned at the last minute. We owe dragSource a dragend event.
3467 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3468 m_mouseDownMayStartDrag = false;
3473 if (!m_mouseDownMayStartDrag) {
3474 // Something failed to start the drag, clean up.
3476 dragState().source = 0;
3479 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3482 #endif // ENABLE(DRAG_SUPPORT)
3484 bool EventHandler::mouseMovementExceedsThreshold(const FloatPoint& viewportLocation, int pointsThreshold) const
3486 FrameView* view = m_frame.view();
3489 IntPoint location = view->windowToContents(flooredIntPoint(viewportLocation));
3490 IntSize delta = location - m_mouseDownPos;
3492 return abs(delta.width()) >= pointsThreshold || abs(delta.height()) >= pointsThreshold;
3495 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3497 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3498 // and avoid dispatching text input events from keydown default handlers.
3499 ASSERT(!is<KeyboardEvent>(underlyingEvent) || downcast<KeyboardEvent>(*underlyingEvent).type() == eventNames().keypressEvent);
3501 EventTarget* target;
3502 if (underlyingEvent)
3503 target = underlyingEvent->target();
3505 target = eventTargetElementForDocument(m_frame.document());
3509 if (FrameView* view = m_frame.view())
3510 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3512 RefPtr<TextEvent> event = TextEvent::create(m_frame.document()->domWindow(), text, inputType);
3513 event->setUnderlyingEvent(underlyingEvent);
3515 target->dispatchEvent(event, IGNORE_EXCEPTION);
3516 return event->defaultHandled();
3519 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3522 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3524 && event->keyIdentifier() == "U+0009";
3527 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3529 #if PLATFORM(COCOA) || PLATFORM(EFL)
3530 return EventHandler::isKeyboardOptionTab(event);
3532 UNUSED_PARAM(event);
3537 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3539 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3541 Page* page = m_frame.page();
3545 bool tabsToLinksClientCallResult = page->chrome().client().keyboardUIMode() & KeyboardAccessTabsToLinks;
3546 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3549 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3551 if (m_frame.editor().handleTextEvent(event))
3552 event->setDefaultHandled();
3556 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3558 ASSERT(event->type() == eventNames().keypressEvent);
3560 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3563 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3564 if (logicalScrollOverflow(direction, ScrollByPage)) {
3565 event->setDefaultHandled();
3569 FrameView* view = m_frame.view();
3573 if (view->logicalScroll(direction, ScrollByPage))
3574 event->setDefaultHandled();
3577 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3579 ASSERT(event->type() == eventNames().keydownEvent);
3581 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3584 if (!m_frame.editor().behavior().shouldNavigateBackOnBackspace())
3587 Page* page = m_frame.page();
3591 if (!m_frame.settings().backspaceKeyNavigationEnabled())
3594 bool handledEvent = false;
3596 if (event->shiftKey())
3597 handledEvent = page->backForward().goForward();
3599 handledEvent = page->backForward().goBack();
3602 event->setDefaultHandled();
3606 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3608 ASSERT(event->type() == eventNames().keydownEvent);
3610 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3613 Page* page = m_frame.page();
3617 if (!isSpatialNavigationEnabled(&m_frame))
3620 // Arrows and other possible directional navigation keys can be used in design
3622 if (m_frame.document()->inDesignMode())
3625 if (page->focusController().advanceFocus(focusDirection, event))
3626 event->setDefaultHandled();
3629 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3631 ASSERT(event->type() == eventNames().keydownEvent);
3633 // We should only advance focus on tabs if no special modifier keys are held down.
3634 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3637 Page* page = m_frame.page();
3640 if (!page->tabKeyCyclesThroughElements())
3643 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3645 // Tabs can be used in design mode editing.
3646 if (m_frame.document()->inDesignMode())
3649 if (page->focusController().advanceFocus(focusDirection, event))
3650 event->setDefaultHandled();
3653 void EventHandler::capsLockStateMayHaveChanged()
3655 Document* document = m_frame.document();
3656 if (auto* element = document->focusedElement()) {
3657 if (is<HTMLInputElement>(*element))
3658 downcast<HTMLInputElement>(*element).capsLockStateMayHaveChanged();
3662 void EventHandler::sendScrollEvent()
3664 setFrameWasScrolledByUser();
3665 if (m_frame.view() && m_frame.document())
3666 m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document());
3669 void EventHandler::setFrameWasScrolledByUser()
3671 FrameView* v = m_frame.view();
3673 v->setWasScrolledByUser(true);
3676 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mouseEvent, Scrollbar* scrollbar)
3678 if (!scrollbar || !scrollbar->enabled())
3680 setFrameWasScrolledByUser();
3681 return scrollbar->mouseDown(mouseEvent.event());
3684 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3685 // last to scrollbar if setLast is true; else set last to nullptr.
3686 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3688 if (m_lastScrollbarUnderMouse.get() != scrollbar) {
3689 // Send mouse exited to the old scrollbar.
3690 if (m_lastScrollbarUnderMouse)
3691 m_lastScrollbarUnderMouse->mouseExited();
3693 // Send mouse entered if we're setting a new scrollbar.
3694 if (scrollbar && setLast)
3695 scrollbar->mouseEntered();
3697 if (setLast && scrollbar)
3698 m_lastScrollbarUnderMouse = scrollbar->createWeakPtr();
3700 m_lastScrollbarUnderMouse = nullptr;
3704 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
3705 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3708 case PlatformTouchPoint::TouchReleased:
3709 return eventNames().touchendEvent;
3710 case PlatformTouchPoint::TouchCancelled:
3711 return eventNames().touchcancelEvent;
3712 case PlatformTouchPoint::TouchPressed:
3713 return eventNames().touchstartEvent;
3714 case PlatformTouchPoint::TouchMoved:
3715 return eventNames().touchmoveEvent;
3716 case PlatformTouchPoint::TouchStationary:
3717 // TouchStationary state is not converted to touch events, so fall through to assert.
3719 ASSERT_NOT_REACHED();
3724 static HitTestResult hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3726 HitTestResult result(point);
3728 if (!frame || !frame->contentRenderer())
3731 if (frame->view()) {
3732 IntRect rect = frame->view()->visibleContentRect();
3733 if (!rect.contains(roundedIntPoint(point)))
3736 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3740 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3742 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3743 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3744 // for an overview of how these lists fit together.
3746 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3747 RefPtr<TouchList> touches = TouchList::create();
3749 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3750 // 'targetTouches' list in the JS event.
3751 typedef HashMap<EventTarget*, RefPtr<TouchList>> TargetTouchesMap;
3752 TargetTouchesMap touchesByTarget;
3754 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3755 typedef HashSet<RefPtr<EventTarget>> EventTargetSet;
3757 // The touches corresponding to the particular change state this struct instance represents.
3758 RefPtr<TouchList> m_touches;
3759 // Set of targets involved in m_touches.
3760 EventTargetSet m_targets;
3761 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3763 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3765 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture, m_frame.document());
3768 bool freshTouchEvents = true;
3769 bool allTouchReleased = true;
3770 for (i = 0; i < points.size(); ++i) {
3771 const PlatformTouchPoint& point = points[i];
3772 if (point.state() != PlatformTouchPoint::TouchPressed)
3773 freshTouchEvents = false;
3774 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3775 allTouchReleased = false;
3778 for (i = 0; i < points.size(); ++i) {
3779 const PlatformTouchPoint& point = points[i];
3780 PlatformTouchPoint::State pointState = point.state();
3781 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3783 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3784 // The HitTestRequest types used for mouse events map quite adequately
3785 // to touch events. Note that in addition to meaning that the hit test
3786 // should affect the active state of the current node if necessary,
3787 // HitTestRequest::Active signifies that the hit test is taking place
3788 // with the mouse (or finger in this case) being pressed.
3789 switch (pointState) {
3790 case PlatformTouchPoint::TouchPressed:
3791 hitType |= HitTestRequest::Active;
3793 case PlatformTouchPoint::TouchMoved:
3794 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3796 case PlatformTouchPoint::TouchReleased:
3797 case PlatformTouchPoint::TouchCancelled:
3798 hitType |= HitTestRequest::Release;
3800 case PlatformTouchPoint::TouchStationary:
3801 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3804 ASSERT_NOT_REACHED();
3808 if (shouldGesturesTriggerActive())
3809 hitType |= HitTestRequest::ReadOnly;
3811 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3812 unsigned touchPointTargetKey = point.id() + 1;
3813 RefPtr<EventTarget> touchTarget;
3814 if (pointState == PlatformTouchPoint::TouchPressed) {
3815 HitTestResult result;
3816 if (freshTouchEvents) {
3817 result = hitTestResultAtPoint(pagePoint, hitType);
3818 m_originatingTouchPointTargetKey = touchPointTargetKey;
3819 } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) {
3820 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(*m_originatingTouchPointDocument->frame(), point.pos());
3821 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType);
3822 if (!result.innerNode())
3827 // FIXME: This code should use Element* instead of Node*.
3828 Node* node = result.innerElement();
3831 if (node && InspectorInstrumentation::handleTouchEvent(m_frame, *node))
3834 Document& doc = node->document();
3835 // Record the originating touch document even if it does not have a touch listener.
3836 if (freshTouchEvents) {
3837 m_originatingTouchPointDocument = &doc;
3838 freshTouchEvents = false;
3840 if (!doc.hasTouchEventHandlers())
3842 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3844 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3845 // No need to perform a hit-test since we only need to unset :hover and :active states.
3846 if (!shouldGesturesTriggerActive() && allTouchReleased)
3847 m_frame.document()->updateHoverActiveState(hitType, 0);
3848 if (touchPointTargetKey == m_originatingTouchPointTargetKey)
3849 m_originatingTouchPointTargetKey = 0;
3851 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3852 // we also remove it from the map.
3853 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3855 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3856 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3858 if (!touchTarget.get())
3860 Document& doc = touchTarget->toNode()->document();
3861 if (!doc.hasTouchEventHandlers())
3863 Frame* targetFrame = doc.frame();
3867 if (&m_frame != targetFrame) {
3868 // pagePoint should always be relative to the target elements containing frame.
3869 pagePoint = documentPointForWindowPoint(*targetFrame, point.pos());
3872 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor();
3874 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3875 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3877 RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3878 point.screenPos().x(), point.screenPos().y(),
3879 adjustedPageX, adjustedPageY,
3880 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3882 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3883 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3884 if (targetTouchesIterator == touchesByTarget.end())
3885 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3887 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3888 // released or cancelled it will only appear in the changedTouches list.
3889 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3890 touches->append(touch);
3891 targetTouchesIterator->value->append(touch);
3894 // Now build up the correct list for changedTouches.
3895 // Note that any touches that are in the TouchStationary state (e.g. if
3896 // the user had several points touched but did not move them all) should
3897 // never be in the changedTouches list so we do not handle them explicitly here.
3898 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3899 // about the TouchStationary state.
3900 if (pointState != PlatformTouchPoint::TouchStationary) {
3901 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3902 if (!changedTouches[pointState].m_touches)
3903 changedTouches[pointState].m_touches = TouchList::create();
3904 changedTouches[pointState].m_touches->append(touch);
3905 changedTouches[pointState].m_targets.add(touchTarget);
3908 m_touchPressed = touches->length() > 0;
3909 if (allTouchReleased)
3910 m_originatingTouchPointDocument.clear();
3912 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3913 bool swallowedEvent = false;
3914 RefPtr<TouchList> emptyList = TouchList::create();
3915 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3916 if (!changedTouches[state].m_touches)
3919 // When sending a touch cancel event, use empty touches and targetTouches lists.
3920 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3921 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3922 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3923 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3925 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3926 EventTarget* touchEventTarget = it->get();
3927 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3928 ASSERT(targetTouches);
3930 RefPtr<TouchEvent> touchEvent =
3931 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3932 stateName, touchEventTarget->toNode()->document().defaultView(),
3933 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3934 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3935 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3939 return swallowedEvent;
3941 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
3943 #if ENABLE(TOUCH_EVENTS)
3944 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& platformMouseEvent)
3946 #if ENABLE(IOS_TOUCH_EVENTS)
3947 UNUSED_PARAM(platformMouseEvent);
3950 if (!m_frame.settings().isTouchEventEmulationEnabled())
3953 PlatformEvent::Type eventType = platformMouseEvent.type();
3954 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
3957 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
3958 MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
3959 if (mouseEvent.scrollbar() || subframeForHitTestResult(mouseEvent))
3962 // The order is important. This check should follow the subframe test: http://webkit.org/b/111292.
3963 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
3966 SyntheticSingleTouchEvent touchEvent(platformMouseEvent);
3967 return handleTouchEvent(touchEvent);
3970 #endif // ENABLE(TOUCH_EVENTS)
3972 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3974 m_mousePositionIsUnknown = false;
3975 m_lastKnownMousePosition = event.position();
3976 m_lastKnownMouseGlobalPosition = event.globalPosition();
3979 } // namespace WebCore