2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 COMPUTER, 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 COMPUTER, 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 "core/page/EventHandler.h"
31 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
32 #include "core/HTMLNames.h"
33 #include "core/InputTypeNames.h"
34 #include "core/SVGNames.h"
35 #include "core/clipboard/DataObject.h"
36 #include "core/clipboard/DataTransfer.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/DocumentMarkerController.h"
39 #include "core/dom/Fullscreen.h"
40 #include "core/dom/NodeRenderingTraversal.h"
41 #include "core/dom/TouchList.h"
42 #include "core/dom/shadow/ShadowRoot.h"
43 #include "core/editing/Editor.h"
44 #include "core/editing/FrameSelection.h"
45 #include "core/editing/TextIterator.h"
46 #include "core/editing/htmlediting.h"
47 #include "core/events/DOMWindowEventQueue.h"
48 #include "core/events/EventPath.h"
49 #include "core/events/KeyboardEvent.h"
50 #include "core/events/MouseEvent.h"
51 #include "core/events/TextEvent.h"
52 #include "core/events/TouchEvent.h"
53 #include "core/events/WheelEvent.h"
54 #include "core/fetch/ImageResource.h"
55 #include "core/frame/EventHandlerRegistry.h"
56 #include "core/frame/FrameView.h"
57 #include "core/frame/LocalFrame.h"
58 #include "core/frame/Settings.h"
59 #include "core/html/HTMLDialogElement.h"
60 #include "core/html/HTMLFrameElementBase.h"
61 #include "core/html/HTMLFrameSetElement.h"
62 #include "core/html/HTMLInputElement.h"
63 #include "core/inspector/InspectorController.h"
64 #include "core/loader/FrameLoader.h"
65 #include "core/loader/FrameLoaderClient.h"
66 #include "core/page/AutoscrollController.h"
67 #include "core/page/Chrome.h"
68 #include "core/page/ChromeClient.h"
69 #include "core/page/DragController.h"
70 #include "core/page/DragState.h"
71 #include "core/page/EditorClient.h"
72 #include "core/page/FocusController.h"
73 #include "core/page/FrameTree.h"
74 #include "core/page/Page.h"
75 #include "core/page/SpatialNavigation.h"
76 #include "core/page/TouchAdjustment.h"
77 #include "core/rendering/HitTestRequest.h"
78 #include "core/rendering/HitTestResult.h"
79 #include "core/rendering/RenderFlowThread.h"
80 #include "core/rendering/RenderLayer.h"
81 #include "core/rendering/RenderPart.h"
82 #include "core/rendering/RenderTextControlSingleLine.h"
83 #include "core/rendering/RenderView.h"
84 #include "core/rendering/style/RenderStyle.h"
85 #include "core/svg/SVGDocumentExtensions.h"
86 #include "platform/PlatformGestureEvent.h"
87 #include "platform/PlatformKeyboardEvent.h"
88 #include "platform/PlatformTouchEvent.h"
89 #include "platform/PlatformWheelEvent.h"
90 #include "platform/RuntimeEnabledFeatures.h"
91 #include "platform/TraceEvent.h"
92 #include "platform/WindowsKeyboardCodes.h"
93 #include "platform/geometry/FloatPoint.h"
94 #include "platform/graphics/Image.h"
95 #include "platform/heap/Handle.h"
96 #include "platform/scroll/ScrollAnimator.h"
97 #include "platform/scroll/Scrollbar.h"
98 #include "wtf/Assertions.h"
99 #include "wtf/CurrentTime.h"
100 #include "wtf/StdLibExtras.h"
101 #include "wtf/TemporaryChange.h"
105 using namespace HTMLNames;
107 // The link drag hysteresis is much larger than the others because there
108 // needs to be enough space to cancel the link press without starting a link drag,
109 // and because dragging links is rare.
110 static const int LinkDragHysteresis = 40;
111 static const int ImageDragHysteresis = 5;
112 static const int TextDragHysteresis = 3;
113 static const int GeneralDragHysteresis = 3;
115 // The amount of time to wait before sending a fake mouse event, triggered
116 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
117 // otherwise the long interval is used.
118 static const double fakeMouseMoveShortInterval = 0.1;
119 static const double fakeMouseMoveLongInterval = 0.250;
121 // The amount of time to wait for a cursor update on style and layout changes
122 // Set to 50Hz, no need to be faster than common screen refresh rate
123 static const double cursorUpdateInterval = 0.02;
125 static const int maximumCursorSize = 128;
127 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
128 // need to ensure here is that the scale isn't so small that integer overflow can occur when
129 // dividing cursor sizes (limited above) by the scale.
130 static const double minimumCursorScale = 0.001;
132 // The minimum amount of time an element stays active after a ShowPress
133 // This is roughly 9 frames, which should be long enough to be noticeable.
134 static const double minimumActiveInterval = 0.15;
137 static const double TextDragDelay = 0.15;
139 static const double TextDragDelay = 0.0;
142 enum NoCursorChangeType { NoCursorChange };
144 class OptionalCursor {
146 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
147 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
149 bool isCursorChange() const { return m_isCursorChange; }
150 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
153 bool m_isCursorChange;
157 class MaximumDurationTracker {
159 explicit MaximumDurationTracker(double *maxDuration)
160 : m_maxDuration(maxDuration)
161 , m_start(monotonicallyIncreasingTime())
165 ~MaximumDurationTracker()
167 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
171 double* m_maxDuration;
175 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
178 case WheelEvent::DOM_DELTA_PAGE:
180 case WheelEvent::DOM_DELTA_LINE:
182 case WheelEvent::DOM_DELTA_PIXEL:
183 return ScrollByPixel;
185 return ScrollByPixel;
189 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
190 // If a mouse event handler changes the input element type to one that has a widget associated,
191 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
192 // event target node can't still be the shadow node.
193 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
195 Node* targetNode = mev.innerNode();
196 if (!targetNode || !targetNode->parentNode())
198 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host());
201 EventHandler::EventHandler(LocalFrame* frame)
203 , m_mousePressed(false)
204 , m_capturesDragging(false)
205 , m_mouseDownMayStartSelect(false)
206 , m_mouseDownMayStartDrag(false)
207 , m_mouseDownWasSingleClickInSelection(false)
208 , m_selectionInitiationState(HaveNotStartedSelection)
209 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
210 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
211 , m_mouseDownMayStartAutoscroll(false)
212 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
214 , m_resizeScrollableArea(nullptr)
215 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
217 , m_shouldOnlyFireDragOverEvent(false)
218 , m_mousePositionIsUnknown(true)
219 , m_mouseDownTimestamp(0)
220 , m_widgetIsLatched(false)
221 , m_touchPressed(false)
222 , m_scrollGestureHandlingNode(nullptr)
223 , m_lastGestureScrollOverWidget(false)
224 , m_maxMouseMovedDuration(0)
225 , m_didStartDrag(false)
226 , m_longTapShouldInvokeContextMenu(false)
227 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
228 , m_lastShowPressTimestamp(0)
232 EventHandler::~EventHandler()
234 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
237 void EventHandler::trace(Visitor* visitor)
240 visitor->trace(m_mousePressNode);
241 visitor->trace(m_capturingMouseEventsNode);
242 visitor->trace(m_nodeUnderMouse);
243 visitor->trace(m_lastNodeUnderMouse);
244 visitor->trace(m_lastMouseMoveEventSubframe);
245 visitor->trace(m_lastScrollbarUnderMouse);
246 visitor->trace(m_clickNode);
247 visitor->trace(m_dragTarget);
248 visitor->trace(m_frameSetBeingResized);
249 visitor->trace(m_latchedWheelEventNode);
250 visitor->trace(m_previousWheelScrolledNode);
251 visitor->trace(m_scrollbarHandlingScrollGesture);
252 visitor->trace(m_targetForTouchID);
253 visitor->trace(m_touchSequenceDocument);
254 visitor->trace(m_scrollGestureHandlingNode);
255 visitor->trace(m_previousGestureScrolledNode);
256 visitor->trace(m_lastDeferredTapElement);
260 DragState& EventHandler::dragState()
262 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<DragState>, state, (adoptPtrWillBeNoop(new DragState())));
266 void EventHandler::clear()
269 m_cursorUpdateTimer.stop();
270 m_fakeMouseMoveEventTimer.stop();
271 m_activeIntervalTimer.stop();
272 m_resizeScrollableArea = nullptr;
273 m_nodeUnderMouse = nullptr;
274 m_lastNodeUnderMouse = nullptr;
275 m_lastMouseMoveEventSubframe = nullptr;
276 m_lastScrollbarUnderMouse = nullptr;
278 m_clickNode = nullptr;
279 m_frameSetBeingResized = nullptr;
280 m_dragTarget = nullptr;
281 m_shouldOnlyFireDragOverEvent = false;
282 m_mousePositionIsUnknown = true;
283 m_lastKnownMousePosition = IntPoint();
284 m_lastKnownMouseGlobalPosition = IntPoint();
285 m_lastMouseDownUserGestureToken.clear();
286 m_mousePressNode = nullptr;
287 m_mousePressed = false;
288 m_capturesDragging = false;
289 m_capturingMouseEventsNode = nullptr;
290 m_latchedWheelEventNode = nullptr;
291 m_previousWheelScrolledNode = nullptr;
292 m_targetForTouchID.clear();
293 m_touchSequenceDocument.clear();
294 m_touchSequenceUserGestureToken.clear();
295 m_scrollGestureHandlingNode = nullptr;
296 m_lastGestureScrollOverWidget = false;
297 m_previousGestureScrolledNode = nullptr;
298 m_scrollbarHandlingScrollGesture = nullptr;
299 m_maxMouseMovedDuration = 0;
300 m_didStartDrag = false;
301 m_touchPressed = false;
302 m_mouseDownMayStartSelect = false;
303 m_mouseDownMayStartDrag = false;
304 m_lastShowPressTimestamp = 0;
305 m_lastDeferredTapElement = nullptr;
308 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
310 if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
312 if (nodeToBeRemoved.isInShadowTree()) {
313 m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
315 // We don't dispatch click events if the mousedown node is removed
316 // before a mouseup event. It is compatible with IE and Firefox.
317 m_clickNode = nullptr;
321 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
323 if (selection.selection() != newSelection)
324 selection.setSelection(newSelection);
327 static inline bool dispatchSelectStart(Node* node)
329 if (!node || !node->renderer())
332 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
335 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
337 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
338 if (!rootUserSelectAll)
341 VisibleSelection newSelection(selection);
342 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
343 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
348 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
350 if (Position::nodeIsUserSelectNone(targetNode))
353 if (!dispatchSelectStart(targetNode))
356 if (selection.isRange())
357 m_selectionInitiationState = ExtendedSelection;
359 granularity = CharacterGranularity;
360 m_selectionInitiationState = PlacedCaret;
363 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
368 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
370 Node* innerNode = result.innerNode();
371 VisibleSelection newSelection;
373 if (innerNode && innerNode->renderer()) {
374 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
375 if (pos.isNotNull()) {
376 newSelection = VisibleSelection(pos);
377 newSelection.expandUsingGranularity(WordGranularity);
380 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
381 newSelection.appendTrailingWhitespace();
383 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
387 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
389 Node* innerNode = result.innerNode();
390 VisibleSelection newSelection;
392 if (innerNode && innerNode->renderer()) {
393 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
394 Position start = pos.deepEquivalent();
395 Position end = pos.deepEquivalent();
396 if (pos.isNotNull()) {
397 DocumentMarkerVector markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
398 if (markers.size() == 1) {
399 start.moveToOffset(markers[0]->startOffset());
400 end.moveToOffset(markers[0]->endOffset());
401 newSelection = VisibleSelection(start, end);
405 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
406 newSelection.appendTrailingWhitespace();
408 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
412 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
414 if (m_mouseDownMayStartSelect) {
415 selectClosestWordFromHitTestResult(result.hitTestResult(),
416 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
420 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
422 if (m_mouseDownMayStartSelect) {
423 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
424 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
428 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
430 if (!result.hitTestResult().isLiveLink())
431 return selectClosestWordFromMouseEvent(result);
433 Node* innerNode = result.innerNode();
435 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
436 VisibleSelection newSelection;
437 Element* URLElement = result.hitTestResult().URLElement();
438 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
439 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
440 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
442 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
446 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
448 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventDoubleClick");
450 if (event.event().button() != LeftButton)
453 if (m_frame->selection().isRange()) {
454 // A double-click when range is already selected
455 // should not change the selection. So, do not call
456 // selectClosestWordFromMouseEvent, but do set
457 // m_beganSelectingText to prevent handleMouseReleaseEvent
458 // from setting caret selection.
459 m_selectionInitiationState = ExtendedSelection;
461 selectClosestWordFromMouseEvent(event);
466 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
468 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventTripleClick");
470 if (event.event().button() != LeftButton)
473 Node* innerNode = event.innerNode();
474 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
477 VisibleSelection newSelection;
478 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
479 if (pos.isNotNull()) {
480 newSelection = VisibleSelection(pos);
481 newSelection.expandUsingGranularity(ParagraphGranularity);
484 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
487 static int textDistance(const Position& start, const Position& end)
489 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, end);
490 return TextIterator::rangeLength(range.get(), true);
493 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
495 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventSingleClick");
497 m_frame->document()->updateLayoutIgnorePendingStylesheets();
498 Node* innerNode = event.innerNode();
499 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
502 // Extend the selection if the Shift key is down, unless the click is in a link.
503 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
505 // Don't restart the selection when the mouse is pressed on an
506 // existing selection so we can allow for text dragging.
507 if (FrameView* view = m_frame->view()) {
508 LayoutPoint vPoint = view->windowToContents(event.event().position());
509 if (!extendSelection && m_frame->selection().contains(vPoint)) {
510 m_mouseDownWasSingleClickInSelection = true;
515 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
516 if (visiblePos.isNull())
517 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
518 Position pos = visiblePos.deepEquivalent();
520 VisibleSelection newSelection = m_frame->selection().selection();
521 TextGranularity granularity = CharacterGranularity;
523 if (extendSelection && newSelection.isCaretOrRange()) {
524 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
525 if (selectionInUserSelectAll.isRange()) {
526 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
527 pos = selectionInUserSelectAll.start();
528 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
529 pos = selectionInUserSelectAll.end();
532 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
533 if (pos.isNotNull()) {
534 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
535 // was created right-to-left
536 Position start = newSelection.start();
537 Position end = newSelection.end();
538 int distanceToStart = textDistance(start, pos);
539 int distanceToEnd = textDistance(pos, end);
540 if (distanceToStart <= distanceToEnd)
541 newSelection = VisibleSelection(end, pos);
543 newSelection = VisibleSelection(start, pos);
546 newSelection.setExtent(pos);
548 if (m_frame->selection().granularity() != CharacterGranularity) {
549 granularity = m_frame->selection().granularity();
550 newSelection.expandUsingGranularity(m_frame->selection().granularity());
553 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos));
556 // Updating the selection is considered side-effect of the event and so it doesn't impact the handled state.
557 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
561 static inline bool canMouseDownStartSelect(Node* node)
563 if (!node || !node->renderer())
566 if (!node->canStartSelection())
572 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
574 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent");
577 dragState().m_dragSrc = nullptr;
579 cancelFakeMouseMoveEvent();
581 m_frame->document()->updateLayoutIgnorePendingStylesheets();
583 if (FrameView* frameView = m_frame->view()) {
584 if (frameView->isPointInScrollbarCorner(event.event().position()))
588 bool singleClick = event.event().clickCount() <= 1;
590 // If we got the event back, that must mean it wasn't prevented,
591 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
592 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !event.scrollbar();
594 m_mouseDownMayStartDrag = singleClick;
596 m_mouseDownWasSingleClickInSelection = false;
598 m_mouseDown = event.event();
600 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
603 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGExtensions().zoomAndPanEnabled()) {
604 if (event.event().shiftKey() && singleClick) {
606 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()->windowToContents(event.event().position()));
611 // We don't do this at the start of mouse down handling,
612 // because we don't want to do it until we know we didn't hit a widget.
616 Node* innerNode = event.innerNode();
618 m_mousePressNode = innerNode;
619 m_dragStartPos = event.event().position();
621 bool swallowEvent = false;
622 m_mousePressed = true;
624 if (event.event().clickCount() == 2)
625 swallowEvent = handleMousePressEventDoubleClick(event);
626 else if (event.event().clickCount() >= 3)
627 swallowEvent = handleMousePressEventTripleClick(event);
629 swallowEvent = handleMousePressEventSingleClick(event);
631 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
632 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
637 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
639 TRACE_EVENT0("blink", "EventHandler::handleMouseDraggedEvent");
644 if (handleDrag(event, ShouldCheckDragHysteresis))
647 Node* targetNode = event.innerNode();
648 if (event.event().button() != LeftButton || !targetNode)
651 RenderObject* renderer = targetNode->renderer();
653 Node* parent = NodeRenderingTraversal::parent(targetNode);
657 renderer = parent->renderer();
658 if (!renderer || !renderer->isListBox())
662 m_mouseDownMayStartDrag = false;
664 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
665 if (AutoscrollController* controller = autoscrollController()) {
666 controller->startAutoscrollForSelection(renderer);
667 m_mouseDownMayStartAutoscroll = false;
671 if (m_selectionInitiationState != ExtendedSelection) {
672 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
673 HitTestResult result(m_mouseDownPos);
674 m_frame->document()->renderView()->hitTest(request, result);
676 updateSelectionForMouseDrag(result);
678 updateSelectionForMouseDrag(event.hitTestResult());
682 void EventHandler::updateSelectionForMouseDrag()
684 FrameView* view = m_frame->view();
687 RenderView* renderer = m_frame->contentRenderer();
691 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move);
692 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
693 renderer->hitTest(request, result);
694 updateSelectionForMouseDrag(result);
697 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
699 if (!m_mouseDownMayStartSelect)
702 Node* target = hitTestResult.innerNode();
706 VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
707 // Don't modify the selection if we're not on a node.
708 if (targetPosition.isNull())
711 // Restart the selection if this is the first mouse move. This work is usually
712 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
713 VisibleSelection newSelection = m_frame->selection().selection();
715 // Special case to limit selection to the containing block for SVG text.
716 // FIXME: Isn't there a better non-SVG-specific way to do this?
717 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
718 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
719 if (selectionBaseRenderer->isSVGText())
720 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
723 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
726 if (m_selectionInitiationState != ExtendedSelection) {
727 // Always extend selection here because it's caused by a mouse drag
728 m_selectionInitiationState = ExtendedSelection;
729 newSelection = VisibleSelection(targetPosition);
732 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
733 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
734 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
735 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
736 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
738 // Reset base for user select all when base is inside user-select-all area and extent < base.
739 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
740 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
742 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
743 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
744 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
745 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
746 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
748 newSelection.setExtent(targetPosition);
751 newSelection.setExtent(targetPosition);
754 if (m_frame->selection().granularity() != CharacterGranularity)
755 newSelection.expandUsingGranularity(m_frame->selection().granularity());
757 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
758 FrameSelection::AdjustEndpointsAtBidiBoundary);
761 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
763 AutoscrollController* controller = autoscrollController();
764 if (controller && controller->autoscrollInProgress())
767 // Used to prevent mouseMoveEvent from initiating a drag before
768 // the mouse is pressed again.
769 m_mousePressed = false;
770 m_capturesDragging = false;
771 m_mouseDownMayStartDrag = false;
772 m_mouseDownMayStartSelect = false;
773 m_mouseDownMayStartAutoscroll = false;
775 bool handled = false;
777 // Clear the selection if the mouse didn't move after the last mouse
778 // press and it's not a context menu click. We do this so when clicking
779 // on the selection, the selection goes away. However, if we are
780 // editing, place the caret.
781 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
782 && m_dragStartPos == event.event().position()
783 && m_frame->selection().isRange()
784 && event.event().button() != RightButton) {
785 VisibleSelection newSelection;
786 Node* node = event.innerNode();
787 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
788 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
789 VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
790 newSelection = VisibleSelection(pos);
793 setSelectionIfNeeded(m_frame->selection(), newSelection);
798 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
800 m_frame->selection().selectFrameElementInParentIfFullySelected();
802 if (event.event().button() == MiddleButton && !event.isOverLink()) {
803 // Ignore handled, since we want to paste to where the caret was placed anyway.
804 handled = handlePasteGlobalSelection(event.event()) || handled;
812 void EventHandler::startPanScrolling(RenderObject* renderer)
814 if (!renderer->isBox())
816 AutoscrollController* controller = autoscrollController();
819 controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
825 AutoscrollController* EventHandler::autoscrollController() const
827 if (Page* page = m_frame->page())
828 return &page->autoscrollController();
832 bool EventHandler::panScrollInProgress() const
834 return autoscrollController() && autoscrollController()->panScrollInProgress();
837 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
839 TRACE_EVENT0("blink", "EventHandler::hitTestResultAtPoint");
841 // We always send hitTestResultAtPoint to the main frame if we have one,
842 // otherwise we might hit areas that are obscured by higher frames.
843 if (m_frame->page()) {
844 LocalFrame* mainFrame = m_frame->localFrameRoot();
845 if (mainFrame && m_frame != mainFrame) {
846 FrameView* frameView = m_frame->view();
847 FrameView* mainView = mainFrame->view();
848 if (frameView && mainView) {
849 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
850 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
855 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
857 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
858 // layout because until then, there is nothing shown on the screen - the user can't
859 // have intentionally clicked on something belonging to this page. Furthermore,
860 // mousemove events before the first layout should not lead to a premature layout()
861 // happening, which could show a flash of white.
862 // See also the similar code in Document::prepareMouseEvent.
863 if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
866 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
867 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
868 m_frame->contentRenderer()->hitTest(request, result);
869 if (!request.readOnly())
870 m_frame->document()->updateHoverActiveState(request, result.innerElement());
875 void EventHandler::stopAutoscroll()
877 if (AutoscrollController* controller = autoscrollController())
878 controller->stopAutoscroll();
881 Node* EventHandler::mousePressNode() const
883 return m_mousePressNode.get();
886 bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoint absolutePoint)
891 Node* node = startNode;
894 node = m_frame->document()->focusedElement();
897 node = m_mousePressNode.get();
899 if (!node || !node->renderer())
902 bool rootLayerScrolls = m_frame->settings() && m_frame->settings()->rootLayerScrolls();
903 RenderBox* curBox = node->renderer()->enclosingBox();
904 while (curBox && (rootLayerScrolls || !curBox->isRenderView())) {
905 ScrollDirection physicalDirection = toPhysicalDirection(
906 direction, curBox->isHorizontalWritingMode(), curBox->style()->slowIsFlippedBlocksWritingMode());
908 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
909 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *stopNode;
910 bool didScroll = curBox->scroll(physicalDirection, granularity, delta);
912 if (didScroll && stopNode)
913 *stopNode = curBox->node();
915 if (didScroll || shouldStopBubbling) {
916 setFrameWasScrolledByUser();
920 curBox = curBox->containingBlock();
926 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
928 // The layout needs to be up to date to determine if we can scroll. We may be
929 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
930 m_frame->document()->updateLayoutIgnorePendingStylesheets();
931 if (scroll(direction, granularity, startingNode))
933 LocalFrame* frame = m_frame;
934 FrameView* view = frame->view();
935 if (view && view->scroll(direction, granularity))
937 Frame* parentFrame = frame->tree().parent();
938 if (!parentFrame || !parentFrame->isLocalFrame())
940 // FIXME: Broken for OOPI.
941 return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, granularity, m_frame->deprecatedLocalOwner());
944 IntPoint EventHandler::lastKnownMousePosition() const
946 return m_lastKnownMousePosition;
949 static LocalFrame* subframeForTargetNode(Node* node)
954 RenderObject* renderer = node->renderer();
955 if (!renderer || !renderer->isRenderPart())
958 // FIXME: This explicit check is needed only until RemoteFrames have RemoteFrameViews.
959 if (isHTMLFrameElementBase(node) && toHTMLFrameElementBase(node)->contentFrame() && toHTMLFrameElementBase(node)->contentFrame()->isRemoteFrameTemporary())
962 Widget* widget = toRenderPart(renderer)->widget();
963 if (!widget || !widget->isFrameView())
966 return &toFrameView(widget)->frame();
969 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
971 if (!hitTestResult.isOverWidget())
973 return subframeForTargetNode(hitTestResult.innerNode());
976 static bool isSubmitImage(Node* node)
978 return isHTMLInputElement(node) && toHTMLInputElement(node)->type() == InputTypeNames::image;
981 bool EventHandler::useHandCursor(Node* node, bool isOverLink)
986 return ((isOverLink || isSubmitImage(node)) && !node->hasEditableStyle());
989 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
992 ASSERT(m_frame->document());
997 void EventHandler::updateCursor()
999 if (m_mousePositionIsUnknown)
1002 FrameView* view = m_frame->view();
1003 if (!view || !view->shouldSetCursor())
1006 RenderView* renderView = view->renderView();
1010 m_frame->document()->updateLayout();
1012 HitTestRequest request(HitTestRequest::ReadOnly);
1013 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1014 renderView->hitTest(request, result);
1016 OptionalCursor optionalCursor = selectCursor(result);
1017 if (optionalCursor.isCursorChange()) {
1018 m_currentMouseCursor = optionalCursor.cursor();
1019 view->setCursor(m_currentMouseCursor);
1023 OptionalCursor EventHandler::selectCursor(const HitTestResult& result)
1025 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1026 return NoCursorChange;
1028 Page* page = m_frame->page();
1030 return NoCursorChange;
1032 if (panScrollInProgress())
1033 return NoCursorChange;
1036 Node* node = result.innerPossiblyPseudoNode();
1038 return selectAutoCursor(result, node, iBeamCursor());
1040 RenderObject* renderer = node->renderer();
1041 RenderStyle* style = renderer ? renderer->style() : nullptr;
1044 Cursor overrideCursor;
1045 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1046 case SetCursorBasedOnStyle:
1049 return overrideCursor;
1050 case DoNotSetCursor:
1051 return NoCursorChange;
1055 if (style && style->cursors()) {
1056 const CursorList* cursors = style->cursors();
1057 for (unsigned i = 0; i < cursors->size(); ++i) {
1058 StyleImage* styleImage = (*cursors)[i].image();
1061 ImageResource* cachedImage = styleImage->cachedImage();
1064 float scale = styleImage->imageScaleFactor();
1065 // Get hotspot and convert from logical pixels to physical pixels.
1066 IntPoint hotSpot = (*cursors)[i].hotSpot();
1067 hotSpot.scale(scale, scale);
1068 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1069 if (cachedImage->errorOccurred())
1071 // Limit the size of cursors (in UI pixels) so that they cannot be
1072 // used to cover UI elements in chrome.
1073 size.scale(1 / scale);
1074 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1077 Image* image = cachedImage->imageForRenderer(renderer);
1078 // Ensure no overflow possible in calculations above.
1079 if (scale < minimumCursorScale)
1081 return Cursor(image, hotSpot, scale);
1085 switch (style ? style->cursor() : CURSOR_AUTO) {
1087 bool horizontalText = !style || style->isHorizontalWritingMode();
1088 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1089 return selectAutoCursor(result, node, iBeam);
1092 return crossCursor();
1093 case CURSOR_POINTER:
1094 return handCursor();
1096 return moveCursor();
1097 case CURSOR_ALL_SCROLL:
1098 return moveCursor();
1099 case CURSOR_E_RESIZE:
1100 return eastResizeCursor();
1101 case CURSOR_W_RESIZE:
1102 return westResizeCursor();
1103 case CURSOR_N_RESIZE:
1104 return northResizeCursor();
1105 case CURSOR_S_RESIZE:
1106 return southResizeCursor();
1107 case CURSOR_NE_RESIZE:
1108 return northEastResizeCursor();
1109 case CURSOR_SW_RESIZE:
1110 return southWestResizeCursor();
1111 case CURSOR_NW_RESIZE:
1112 return northWestResizeCursor();
1113 case CURSOR_SE_RESIZE:
1114 return southEastResizeCursor();
1115 case CURSOR_NS_RESIZE:
1116 return northSouthResizeCursor();
1117 case CURSOR_EW_RESIZE:
1118 return eastWestResizeCursor();
1119 case CURSOR_NESW_RESIZE:
1120 return northEastSouthWestResizeCursor();
1121 case CURSOR_NWSE_RESIZE:
1122 return northWestSouthEastResizeCursor();
1123 case CURSOR_COL_RESIZE:
1124 return columnResizeCursor();
1125 case CURSOR_ROW_RESIZE:
1126 return rowResizeCursor();
1128 return iBeamCursor();
1130 return waitCursor();
1132 return helpCursor();
1133 case CURSOR_VERTICAL_TEXT:
1134 return verticalTextCursor();
1136 return cellCursor();
1137 case CURSOR_CONTEXT_MENU:
1138 return contextMenuCursor();
1139 case CURSOR_PROGRESS:
1140 return progressCursor();
1141 case CURSOR_NO_DROP:
1142 return noDropCursor();
1144 return aliasCursor();
1146 return copyCursor();
1148 return noneCursor();
1149 case CURSOR_NOT_ALLOWED:
1150 return notAllowedCursor();
1151 case CURSOR_DEFAULT:
1152 return pointerCursor();
1153 case CURSOR_ZOOM_IN:
1154 return zoomInCursor();
1155 case CURSOR_ZOOM_OUT:
1156 return zoomOutCursor();
1157 case CURSOR_WEBKIT_GRAB:
1158 return grabCursor();
1159 case CURSOR_WEBKIT_GRABBING:
1160 return grabbingCursor();
1162 return pointerCursor();
1165 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam)
1167 bool editable = (node && node->hasEditableStyle());
1169 if (useHandCursor(node, result.isOverLink()))
1170 return handCursor();
1172 bool inResizer = false;
1173 RenderObject* renderer = node ? node->renderer() : nullptr;
1174 if (renderer && m_frame->view()) {
1175 RenderLayer* layer = renderer->enclosingLayer();
1176 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1179 // During selection, use an I-beam no matter what we're over.
1180 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1181 if (m_mousePressed && m_mouseDownMayStartSelect
1182 && !m_mouseDownMayStartDrag
1183 && m_frame->selection().isCaretOrRange()
1184 && !m_capturingMouseEventsNode) {
1188 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1190 return pointerCursor();
1193 static LayoutPoint documentPointForWindowPoint(LocalFrame* frame, const IntPoint& windowPoint)
1195 FrameView* view = frame->view();
1196 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1197 // Historically the code would just crash; this is clearly no worse than that.
1198 return view ? view->windowToContents(windowPoint) : windowPoint;
1201 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1203 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent");
1205 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1207 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1208 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1210 cancelFakeMouseMoveEvent();
1211 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1212 m_capturingMouseEventsNode = nullptr;
1213 m_mousePressed = true;
1214 m_capturesDragging = true;
1215 setLastKnownMousePosition(mouseEvent);
1216 m_mouseDownTimestamp = mouseEvent.timestamp();
1217 m_mouseDownMayStartDrag = false;
1218 m_mouseDownMayStartSelect = false;
1219 m_mouseDownMayStartAutoscroll = false;
1220 if (FrameView* view = m_frame->view())
1221 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1227 HitTestRequest request(HitTestRequest::Active);
1228 // Save the document point we generate in case the window coordinate is invalidated by what happens
1229 // when we dispatch the event.
1230 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1231 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1233 if (!mev.innerNode()) {
1238 m_mousePressNode = mev.innerNode();
1240 RefPtrWillBeRawPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1241 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1242 // Start capturing future events for this frame. We only do this if we didn't clear
1243 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1244 m_capturesDragging = subframe->eventHandler().capturesDragging();
1245 if (m_mousePressed && m_capturesDragging) {
1246 m_capturingMouseEventsNode = mev.innerNode();
1247 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1254 // We store whether pan scrolling is in progress before calling stopAutoscroll()
1255 // because it will set m_autoscrollType to NoAutoscroll on return.
1256 bool isPanScrollInProgress = panScrollInProgress();
1258 if (isPanScrollInProgress) {
1259 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1260 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1266 m_clickCount = mouseEvent.clickCount();
1267 m_clickNode = mev.innerNode()->isTextNode() ? NodeRenderingTraversal::parent(mev.innerNode()) : mev.innerNode();
1269 if (FrameView* view = m_frame->view()) {
1270 RenderLayer* layer = mev.innerNode()->renderer() ? mev.innerNode()->renderer()->enclosingLayer() : nullptr;
1271 IntPoint p = view->windowToContents(mouseEvent.position());
1272 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1273 m_resizeScrollableArea = layer->scrollableArea();
1274 m_resizeScrollableArea->setInResizeMode(true);
1275 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1281 m_frame->selection().setCaretBlinkingSuspended(true);
1283 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.innerNode(), m_clickCount, mouseEvent, true);
1284 // m_selectionInitiationState is initialized after dispatching mousedown event in order not to keep the selection by DOM APIs
1285 // Because we can't give the user the chance to handle the selection by user action like dragging if we keep the selection in case of mousedown.
1286 // FireFox also has the same behavior and it's more compatible with other browsers.
1287 m_selectionInitiationState = HaveNotStartedSelection;
1288 HitTestResult hitTestResult = hitTestResultInFrame(m_frame, mouseEvent.position(), HitTestRequest::ReadOnly);
1289 swallowEvent = swallowEvent || handleMouseFocus(MouseEventWithHitTestResults(mouseEvent, hitTestResult));
1290 m_capturesDragging = !swallowEvent || mev.scrollbar();
1292 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1293 // in case the scrollbar widget was destroyed when the mouse event was handled.
1294 if (mev.scrollbar()) {
1295 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1296 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1297 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1298 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1299 m_lastScrollbarUnderMouse = nullptr;
1303 // scrollbars should get events anyway, even disabled controls might be scrollable
1304 passMousePressEventToScrollbar(mev);
1306 if (shouldRefetchEventTarget(mev)) {
1307 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1308 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1311 if (passMousePressEventToScrollbar(mev))
1312 swallowEvent = true;
1314 swallowEvent = handleMousePressEvent(mev);
1317 return swallowEvent;
1320 static RenderLayer* layerForNode(Node* node)
1325 RenderObject* renderer = node->renderer();
1329 RenderLayer* layer = renderer->enclosingLayer();
1336 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1338 if (RenderLayerScrollableArea* scrollableArea = layer->scrollableArea()) {
1339 if (scrollableArea->scrollsOverflow())
1340 return scrollableArea;
1346 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1348 TRACE_EVENT0("blink", "EventHandler::handleMouseMoveEvent");
1350 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1351 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1353 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1354 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1356 Page* page = m_frame->page();
1360 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1361 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1362 layerScrollableArea->mouseMovedInContentArea();
1365 if (FrameView* frameView = m_frame->view())
1366 frameView->mouseMovedInContentArea();
1368 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1369 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1370 page->chrome().setToolTip(hoveredNode);
1375 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1377 TRACE_EVENT0("blink", "EventHandler::handleMouseLeaveEvent");
1379 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1380 handleMouseMoveOrLeaveEvent(event);
1383 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1386 ASSERT(m_frame->view());
1388 setLastKnownMousePosition(mouseEvent);
1390 if (m_hoverTimer.isActive())
1391 m_hoverTimer.stop();
1393 m_cursorUpdateTimer.stop();
1395 cancelFakeMouseMoveEvent();
1398 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1402 if (m_frameSetBeingResized)
1403 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), 0, mouseEvent, false);
1405 // Send events right to a scrollbar if the mouse is pressed.
1406 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1407 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1411 // Mouse events simulated from touch should not hit-test again.
1412 ASSERT(!mouseEvent.fromTouch());
1414 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move;
1416 hitType |= HitTestRequest::Active;
1417 else if (onlyUpdateScrollbars) {
1418 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1419 // means that :hover and :active freeze in the state they were in, rather than updating
1420 // for nodes the mouse moves while the window is not key (which will be the case if
1421 // onlyUpdateScrollbars is true).
1422 hitType |= HitTestRequest::ReadOnly;
1425 // Treat any mouse move events as readonly if the user is currently touching the screen.
1427 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1428 HitTestRequest request(hitType);
1429 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1431 *hoveredNode = mev.hitTestResult();
1433 Scrollbar* scrollbar = nullptr;
1435 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1436 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1439 scrollbar = mev.scrollbar();
1441 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1442 if (onlyUpdateScrollbars)
1446 bool swallowEvent = false;
1447 RefPtrWillBeRawPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1449 // 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.
1450 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1451 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1454 // Update over/out state before passing the event to the subframe.
1455 updateMouseEventTargetNode(mev.innerNode(), mouseEvent, true);
1457 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1458 // node to be detached from its FrameView, in which case the event should not be passed.
1459 if (newSubframe->view())
1460 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1462 if (scrollbar && !m_mousePressed)
1463 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1464 if (FrameView* view = m_frame->view()) {
1465 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult());
1466 if (optionalCursor.isCursorChange()) {
1467 m_currentMouseCursor = optionalCursor.cursor();
1468 view->setCursor(m_currentMouseCursor);
1473 m_lastMouseMoveEventSubframe = newSubframe;
1478 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.innerNode(), 0, mouseEvent, true);
1480 swallowEvent = handleMouseDraggedEvent(mev);
1482 return swallowEvent;
1485 void EventHandler::invalidateClick()
1488 m_clickNode = nullptr;
1491 static Node* parentForClickEvent(const Node& node)
1493 // IE doesn't dispatch click events for mousedown/mouseup events across form
1495 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1497 return NodeRenderingTraversal::parent(&node);
1500 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1502 TRACE_EVENT0("blink", "EventHandler::handleMouseReleaseEvent");
1504 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1506 m_frame->selection().setCaretBlinkingSuspended(false);
1508 OwnPtr<UserGestureIndicator> gestureIndicator;
1510 if (m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken)
1511 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1513 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1516 if (Page* page = m_frame->page())
1517 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1520 m_mousePressed = false;
1521 setLastKnownMousePosition(mouseEvent);
1525 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1529 if (m_frameSetBeingResized)
1530 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), m_clickCount, mouseEvent, false);
1532 if (m_lastScrollbarUnderMouse) {
1534 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1535 bool setUnder = false;
1536 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), m_clickCount, mouseEvent, setUnder);
1539 // Mouse events simulated from touch should not hit-test again.
1540 ASSERT(!mouseEvent.fromTouch());
1542 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release;
1543 HitTestRequest request(hitType);
1544 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1545 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1546 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1547 m_capturingMouseEventsNode = nullptr;
1548 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1551 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.innerNode(), m_clickCount, mouseEvent, false);
1553 bool contextMenuEvent = mouseEvent.button() == RightButton;
1555 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1556 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1557 contextMenuEvent = true;
1560 bool swallowClickEvent = false;
1561 if (m_clickCount > 0 && !contextMenuEvent && mev.innerNode() && m_clickNode) {
1562 // Updates distribution because a 'mouseup' event listener can make the
1563 // tree dirty at dispatchMouseEvent() invocation above.
1564 // Unless distribution is updated, commonAncestor would hit ASSERT.
1565 // Both m_clickNode and mev.innerNode() don't need to be updated
1566 // because commonAncestor() will exit early if their documents are different.
1567 m_clickNode->document().updateDistributionForNodeIfNeeded(m_clickNode.get());
1568 if (Node* clickTargetNode = mev.innerNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1569 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, m_clickCount, mouseEvent, true);
1572 if (m_resizeScrollableArea) {
1573 m_resizeScrollableArea->setInResizeMode(false);
1574 m_resizeScrollableArea = nullptr;
1577 bool swallowMouseReleaseEvent = false;
1578 if (!swallowMouseUpEvent)
1579 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1583 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1586 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1588 // If the event was a middle click, attempt to copy global selection in after
1589 // the newly set caret position.
1591 // This code is called from either the mouse up or mouse down handling. There
1592 // is some debate about when the global selection is pasted:
1593 // xterm: pastes on up.
1594 // GTK: pastes on down.
1595 // Qt: pastes on up.
1596 // Firefox: pastes on up.
1597 // Chromium: pastes on up.
1599 // There is something of a webcompat angle to this well, as highlighted by
1600 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1601 // down then the text is pasted just before the onclick handler runs and
1602 // clears the text box. So it's important this happens after the event
1603 // handlers have been fired.
1604 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1607 if (!m_frame->page())
1609 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1610 // Do not paste here if the focus was moved somewhere else.
1611 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1612 return m_frame->editor().command("PasteGlobalSelection").execute();
1618 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
1620 FrameView* view = m_frame->view();
1622 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1626 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType,
1627 true, true, m_frame->document()->domWindow(),
1628 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1629 event.movementDelta().x(), event.movementDelta().y(),
1630 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1631 0, nullptr, dataTransfer);
1633 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1634 return me->defaultPrevented();
1637 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1639 if (!isHTMLFrameElementBase(target))
1642 // Cross-process drag and drop is not yet supported.
1643 if (toHTMLFrameElementBase(target)->contentFrame() && !toHTMLFrameElementBase(target)->contentFrame()->isLocalFrame())
1646 frame = toLocalFrame(toHTMLFrameElementBase(target)->contentFrame());
1650 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
1652 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1653 for (; element; element = element->parentElement()) {
1654 bool matched = false;
1655 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1657 if (dropZoneStr.isEmpty())
1660 UseCounter::count(element->document(), UseCounter::PrefixedHTMLElementDropzone);
1662 dropZoneStr = dropZoneStr.lower();
1664 SpaceSplitString keywords(dropZoneStr, false);
1665 if (keywords.isNull())
1668 DragOperation dragOperation = DragOperationNone;
1669 for (unsigned i = 0; i < keywords.size(); i++) {
1670 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1671 if (op != DragOperationNone) {
1672 if (dragOperation == DragOperationNone)
1675 matched = matched || dataTransfer->hasDropZoneType(keywords[i].string());
1678 if (matched && dragOperation != DragOperationNone)
1682 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1689 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
1691 bool accept = false;
1693 if (!m_frame->view())
1696 HitTestRequest request(HitTestRequest::ReadOnly);
1697 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1699 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1700 RefPtrWillBeRawPtr<Node> newTarget = mev.innerNode();
1701 if (newTarget && newTarget->isTextNode())
1702 newTarget = NodeRenderingTraversal::parent(newTarget.get());
1704 if (AutoscrollController* controller = autoscrollController())
1705 controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1707 if (m_dragTarget != newTarget) {
1708 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1709 // it is sometimes incorrect when dragging within subframes, as seen with
1710 // LayoutTests/fast/events/drag-in-frames.html.
1712 // 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>.
1713 LocalFrame* targetFrame;
1714 if (targetIsFrame(newTarget.get(), targetFrame)) {
1716 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
1717 } else if (newTarget) {
1718 // 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.
1719 if (dragState().m_dragSrc) {
1720 // for now we don't care if event handler cancels default behavior, since there is none
1721 dispatchDragSrcEvent(EventTypeNames::drag, event);
1723 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, dataTransfer);
1725 accept = findDropZone(newTarget.get(), dataTransfer);
1728 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1730 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
1731 } else if (m_dragTarget) {
1732 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, dataTransfer);
1736 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1737 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1738 m_shouldOnlyFireDragOverEvent = true;
1741 LocalFrame* targetFrame;
1742 if (targetIsFrame(newTarget.get(), targetFrame)) {
1744 accept = targetFrame->eventHandler().updateDragAndDrop(event, dataTransfer);
1745 } else if (newTarget) {
1746 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1747 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1748 // for now we don't care if event handler cancels default behavior, since there is none
1749 dispatchDragSrcEvent(EventTypeNames::drag, event);
1751 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, dataTransfer);
1753 accept = findDropZone(newTarget.get(), dataTransfer);
1754 m_shouldOnlyFireDragOverEvent = false;
1757 m_dragTarget = newTarget;
1762 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
1764 LocalFrame* targetFrame;
1765 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1767 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
1768 } else if (m_dragTarget.get()) {
1769 if (dragState().m_dragSrc)
1770 dispatchDragSrcEvent(EventTypeNames::drag, event);
1771 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, dataTransfer);
1776 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTransfer* dataTransfer)
1778 LocalFrame* targetFrame;
1779 bool preventedDefault = false;
1780 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1782 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, dataTransfer);
1783 } else if (m_dragTarget.get()) {
1784 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, dataTransfer);
1787 return preventedDefault;
1790 void EventHandler::clearDragState()
1793 m_dragTarget = nullptr;
1794 m_capturingMouseEventsNode = nullptr;
1795 m_shouldOnlyFireDragOverEvent = false;
1798 void EventHandler::setCapturingMouseEventsNode(PassRefPtrWillBeRawPtr<Node> n)
1800 m_capturingMouseEventsNode = n;
1801 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1804 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1807 ASSERT(m_frame->document());
1809 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1812 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1814 Node* result = targetNode;
1816 // If we're capturing, we always go right to that node.
1817 if (m_capturingMouseEventsNode)
1818 result = m_capturingMouseEventsNode.get();
1820 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1821 if (result && result->isTextNode())
1822 result = NodeRenderingTraversal::parent(result);
1824 m_nodeUnderMouse = result;
1826 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1827 if (fireMouseOverOut) {
1828 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1829 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1830 Page* page = m_frame->page();
1832 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1833 // The mouse has moved between frames.
1834 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1835 if (FrameView* frameView = frame->view())
1836 frameView->mouseExitedContentArea();
1838 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1839 // The mouse has moved between layers.
1840 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
1841 scrollableAreaForLastNode->mouseExitedContentArea();
1844 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1845 // The mouse has moved between frames.
1846 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
1847 if (FrameView* frameView = frame->view())
1848 frameView->mouseEnteredContentArea();
1850 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1851 // The mouse has moved between layers.
1852 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
1853 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1856 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1857 m_lastNodeUnderMouse = nullptr;
1858 m_lastScrollbarUnderMouse = nullptr;
1861 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1862 // send mouseout event to the old node
1863 if (m_lastNodeUnderMouse)
1864 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
1865 // send mouseover event to the new node
1866 if (m_nodeUnderMouse)
1867 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
1869 m_lastNodeUnderMouse = m_nodeUnderMouse;
1873 // The return value means 'continue default handling.'
1874 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1876 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1877 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1880 // The return value means 'swallow event' (was handled), as for other handle* functions.
1881 bool EventHandler::handleMouseFocus(const MouseEventWithHitTestResults& targetedEvent)
1883 const PlatformMouseEvent& mouseEvent = targetedEvent.event();
1885 // If clicking on a frame scrollbar, do not mess up with content focus.
1886 if (FrameView* view = m_frame->view()) {
1887 if (view->scrollbarAtWindowPoint(mouseEvent.position()))
1891 // The layout needs to be up to date to determine if an element is focusable.
1892 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1894 Element* element = nullptr;
1895 if (m_nodeUnderMouse)
1896 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
1897 for (; element; element = element->parentOrShadowHostElement()) {
1898 if (element->isFocusable() && element->focused())
1900 if (element->isMouseFocusable())
1903 ASSERT(!element || element->isMouseFocusable());
1905 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
1906 // a node on mouse down if it's selected and inside a focused node. It will
1907 // be focused if the user does a mouseup over it, however, because the
1908 // mouseup will set a selection inside it, which will call
1909 // FrameSelection::setFocusedNodeIfNeeded.
1911 && m_frame->selection().isRange()
1912 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
1913 && element->isDescendantOf(m_frame->document()->focusedElement()))
1916 // Only change the focus when clicking scrollbars if it can transfered to a
1917 // mouse focusable node.
1918 if (!element && targetedEvent.hitTestResult().scrollbar())
1921 if (Page* page = m_frame->page()) {
1922 // If focus shift is blocked, we eat the event. Note we should never
1923 // clear swallowEvent if the page already set it (e.g., by canceling
1924 // default behavior).
1926 if (!page->focusController().setFocusedElement(element, m_frame, FocusTypeMouse))
1929 // We call setFocusedElement even with !element in order to blur
1930 // current focus element when a link is clicked; this is expected by
1931 // some sites that rely on onChange handlers running from form
1932 // fields before the button click is processed.
1933 if (!page->focusController().setFocusedElement(0, m_frame))
1941 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
1943 #define RETURN_WHEEL_EVENT_HANDLED() \
1945 setFrameWasScrolledByUser(); \
1949 Document* doc = m_frame->document();
1951 if (!doc->renderView())
1954 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1956 FrameView* view = m_frame->view();
1960 LayoutPoint vPoint = view->windowToContents(event.position());
1962 HitTestRequest request(HitTestRequest::ReadOnly);
1963 HitTestResult result(vPoint);
1964 doc->renderView()->hitTest(request, result);
1966 Node* node = result.innerNode();
1967 // Wheel events should not dispatch to text nodes.
1968 if (node && node->isTextNode())
1969 node = NodeRenderingTraversal::parent(node);
1972 if (event.useLatchedEventNode()) {
1973 if (!m_latchedWheelEventNode) {
1974 m_latchedWheelEventNode = node;
1975 m_widgetIsLatched = result.isOverWidget();
1977 node = m_latchedWheelEventNode.get();
1979 isOverWidget = m_widgetIsLatched;
1981 if (m_latchedWheelEventNode)
1982 m_latchedWheelEventNode = nullptr;
1983 if (m_previousWheelScrolledNode)
1984 m_previousWheelScrolledNode = nullptr;
1986 isOverWidget = result.isOverWidget();
1990 // Figure out which view to send the event to.
1991 RenderObject* target = node->renderer();
1993 if (isOverWidget && target && target->isRenderPart()) {
1994 Widget* widget = toRenderPart(target)->widget();
1995 if (widget && passWheelEventToWidget(event, widget))
1996 RETURN_WHEEL_EVENT_HANDLED();
1999 if (node && !node->dispatchWheelEvent(event))
2000 RETURN_WHEEL_EVENT_HANDLED();
2003 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2004 view = m_frame->view();
2005 if (!view || !view->wheelEvent(event))
2008 RETURN_WHEEL_EVENT_HANDLED();
2010 #undef RETURN_WHEEL_EVENT_HANDLED
2013 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2015 if (!startNode || !wheelEvent)
2018 // Ctrl + scrollwheel is reserved for triggering zoom in/out actions in Chromium.
2019 if (wheelEvent->ctrlKey())
2022 Node* stopNode = m_previousWheelScrolledNode.get();
2023 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2025 // Break up into two scrolls if we need to. Diagonal movement on
2026 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2027 if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation())))
2028 wheelEvent->setDefaultHandled();
2030 if (scroll(ScrollDown, granularity, startNode, &stopNode, wheelEvent->deltaY(), roundedIntPoint(wheelEvent->absoluteLocation())))
2031 wheelEvent->setDefaultHandled();
2033 if (!m_latchedWheelEventNode)
2034 m_previousWheelScrolledNode = stopNode;
2037 bool EventHandler::handleGestureShowPress()
2039 m_lastShowPressTimestamp = WTF::currentTime();
2041 FrameView* view = m_frame->view();
2044 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2045 scrollAnimator->cancelAnimations();
2046 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2049 for (const ScrollableArea* scrollableArea : *areas) {
2050 ScrollAnimator* animator = scrollableArea->existingScrollAnimator();
2052 animator->cancelAnimations();
2057 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2059 // Propagation to inner frames is handled below this function.
2060 ASSERT(m_frame == m_frame->localFrameRoot());
2062 // Scrolling-related gesture events invoke EventHandler recursively for each frame down
2063 // the chain, doing a single-frame hit-test per frame. This matches handleWheelEvent.
2064 // FIXME: Add a test that traverses this path, e.g. for devtools overlay.
2065 if (gestureEvent.isScrollEvent())
2066 return handleGestureScrollEvent(gestureEvent);
2068 // Hit test across all frames and do touch adjustment as necessary for the event type.
2069 GestureEventWithHitTestResults targetedEvent = targetGestureEvent(gestureEvent);
2071 return handleGestureEvent(targetedEvent);
2074 bool EventHandler::handleGestureEvent(const GestureEventWithHitTestResults& targetedEvent)
2076 TRACE_EVENT0("input", "EventHandler::handleGestureEvent");
2078 // Propagation to inner frames is handled below this function.
2079 ASSERT(m_frame == m_frame->localFrameRoot());
2081 // Non-scrolling related gesture events do a single cross-frame hit-test and jump
2082 // directly to the inner most frame. This matches handleMousePressEvent etc.
2083 ASSERT(!targetedEvent.event().isScrollEvent());
2085 // Route to the correct frame.
2086 if (LocalFrame* innerFrame = targetedEvent.hitTestResult().innerNodeFrame())
2087 return innerFrame->eventHandler().handleGestureEventInFrame(targetedEvent);
2089 // No hit test result, handle in root instance. Perhaps we should just return false instead?
2090 return handleGestureEventInFrame(targetedEvent);
2093 bool EventHandler::handleGestureEventInFrame(const GestureEventWithHitTestResults& targetedEvent)
2095 ASSERT(!targetedEvent.event().isScrollEvent());
2097 RefPtrWillBeRawPtr<Node> eventTarget = targetedEvent.hitTestResult().innerNode();
2098 RefPtrWillBeRawPtr<Scrollbar> scrollbar = targetedEvent.hitTestResult().scrollbar();
2099 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2102 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2103 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed)
2104 m_scrollbarHandlingScrollGesture = scrollbar;
2109 if (eventTarget && eventTarget->dispatchGestureEvent(gestureEvent))
2112 switch (gestureEvent.type()) {
2113 case PlatformEvent::GestureTap:
2114 return handleGestureTap(targetedEvent);
2115 case PlatformEvent::GestureShowPress:
2116 return handleGestureShowPress();
2117 case PlatformEvent::GestureLongPress:
2118 return handleGestureLongPress(targetedEvent);
2119 case PlatformEvent::GestureLongTap:
2120 return handleGestureLongTap(targetedEvent);
2121 case PlatformEvent::GestureTwoFingerTap:
2122 return sendContextMenuEventForGesture(targetedEvent);
2123 case PlatformEvent::GestureTapDown:
2124 case PlatformEvent::GesturePinchBegin:
2125 case PlatformEvent::GesturePinchEnd:
2126 case PlatformEvent::GesturePinchUpdate:
2127 case PlatformEvent::GestureTapDownCancel:
2128 case PlatformEvent::GestureTapUnconfirmed:
2131 ASSERT_NOT_REACHED();
2137 bool EventHandler::handleGestureScrollEvent(const PlatformGestureEvent& gestureEvent)
2139 TRACE_EVENT0("input", "EventHandler::handleGestureScrollEvent");
2141 RefPtrWillBeRawPtr<Node> eventTarget = nullptr;
2142 RefPtrWillBeRawPtr<Scrollbar> scrollbar = nullptr;
2143 if (gestureEvent.type() != PlatformEvent::GestureScrollBegin) {
2144 scrollbar = m_scrollbarHandlingScrollGesture.get();
2145 eventTarget = m_scrollGestureHandlingNode.get();
2149 Document* document = m_frame->document();
2150 if (!document->renderView())
2153 FrameView* view = m_frame->view();
2154 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2155 HitTestRequest request(HitTestRequest::ReadOnly);
2156 HitTestResult result(viewPoint);
2157 document->renderView()->hitTest(request, result);
2159 eventTarget = result.innerNode();
2161 m_lastGestureScrollOverWidget = result.isOverWidget();
2162 m_scrollGestureHandlingNode = eventTarget;
2163 m_previousGestureScrolledNode = nullptr;
2166 scrollbar = result.scrollbar();
2170 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2171 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2172 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2173 || !eventSwallowed) {
2174 m_scrollbarHandlingScrollGesture = nullptr;
2181 bool eventSwallowed = handleScrollGestureOnResizer(eventTarget.get(), gestureEvent);
2182 if (!eventSwallowed)
2183 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2188 switch (gestureEvent.type()) {
2189 case PlatformEvent::GestureScrollBegin:
2190 return handleGestureScrollBegin(gestureEvent);
2191 case PlatformEvent::GestureScrollUpdate:
2192 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2193 return handleGestureScrollUpdate(gestureEvent);
2194 case PlatformEvent::GestureScrollEnd:
2195 return handleGestureScrollEnd(gestureEvent);
2196 case PlatformEvent::GestureFlingStart:
2197 case PlatformEvent::GesturePinchBegin:
2198 case PlatformEvent::GesturePinchEnd:
2199 case PlatformEvent::GesturePinchUpdate:
2202 ASSERT_NOT_REACHED();
2207 bool EventHandler::handleGestureTap(const GestureEventWithHitTestResults& targetedEvent)
2209 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2210 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2211 HitTestRequest::HitTestRequestType hitType = getHitTypeForGestureType(gestureEvent.type());
2213 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2215 unsigned modifierFlags = 0;
2216 if (gestureEvent.altKey())
2217 modifierFlags |= PlatformEvent::AltKey;
2218 if (gestureEvent.ctrlKey())
2219 modifierFlags |= PlatformEvent::CtrlKey;
2220 if (gestureEvent.metaKey())
2221 modifierFlags |= PlatformEvent::MetaKey;
2222 if (gestureEvent.shiftKey())
2223 modifierFlags |= PlatformEvent::ShiftKey;
2224 PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2226 HitTestResult currentHitTest = targetedEvent.hitTestResult();
2228 // We use the adjusted position so the application isn't surprised to see a event with
2229 // co-ordinates outside the target's bounds.
2230 IntPoint adjustedPoint = m_frame->view()->windowToContents(gestureEvent.position());
2232 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(),
2233 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2234 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2235 dispatchMouseEvent(EventTypeNames::mousemove, currentHitTest.innerNode(), 0, fakeMouseMove, true);
2237 // Do a new hit-test in case the mousemove event changed the DOM.
2238 // Note that if the original hit test wasn't over an element (eg. was over a scrollbar) we
2239 // don't want to re-hit-test because it may be in the wrong frame (and there's no way the page
2240 // could have seen the event anyway).
2241 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
2242 if (currentHitTest.innerNode())
2243 currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, hitType);
2244 m_clickNode = currentHitTest.innerNode();
2245 if (m_clickNode && m_clickNode->isTextNode())
2246 m_clickNode = NodeRenderingTraversal::parent(m_clickNode.get());
2248 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(),
2249 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2250 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2251 bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true);
2252 if (!swallowMouseDownEvent)
2253 swallowMouseDownEvent = handleMouseFocus(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest));
2254 if (!swallowMouseDownEvent)
2255 swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest));
2257 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
2258 if (currentHitTest.innerNode())
2259 currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, hitType);
2260 PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(),
2261 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2262 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2263 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseUp, false);
2265 bool swallowClickEvent = false;
2267 if (currentHitTest.innerNode()) {
2268 // Updates distribution because a mouseup (or mousedown) event listener can make the
2269 // tree dirty at dispatchMouseEvent() invocation above.
2270 // Unless distribution is updated, commonAncestor would hit ASSERT.
2271 // Both m_clickNode and currentHitTest.innerNode()) don't need to be updated
2272 // because commonAncestor() will exit early if their documents are different.
2273 m_clickNode->document().updateDistributionForNodeIfNeeded(m_clickNode.get());
2274 Node* clickTargetNode = currentHitTest.innerNode()->commonAncestor(*m_clickNode, parentForClickEvent);
2275 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, gestureEvent.tapCount(), fakeMouseUp, true);
2277 m_clickNode = nullptr;
2280 if (!swallowMouseUpEvent)
2281 swallowMouseUpEvent = handleMouseReleaseEvent(MouseEventWithHitTestResults(fakeMouseUp, currentHitTest));
2283 return swallowMouseDownEvent | swallowMouseUpEvent | swallowClickEvent;
2286 bool EventHandler::handleGestureLongPress(const GestureEventWithHitTestResults& targetedEvent)
2288 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2289 IntPoint adjustedPoint = gestureEvent.position();
2291 // FIXME: Ideally we should try to remove the extra mouse-specific hit-tests here (re-using the
2292 // supplied HitTestResult), but that will require some overhaul of the touch drag-and-drop code
2293 // and LongPress is such a special scenario that it's unlikely to matter much in practice.
2295 m_longTapShouldInvokeContextMenu = false;
2296 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2297 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2298 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), PlatformMouseEvent::FromTouch, WTF::currentTime());
2299 m_mouseDown = mouseDownEvent;
2301 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2302 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), PlatformMouseEvent::FromTouch, WTF::currentTime());
2303 HitTestRequest request(HitTestRequest::ReadOnly);
2304 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2305 m_didStartDrag = false;
2306 m_mouseDownMayStartDrag = true;
2307 dragState().m_dragSrc = nullptr;
2308 m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2309 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2310 handleDrag(mev, DontCheckDragHysteresis);
2311 if (m_didStartDrag) {
2312 m_longTapShouldInvokeContextMenu = true;
2317 bool shouldLongPressSelectWord = true;
2319 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2321 if (shouldLongPressSelectWord) {
2322 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2323 HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2324 Node* innerNode = result.innerNode();
2325 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode()
2327 || innerNode->canStartSelection()
2330 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2331 if (m_frame->selection().isRange()) {
2332 focusDocumentView();
2337 return sendContextMenuEventForGesture(targetedEvent);
2340 bool EventHandler::handleGestureLongTap(const GestureEventWithHitTestResults& targetedEvent)
2343 if (m_longTapShouldInvokeContextMenu) {
2344 m_longTapShouldInvokeContextMenu = false;
2345 return sendContextMenuEventForGesture(targetedEvent);
2351 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2352 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2353 RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : nullptr;
2354 IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2355 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2356 m_resizeScrollableArea = layer->scrollableArea();
2357 m_resizeScrollableArea->setInResizeMode(true);
2358 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2361 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2362 gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2363 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2364 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2367 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2368 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2369 m_resizeScrollableArea->setInResizeMode(false);
2370 m_resizeScrollableArea = nullptr;
2378 bool EventHandler::passScrollGestureEventToWidget(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2380 ASSERT(gestureEvent.isScrollEvent());
2382 if (!m_lastGestureScrollOverWidget)
2385 if (!renderer || !renderer->isRenderPart())
2388 Widget* widget = toRenderPart(renderer)->widget();
2390 if (!widget || !widget->isFrameView())
2393 return toFrameView(widget)->frame().eventHandler().handleGestureScrollEvent(gestureEvent);
2396 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2397 RefPtrWillBeRawPtr<Node> node = m_scrollGestureHandlingNode;
2398 clearGestureScrollNodes();
2401 passScrollGestureEventToWidget(gestureEvent, node->renderer());
2406 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2408 Document* document = m_frame->document();
2409 if (!document->renderView())
2412 FrameView* view = m_frame->view();
2416 // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2417 // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2418 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2419 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2421 if (!m_scrollGestureHandlingNode)
2424 passScrollGestureEventToWidget(gestureEvent, m_scrollGestureHandlingNode->renderer());
2429 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2431 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2435 Node* node = m_scrollGestureHandlingNode.get();
2437 return sendScrollEventToView(gestureEvent, delta);
2439 // Ignore this event if the targeted node does not have a valid renderer.
2440 RenderObject* renderer = node->renderer();
2444 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2446 Node* stopNode = nullptr;
2447 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2449 // Try to send the event to the correct view.
2450 if (passScrollGestureEventToWidget(gestureEvent, renderer)) {
2451 if(scrollShouldNotPropagate)
2452 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2457 if (scrollShouldNotPropagate)
2458 stopNode = m_previousGestureScrolledNode.get();
2460 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2461 ScrollGranularity granularity = ScrollByPixel;
2462 bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width());
2463 bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height());
2465 if (scrollShouldNotPropagate)
2466 m_previousGestureScrolledNode = stopNode;
2468 if (horizontalScroll || verticalScroll) {
2469 setFrameWasScrolledByUser();
2473 // Otherwise try to scroll the view.
2474 return sendScrollEventToView(gestureEvent, delta);
2477 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& delta)
2479 FrameView* view = m_frame->view();
2483 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2484 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2485 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2486 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2487 delta.width(), delta.height(),
2488 delta.width() / tickDivisor, delta.height() / tickDivisor,
2489 ScrollByPixelWheelEvent,
2490 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2491 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2493 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2495 setFrameWasScrolledByUser();
2497 return scrolledFrame;
2500 void EventHandler::clearGestureScrollNodes()
2502 m_scrollGestureHandlingNode = nullptr;
2503 m_previousGestureScrolledNode = nullptr;
2506 bool EventHandler::isScrollbarHandlingGestures() const
2508 return m_scrollbarHandlingScrollGesture.get();
2511 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2513 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2515 return !event.area().isEmpty();
2518 bool EventHandler::bestClickableNodeForHitTestResult(const HitTestResult& result, IntPoint& targetPoint, Node*& targetNode)
2520 // FIXME: Unify this with the other best* functions which are very similar.
2522 TRACE_EVENT0("input", "EventHandler::bestClickableNodeForHitTestResult");
2523 ASSERT(result.isRectBasedTest());
2525 // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2526 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2527 // scrollbars being untouchable.
2528 if (result.scrollbar()) {
2533 IntPoint touchCenter = m_frame->view()->contentsToWindow(result.roundedPointInMainFrame());
2534 IntRect touchRect = m_frame->view()->contentsToWindow(result.hitTestLocation().boundingBox());
2536 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2537 copyToVector(result.rectBasedTestResult(), nodes);
2539 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2540 return findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node>> (nodes));
2543 bool EventHandler::bestContextMenuNodeForHitTestResult(const HitTestResult& result, IntPoint& targetPoint, Node*& targetNode)
2545 ASSERT(result.isRectBasedTest());
2546 IntPoint touchCenter = m_frame->view()->contentsToWindow(result.roundedPointInMainFrame());
2547 IntRect touchRect = m_frame->view()->contentsToWindow(result.hitTestLocation().boundingBox());
2548 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2549 copyToVector(result.rectBasedTestResult(), nodes);
2551 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2552 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node>>(nodes));
2555 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2557 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2558 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2560 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2561 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2562 copyToVector(result.rectBasedTestResult(), nodes);
2564 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2565 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node>>(nodes));
2568 GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGestureEvent& gestureEvent, bool readOnly)
2570 TRACE_EVENT0("input", "EventHandler::targetGestureEvent");
2572 ASSERT(m_frame == m_frame->localFrameRoot());
2573 // Scrolling events get hit tested per frame (like wheel events do).
2574 ASSERT(!gestureEvent.isScrollEvent());
2576 HitTestRequest::HitTestRequestType hitType = getHitTypeForGestureType(gestureEvent.type());
2577 double activeInterval = 0;
2578 bool shouldKeepActiveForMinInterval = false;
2580 hitType |= HitTestRequest::ReadOnly;
2581 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2582 // If the Tap is received very shortly after ShowPress, we want to
2583 // delay clearing of the active state so that it's visible to the user
2584 // for at least a couple of frames.
2585 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2586 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2587 if (shouldKeepActiveForMinInterval)
2588 hitType |= HitTestRequest::ReadOnly;
2591 // Perform the rect-based hit-test (or point-based if adjustment is disabled). Note that
2592 // we don't yet apply hover/active state here because we need to resolve touch adjustment
2593 // first so that we apply hover/active it to the final adjusted node.
2594 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2596 if (shouldApplyTouchAdjustment(gestureEvent)) {
2597 padding = gestureEvent.area();
2598 padding.scale(1.f / 2);
2600 HitTestResult hitTestResult = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::ReadOnly, padding);
2602 // Adjust the location of the gesture to the most likely nearby node, as appropriate for the
2604 PlatformGestureEvent adjustedEvent = gestureEvent;
2605 applyTouchAdjustment(&adjustedEvent, &hitTestResult);
2607 // Do a new hit-test at the (adjusted) gesture co-ordinates. This is necessary because
2608 // rect-based hit testing and touch adjustment sometimes return a different node than
2609 // what a point-based hit test would return for the same point.
2610 // FIXME: Fix touch adjustment to avoid the need for a redundant hit test. http://crbug.com/398914
2611 if (shouldApplyTouchAdjustment(gestureEvent)) {
2612 LocalFrame* hitFrame = hitTestResult.innerNodeFrame();
2615 hitTestResult = hitTestResultInFrame(hitFrame, hitFrame->view()->windowToContents(adjustedEvent.position()), hitType | HitTestRequest::ReadOnly);
2618 // If we did a rect-based hit test it must be resolved to the best single node by now to
2619 // ensure consumers don't accidentally use one of the other candidates.
2620 ASSERT(!hitTestResult.isRectBasedTest());
2622 // Now apply hover/active state to the final target.
2623 // FIXME: This is supposed to send mouseenter/mouseleave events, but doesn't because we
2624 // aren't passing a PlatformMouseEvent.
2625 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
2626 if (!request.readOnly())
2627 m_frame->document()->updateHoverActiveState(request, hitTestResult.innerElement());
2629 if (shouldKeepActiveForMinInterval) {
2630 m_lastDeferredTapElement = hitTestResult.innerElement();
2631 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval, FROM_HERE);
2634 return GestureEventWithHitTestResults(adjustedEvent, hitTestResult);
2637 HitTestRequest::HitTestRequestType EventHandler::getHitTypeForGestureType(PlatformEvent::Type type)
2639 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2641 case PlatformEvent::GestureShowPress:
2642 case PlatformEvent::GestureTapUnconfirmed:
2643 return hitType | HitTestRequest::Active;
2644 case PlatformEvent::GestureTapDownCancel:
2645 // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2646 if (!m_frame->document()->activeHoverElement())
2647 hitType |= HitTestRequest::ReadOnly;
2648 return hitType | HitTestRequest::Release;
2649 case PlatformEvent::GestureTap:
2650 return hitType | HitTestRequest::Release;
2651 case PlatformEvent::GestureTapDown:
2652 case PlatformEvent::GestureLongPress:
2653 case PlatformEvent::GestureLongTap:
2654 case PlatformEvent::GestureTwoFingerTap:
2655 // FIXME: Shouldn't LongTap and TwoFingerTap clear the Active state?
2656 return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
2658 ASSERT_NOT_REACHED();
2659 return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
2663 void EventHandler::applyTouchAdjustment(PlatformGestureEvent* gestureEvent, HitTestResult* hitTestResult)
2665 if (!shouldApplyTouchAdjustment(*gestureEvent))
2668 Node* adjustedNode = nullptr;
2669 IntPoint adjustedPoint = gestureEvent->position();
2670 IntSize radius = gestureEvent->area();
2671 radius.scale(1.f / 2);
2672 bool adjusted = false;
2673 switch (gestureEvent->type()) {
2674 case PlatformEvent::GestureTap:
2675 case PlatformEvent::GestureTapUnconfirmed:
2676 case PlatformEvent::GestureTapDown:
2677 case PlatformEvent::GestureShowPress:
2678 adjusted = bestClickableNodeForHitTestResult(*hitTestResult, adjustedPoint, adjustedNode);
2680 case PlatformEvent::GestureLongPress:
2681 case PlatformEvent::GestureLongTap:
2682 case PlatformEvent::GestureTwoFingerTap:
2683 adjusted = bestContextMenuNodeForHitTestResult(*hitTestResult, adjustedPoint, adjustedNode);
2686 ASSERT_NOT_REACHED();
2689 // Update the hit-test result to be a point-based result instead of a rect-based result.
2690 // FIXME: We should do this even when no candidate matches the node filter. crbug.com/398914
2692 hitTestResult->resolveRectBasedTest(adjustedNode, m_frame->view()->windowToContents(adjustedPoint));
2693 gestureEvent->applyTouchAdjustment(adjustedPoint);
2697 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2699 Document* doc = m_frame->document();
2700 FrameView* v = m_frame->view();
2704 // Clear mouse press state to avoid initiating a drag while context menu is up.
2705 m_mousePressed = false;
2706 LayoutPoint viewportPos = v->windowToContents(event.position());
2707 HitTestRequest request(HitTestRequest::Active);
2708 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2710 if (!m_frame->selection().contains(viewportPos)
2712 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2713 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2714 // available for text selections. But only if we're above text.
2715 && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev.innerNode()->isTextNode()))) {
2716 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2718 if (mev.hitTestResult().isMisspelled())
2719 selectClosestMisspellingFromMouseEvent(mev);
2720 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2721 selectClosestWordOrLinkFromMouseEvent(mev);
2724 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.innerNode(), 0, event, false);
2727 bool EventHandler::sendContextMenuEventForKey()
2729 FrameView* view = m_frame->view();
2733 Document* doc = m_frame->document();
2737 // Clear mouse press state to avoid initiating a drag while context menu is up.
2738 m_mousePressed = false;
2740 static const int kContextMenuMargin = 1;
2743 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2745 int rightAligned = 0;
2749 Element* focusedElement = doc->focusedElement();
2750 FrameSelection& selection = m_frame->selection();
2751 Position start = selection.selection().start();
2752 bool shouldTranslateToRootView = true;
2754 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2755 RefPtrWillBeRawPtr<Range> selectionRange = selection.toNormalizedRange();
2756 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2758 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2759 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2760 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2761 location = IntPoint(x, y);
2762 } else if (focusedElement) {
2763 IntRect clippedRect = focusedElement->boundsInRootViewSpace();
2764 location = IntPoint(clippedRect.center());
2766 location = IntPoint(
2767 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2768 kContextMenuMargin);
2769 shouldTranslateToRootView = false;
2772 m_frame->view()->setCursor(pointerCursor());
2774 IntPoint position = shouldTranslateToRootView ? view->contentsToRootView(location) : location;
2775 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2777 Node* targetNode = doc->focusedElement();
2781 // Use the focused node as the target for hover and active.
2782 HitTestResult result(position);
2783 result.setInnerNode(targetNode);
2784 doc->updateHoverActiveState(HitTestRequest::Active, result.innerElement());
2786 // The contextmenu event is a mouse event even when invoked using the keyboard.
2787 // This is required for web compatibility.
2790 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2792 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2795 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, PlatformMouseEvent::RealOrIndistinguishable, WTF::currentTime());
2797 handleMousePressEvent(mouseEvent);
2798 return sendContextMenuEvent(mouseEvent);
2801 bool EventHandler::sendContextMenuEventForGesture(const GestureEventWithHitTestResults& targetedEvent)
2804 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2806 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2809 PlatformMouseEvent mouseEvent(targetedEvent.event().position(), targetedEvent.event().globalPosition(), RightButton, eventType, 1, false, false, false, false, PlatformMouseEvent::FromTouch, WTF::currentTime());
2810 // To simulate right-click behavior, we send a right mouse down and then
2811 // context menu event.
2812 // FIXME: Send HitTestResults to avoid redundant hit tests.
2813 handleMousePressEvent(mouseEvent);
2814 return sendContextMenuEvent(mouseEvent);
2815 // We do not need to send a corresponding mouse release because in case of
2816 // right-click, the context menu takes capture and consumes all events.
2819 void EventHandler::scheduleHoverStateUpdate()
2821 if (!m_hoverTimer.isActive())
2822 m_hoverTimer.startOneShot(0, FROM_HERE);
2825 void EventHandler::scheduleCursorUpdate()
2827 if (!m_cursorUpdateTimer.isActive())
2828 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
2831 void EventHandler::dispatchFakeMouseMoveEventSoon()
2836 if (m_mousePositionIsUnknown)
2839 Settings* settings = m_frame->settings();
2840 if (settings && !settings->deviceSupportsMouse())
2843 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2844 // reschedule the timer and use a longer time. This will cause the content
2845 // to receive these moves only after the user is done scrolling, reducing
2846 // pauses during the scroll.
2847 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2848 if (m_fakeMouseMoveEventTimer.isActive())
2849 m_fakeMouseMoveEventTimer.stop();
2850 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_HERE);
2852 if (!m_fakeMouseMoveEventTimer.isActive())
2853 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, FROM_HERE);
2857 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2859 FrameView* view = m_frame->view();
2863 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2866 dispatchFakeMouseMoveEventSoon();
2869 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2871 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2872 ASSERT(!m_mousePressed);
2874 Settings* settings = m_frame->settings();
2875 if (settings && !settings->deviceSupportsMouse())
2878 FrameView* view = m_frame->view();
2882 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2885 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2886 if (!isCursorVisible())
2893 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2894 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, PlatformMouseEvent::RealOrIndistinguishable, currentTime());
2895 handleMouseMoveEvent(fakeMouseMoveEvent);
2898 void EventHandler::cancelFakeMouseMoveEvent()
2900 m_fakeMouseMoveEventTimer.stop();
2903 bool EventHandler::isCursorVisible() const
2905 return m_frame->page()->isCursorVisible();
2908 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2910 m_frameSetBeingResized = frameSet;
2913 void EventHandler::resizeScrollableAreaDestroyed()
2915 ASSERT(m_resizeScrollableArea);
2916 m_resizeScrollableArea = nullptr;
2919 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2921 m_hoverTimer.stop();
2924 ASSERT(m_frame->document());
2926 if (RenderView* renderer = m_frame->contentRenderer()) {
2927 if (FrameView* view = m_frame->view()) {
2928 HitTestRequest request(HitTestRequest::Move);
2929 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2930 renderer->hitTest(request, result);
2931 m_frame->document()->updateHoverActiveState(request, result.innerElement());
2936 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
2938 m_activeIntervalTimer.stop();
2941 && m_frame->document()
2942 && m_lastDeferredTapElement) {
2943 // FIXME: Enable condition when http://crbug.com/226842 lands
2944 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2945 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
2946 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
2948 m_lastDeferredTapElement = nullptr;
2951 void EventHandler::notifyElementActivated()
2953 // Since another element has been set to active, stop current timer and clear reference.
2954 if (m_activeIntervalTimer.isActive())
2955 m_activeIntervalTimer.stop();
2956 m_lastDeferredTapElement = nullptr;
2959 void EventHandler::notifySelectionChanged()
2961 m_selectionInitiationState = ExtendedSelection;
2964 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2966 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2967 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2968 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2969 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2970 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2971 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2973 String key = evt.unmodifiedText();
2974 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2977 elem->accessKeyAction(false);
2981 bool EventHandler::isKeyEventAllowedInFullScreen(Fullscreen* fullscreen, const PlatformKeyboardEvent& keyEvent) const
2983 if (fullscreen->webkitFullScreenKeyboardInputAllowed())
2986 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2987 if (keyEvent.text().length() != 1)
2989 UChar character = keyEvent.text()[0];
2990 return character == ' ';
2993 int keyCode = keyEvent.windowsVirtualKeyCode();
2994 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2995 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2996 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2997 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3000 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3002 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
3004 ASSERT(m_frame->document());
3005 if (Fullscreen* fullscreen = Fullscreen::fromIfExists(*m_frame->document())) {
3006 if (fullscreen->webkitCurrentFullScreenElement() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent)) {
3007 UseCounter::count(*m_frame->document(), UseCounter::KeyEventNotAllowedInFullScreen);
3012 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3013 capsLockStateMayHaveChanged();
3016 if (panScrollInProgress()) {
3017 // If a key is pressed while the panScroll is in progress then we want to stop
3018 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3021 // If we were in panscroll mode, we swallow the key event
3026 // Check for cases where we are too early for events -- possible unmatched key up
3027 // from pressing return in the location bar.
3028 RefPtrWillBeRawPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
3032 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3034 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3035 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3036 // with access keys. Then we dispatch keydown, but suppress its default handling.
3037 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3038 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3039 bool matchedAnAccessKey = false;
3040 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3041 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3043 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3044 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3045 return !node->dispatchKeyEvent(initialKeyEvent);
3047 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3048 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3049 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
3050 RefPtrWillBeRawPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
3051 if (matchedAnAccessKey)
3052 keydown->setDefaultPrevented(true);
3053 keydown->setTarget(node);
3055 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3056 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3057 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3058 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3059 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3062 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3063 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3064 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3065 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3067 return keydownResult;
3069 // Focus may have changed during keydown handling, so refetch node.
3070 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3071 node = eventTargetNodeForDocument(m_frame->document());
3075 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3076 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
3077 if (keyPressEvent.text().isEmpty())
3078 return keydownResult;
3079 RefPtrWillBeRawPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
3080 keypress->setTarget(node);
3082 keypress->setDefaultPrevented(true);
3083 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
3085 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3088 static FocusType focusDirectionForKey(const AtomicString& keyIdentifier)
3090 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3091 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3092 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3093 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3095 FocusType retVal = FocusTypeNone;
3097 if (keyIdentifier == Down)
3098 retVal = FocusTypeDown;
3099 else if (keyIdentifier == Up)
3100 retVal = FocusTypeUp;
3101 else if (keyIdentifier == Left)
3102 retVal = FocusTypeLeft;
3103 else if (keyIdentifier == Right)
3104 retVal = FocusTypeRight;
3109 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3111 if (event->type() == EventTypeNames::keydown) {
3112 // Clear caret blinking suspended state to make sure that caret blinks
3113 // when we type again after long pressing on an empty input field.
3114 if (m_frame && m_frame->selection().isCaretBlinkingSuspended())
3115 m_frame->selection().setCaretBlinkingSuspended(false);
3117 m_frame->editor().handleKeyboardEvent(event);
3118 if (event->defaultHandled())
3120 if (event->keyIdentifier() == "U+0009")
3121 defaultTabEventHandler(event);
3122 else if (event->keyIdentifier() == "U+0008")
3123 defaultBackspaceEventHandler(event);
3124 else if (event->keyIdentifier() == "U+001B")
3125 defaultEscapeEventHandler(event);
3127 FocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
3128 if (type != FocusTypeNone)
3129 defaultArrowEventHandler(type, event);
3132 if (event->type() == EventTypeNames::keypress) {
3133 m_frame->editor().handleKeyboardEvent(event);
3134 if (event->defaultHandled())
3136 if (event->charCode() == ' ')
3137 defaultSpaceEventHandler(event);
3141 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
3143 return dragHysteresisExceeded(flooredIntPoint(floatDragViewportLocation));
3146 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
3148 FrameView* view = m_frame->view();
3151 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
3152 IntSize delta = dragLocation - m_mouseDownPos;
3154 int threshold = GeneralDragHysteresis;
3155 switch (dragState().m_dragType) {
3156 case DragSourceActionSelection:
3157 threshold = TextDragHysteresis;
3159 case DragSourceActionImage:
3160 threshold = ImageDragHysteresis;
3162 case DragSourceActionLink:
3163 threshold = LinkDragHysteresis;
3165 case DragSourceActionDHTML:
3167 case DragSourceActionNone:
3168 ASSERT_NOT_REACHED();
3171 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3174 void EventHandler::clearDragDataTransfer()
3176 if (dragState().m_dragDataTransfer) {
3177 dragState().m_dragDataTransfer->clearDragImage();
3178 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferNumb);
3182 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3184 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3185 HitTestRequest request(HitTestRequest::Release);
3186 prepareMouseEvent(request, event);
3188 if (dragState().m_dragSrc) {
3189 dragState().m_dragDataTransfer->setDestinationOperation(operation);
3190 // for now we don't care if event handler cancels default behavior, since there is none
3191 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3193 clearDragDataTransfer();
3194 dragState().m_dragSrc = nullptr;
3195 // In case the drag was ended due to an escape key press we need to ensure
3196 // that consecutive mousemove events don't reinitiate the drag and drop.
3197 m_mouseDownMayStartDrag = false;
3200 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3202 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3203 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3204 dragState().m_dragSrc = rootEditableElement;
3207 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3208 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3210 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragDataTransfer.get());
3213 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3215 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3216 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3217 // events, causing page/FrameView to go away.
3219 ASSERT(m_frame->view());
3220 if (!m_frame->page())
3223 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3224 // If we allowed the other side of the bridge to handle a drag
3225 // last time, then m_mousePressed might still be set. So we
3226 // clear it now to make sure the next move after a drag
3227 // doesn't look like a drag.
3228 m_mousePressed = false;
3232 if (m_mouseDownMayStartDrag) {
3233 HitTestRequest request(HitTestRequest::ReadOnly);
3234 HitTestResult result(m_mouseDownPos);
3235 m_frame->contentRenderer()->hitTest(request, result);
3236 Node* node = result.innerNode();
3238 DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3239 ? DragController::DelayedSelectionDragResolution
3240 : DragController::ImmediateSelectionDragResolution;
3241 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3243 dragState().m_dragSrc = nullptr;
3246 if (!dragState().m_dragSrc)
3247 m_mouseDownMayStartDrag = false; // no element is draggable
3250 if (!m_mouseDownMayStartDrag)
3251 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3253 // We are starting a text/image/url drag, so the cursor should be an arrow
3254 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3255 m_frame->view()->setCursor(pointerCursor());
3257 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3260 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3263 if (!tryStartDrag(event)) {
3264 // Something failed to start the drag, clean up.
3265 clearDragDataTransfer();
3266 dragState().m_dragSrc = nullptr;
3269 m_mouseDownMayStartDrag = false;
3270 // Whether or not the drag actually started, no more default handling (like selection).
3274 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3276 // The DataTransfer would only be non-empty if we missed a dragEnd.
3277 // Clear it anyway, just to make sure it gets numbified.
3278 clearDragDataTransfer();
3280 dragState().m_dragDataTransfer = createDraggingDataTransfer();
3282 // Check to see if this a DOM based drag, if it is get the DOM specified drag
3284 if (dragState().m_dragType == DragSourceActionDHTML) {
3285 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3286 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), UseTransforms);
3287 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3288 dragState().m_dragDataTransfer->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3290 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3291 // the element in some way. In this case we just kill the drag.
3296 DragController& dragController = m_frame->page()->dragController();
3297 if (!dragController.populateDragDataTransfer(m_frame, dragState(), m_mouseDownPos))
3300 // If dispatching dragstart brings about another mouse down -- one way
3301 // this will happen is if a DevTools user breaks within a dragstart
3302 // handler and then clicks on the suspended page -- the drag state is
3303 // reset. Hence, need to check if this particular drag operation can
3304 // continue even if dispatchEvent() indicates no (direct) cancellation.
3305 // Do that by checking if m_dragSrc is still set.
3306 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3307 && !m_frame->selection().isInPasswordField() && dragState().m_dragSrc;
3309 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3310 // image can still be changed as we drag, but not the pasteboard data.
3311 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferImageWritable);
3313 if (m_mouseDownMayStartDrag) {
3314 // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3315 m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3316 // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3317 // whether or not the drag started, but perhaps it can simply use the return value from
3318 // handleDrag(), even though it doesn't mean exactly the same thing.
3321 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3322 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3328 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3330 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3331 // and avoid dispatching text input events from keydown default handlers.
3332 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3337 EventTarget* target;
3338 if (underlyingEvent)
3339 target = underlyingEvent->target();
3341 target = eventTargetNodeForDocument(m_frame->document());
3345 RefPtrWillBeRawPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3346 event->setUnderlyingEvent(underlyingEvent);
3348 target->dispatchEvent(event, IGNORE_EXCEPTION);
3349 return event->defaultHandled();
3352 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3354 if (m_frame->editor().handleTextEvent(event))
3355 event->setDefaultHandled();
3358 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3360 ASSERT(event->type() == EventTypeNames::keypress);
3362 if (event->ctrlKey() || event->metaKey() || event->altKey())
3365 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3366 if (scroll(direction, ScrollByPage)) {
3367 event->setDefaultHandled();
3371 FrameView* view = m_frame->view();
3375 if (view->scroll(direction, ScrollByPage))
3376 event->setDefaultHandled();
3379 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3381 ASSERT(event->type() == EventTypeNames::keydown);
3383 if (event->ctrlKey() || event->metaKey() || event->altKey())
3386 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3388 bool handledEvent = m_frame->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3390 event->setDefaultHandled();
3393 void EventHandler::defaultArrowEventHandler(FocusType focusType, KeyboardEvent* event)
3395 ASSERT(event->type() == EventTypeNames::keydown);
3397 if (event->ctrlKey() || event->metaKey() || event->shiftKey())
3400 Page* page = m_frame->page();
3404 if (!isSpatialNavigationEnabled(m_frame))
3407 // Arrows and other possible directional navigation keys can be used in design
3409 if (m_frame->document()->inDesignMode())
3412 if (page->focusController().advanceFocus(focusType))
3413 event->setDefaultHandled();
3416 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3418 ASSERT(event->type() == EventTypeNames::keydown);
3420 // We should only advance focus on tabs if no special modifier keys are held down.
3421 if (event->ctrlKey() || event->metaKey())
3424 Page* page = m_frame->page();
3427 if (!page->tabKeyCyclesThroughElements())
3430 FocusType focusType = event->shiftKey() ? FocusTypeBackward : FocusTypeForward;
3432 // Tabs can be used in design mode editing.
3433 if (m_frame->document()->inDesignMode())
3436 if (page->focusController().advanceFocus(focusType))
3437 event->setDefaultHandled();
3440 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3442 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3443 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3446 void EventHandler::capsLockStateMayHaveChanged()
3448 if (Element* element = m_frame->document()->focusedElement()) {
3449 if (RenderObject* r = element->renderer()) {
3450 if (r->isTextField())
3451 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3456 void EventHandler::setFrameWasScrolledByUser()
3458 if (FrameView* view = m_frame->view())
3459 view->setWasScrolledByUser(true);
3462 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev)
3464 Scrollbar* scrollbar = mev.scrollbar();
3465 updateLastScrollbarUnderMouse(scrollbar, true);
3467 if (!scrollbar || !scrollbar->enabled())
3469 setFrameWasScrolledByUser();
3470 scrollbar->mouseDown(mev.event());
3474 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3475 // last to scrollbar if setLast is true; else set last to 0.
3476 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3478 if (m_lastScrollbarUnderMouse != scrollbar) {
3479 // Send mouse exited to the old scrollbar.
3480 if (m_lastScrollbarUnderMouse)
3481 m_lastScrollbarUnderMouse->mouseExited();
3483 // Send mouse entered if we're setting a new scrollbar.
3484 if (scrollbar && setLast)
3485 scrollbar->mouseEntered();
3487 m_lastScrollbarUnderMouse = setLast ? scrollbar : nullptr;
3491 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3494 case PlatformTouchPoint::TouchReleased:
3495 return EventTypeNames::touchend;
3496 case PlatformTouchPoint::TouchCancelled:
3497 return EventTypeNames::touchcancel;
3498 case PlatformTouchPoint::TouchPressed:
3499 return EventTypeNames::touchstart;
3500 case PlatformTouchPoint::TouchMoved:
3501 return EventTypeNames::touchmove;
3502 case PlatformTouchPoint::TouchStationary:
3503 // TouchStationary state is not converted to touch events, so fall through to assert.
3505 ASSERT_NOT_REACHED();
3510 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3512 HitTestResult result(point);
3514 if (!frame || !frame->contentRenderer())
3516 if (frame->view()) {
3517 IntRect rect = frame->view()->visibleContentRect(IncludeScrollbars);
3518 if (!rect.contains(roundedIntPoint(point)))
3521 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3525 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3527 TRACE_EVENT0("blink", "EventHandler::handleTouchEvent");
3529 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3532 bool freshTouchEvents = true;
3533 bool allTouchReleased = true;
3534 for (i = 0; i < points.size(); ++i) {
3535 const PlatformTouchPoint& point = points[i];
3536 if (point.state() != PlatformTouchPoint::TouchPressed)
3537 freshTouchEvents = false;
3538 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3539 allTouchReleased = false;
3541 if (freshTouchEvents) {
3542 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3543 // have cleared the active document when we saw the last release. But we
3544 // have some tests that violate this, ClusterFuzz could trigger it, and
3545 // there may be cases where the browser doesn't reliably release all
3546 // touches. http://crbug.com/345372 tracks this.
3547 m_touchSequenceDocument.clear();
3548 m_touchSequenceUserGestureToken.clear();
3551 OwnPtr<UserGestureIndicator> gestureIndicator;
3553 if (m_touchSequenceUserGestureToken)
3554 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequenceUserGestureToken.release()));
3556 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
3558 m_touchSequenceUserGestureToken = gestureIndicator->currentToken();
3560 ASSERT(m_frame->view());
3561 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touchSequenceDocument->frame()->view())) {
3562 // If the active touch document has no frame or view, it's probably being destroyed
3563 // so we can't dispatch events.
3567 // First do hit tests for any new touch points.
3568 for (i = 0; i < points.size(); ++i) {
3569 const PlatformTouchPoint& point = points[i];
3571 // Touch events implicitly capture to the touched node, and don't change
3572 // active/hover states themselves (Gesture events do). So we only need
3573 // to hit-test on touchstart, and it can be read-only.
3574 if (point.state() == PlatformTouchPoint::TouchPressed) {
3575 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3576 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->windowToContents(point.pos()));
3577 HitTestResult result;
3578 if (!m_touchSequenceDocument) {
3579 result = hitTestResultAtPoint(pagePoint, hitType);
3580 } else if (m_touchSequenceDocument->frame()) {
3581 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocument->frame()->view()->windowToContents(point.pos()));
3582 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), framePoint, hitType);
3586 Node* node = result.innerNode();
3590 // Touch events should not go to text nodes
3591 if (node->isTextNode())
3592 node = NodeRenderingTraversal::parent(node);
3594 if (!m_touchSequenceDocument) {
3595 // Keep track of which document should receive all touch events
3596 // in the active sequence. This must be a single document to
3597 // ensure we don't leak Nodes between documents.
3598 m_touchSequenceDocument = &(result.innerNode()->document());
3599 ASSERT(m_touchSequenceDocument->frame()->view());
3602 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3603 // since we shouldn't get a touchstart for a touch that's already
3604 // down. However EventSender allows this to be violated and there's
3605 // some tests that take advantage of it. There may also be edge
3606 // cases in the browser where this happens.
3607 // See http://crbug.com/345372.
3608 m_targetForTouchID.set(point.id(), node);
3610 TouchAction effectiveTouchAction = computeEffectiveTouchAction(*node);
3611 if (effectiveTouchAction != TouchActionAuto)
3612 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3616 m_touchPressed = !allTouchReleased;
3618 // If there's no document receiving touch events, or no handlers on the
3619 // document set to receive the events, then we can skip all the rest of
3621 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !m_touchSequenceDocument->frameHost()->eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::TouchEvent) || !m_touchSequenceDocument->frame()) {
3622 if (allTouchReleased) {
3623 m_touchSequenceDocument.clear();
3624 m_touchSequenceUserGestureToken.clear();
3629 // Build up the lists to use for the 'touches', 'targetTouches' and
3630 // 'changedTouches' attributes in the JS event. See
3631 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3632 // lists fit together.
3634 // Holds the complete set of touches on the screen.
3635 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3637 // A different view on the 'touches' list above, filtered and grouped by
3638 // event target. Used for the 'targetTouches' list in the JS event.
3639 using TargetTouchesHeapMap = WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList>>;
3640 TargetTouchesHeapMap touchesByTarget;
3642 // Array of touches per state, used to assemble the 'changedTouches' list.
3643 using EventTargetSet = WillBeHeapHashSet<RefPtrWillBeMember<EventTarget>>;
3645 // The touches corresponding to the particular change state this struct
3646 // instance represents.
3647 RefPtrWillBeMember<TouchList> m_touches;
3648 // Set of targets involved in m_touches.
3649 EventTargetSet m_targets;
3650 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3652 for (i = 0; i < points.size(); ++i) {
3653 const PlatformTouchPoint& point = points[i];
3654 PlatformTouchPoint::State pointState = point.state();
3655 RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr;
3657 if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3658 // The target should be the original target for this touch, so get
3659 // it from the hashmap. As it's a release or cancel we also remove
3661 touchTarget = m_targetForTouchID.take(point.id());
3663 // No hittest is performed on move or stationary, since the target
3664 // is not allowed to change anyway.
3665 touchTarget = m_targetForTouchID.get(point.id());
3668 LocalFrame* targetFrame = nullptr;
3669 bool knownTarget = false;
3671 Document& doc = touchTarget->toNode()->document();
3672 // If the target node has moved to a new document while it was being touched,
3673 // we can't send events to the new document because that could leak nodes
3674 // from one document to another. See http://crbug.com/394339.
3675 if (&doc == m_touchSequenceDocument.get()) {
3676 targetFrame = doc.frame();
3681 // If we don't have a target registered for the point it means we've
3682 // missed our opportunity to do a hit test for it (due to some
3683 // optimization that prevented blink from ever seeing the
3684 // touchstart), or that the touch started outside the active touch
3685 // sequence document. We should still include the touch in the
3686 // Touches list reported to the application (eg. so it can
3687 // differentiate between a one and two finger gesture), but we won't
3688 // actually dispatch any events for it. Set the target to the
3689 // Document so that there's some valid node here. Perhaps this
3690 // should really be LocalDOMWindow, but in all other cases the target of
3691 // a Touch is a Node so using the window could be a breaking change.
3692 // Since we know there was no handler invoked, the specific target
3693 // should be completely irrelevant to the application.
3694 touchTarget = m_touchSequenceDocument;
3695 targetFrame = m_touchSequenceDocument->frame();
3697 ASSERT(targetFrame);
3699 // pagePoint should always be relative to the target elements
3700 // containing frame.
3701 FloatPoint pagePoint = targetFrame->view()->windowToContents(point.pos());
3703 float scaleFactor = 1.0f / targetFrame->pageZoomFactor();
3705 FloatPoint adjustedPagePoint = pagePoint.scaledBy(scaleFactor);
3706 FloatSize adjustedRadius = point.radius().scaledBy(scaleFactor);
3708 RefPtrWillBeRawPtr<Touch> touch = Touch::create(
3709 targetFrame, touchTarget.get(), point.id(), point.screenPos(), adjustedPagePoint, adjustedRadius, point.rotationAngle(), point.force());
3711 // Ensure this target's touch list exists, even if it ends up empty, so
3712 // it can always be passed to TouchEvent::Create below.
3713 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3714 if (targetTouchesIterator == touchesByTarget.end()) {
3715 touchesByTarget.set(touchTarget.get(), TouchList::create());
3716 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3719 // touches and targetTouches should only contain information about
3720 // touches still on the screen, so if this point is released or
3721 // cancelled it will only appear in the changedTouches list.
3722 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3723 touches->append(touch);
3724 targetTouchesIterator->value->append(touch);
3727 // Now build up the correct list for changedTouches.
3728 // Note that any touches that are in the TouchStationary state (e.g. if
3729 // the user had several points touched but did not move them all) should
3730 // never be in the changedTouches list so we do not handle them
3731 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
3732 // for further discussion about the TouchStationary state.
3733 if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) {
3734 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3735 if (!changedTouches[pointState].m_touches)
3736 changedTouches[pointState].m_touches = TouchList::create();
3737 changedTouches[pointState].m_touches->append(touch);
3738 changedTouches[pointState].m_targets.add(touchTarget);
3741 if (allTouchReleased) {
3742 m_touchSequenceDocument.clear();
3743 m_touchSequenceUserGestureToken.clear();
3746 // Now iterate the changedTouches list and m_targets within it, sending
3747 // events to the targets as required.
3748 bool swallowedEvent = false;
3749 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3750 if (!changedTouches[state].m_touches)
3753 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3754 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3755 for (const RefPtrWillBeMember<EventTarget>& eventTarget : targetsForState) {
3756 EventTarget* touchEventTarget = eventTarget.get();
3757 RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create(
3758 touches.get(), touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(),
3759 stateName, touchEventTarget->toNode()->document().domWindow(),
3760 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.cancelable());
3761 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3762 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3766 return swallowedEvent;
3769 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
3771 if (action1 == TouchActionNone || action2 == TouchActionNone)
3772 return TouchActionNone;
3773 if (action1 == TouchActionAuto)
3775 if (action2 == TouchActionAuto)
3777 if (!(action1 & action2))
3778 return TouchActionNone;
3779 return action1 & action2;
3782 TouchAction EventHandler::computeEffectiveTouchAction(const Node& node)
3784 // Start by permitting all actions, then walk the elements supporting
3785 // touch-action from the target node up to the nearest scrollable ancestor
3786 // and exclude any prohibited actions.
3787 TouchAction effectiveTouchAction = TouchActionAuto;
3788 for (const Node* curNode = &node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3789 if (RenderObject* renderer = curNode->renderer()) {
3790 if (renderer->supportsTouchAction()) {
3791 TouchAction action = renderer->style()->touchAction();
3792 effectiveTouchAction = intersectTouchAction(action, effectiveTouchAction);
3793 if (effectiveTouchAction == TouchActionNone)
3797 // If we've reached an ancestor that supports a touch action, search no further.
3798 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3802 return effectiveTouchAction;
3805 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3807 m_mousePositionIsUnknown = false;
3808 m_lastKnownMousePosition = event.position();
3809 m_lastKnownMouseGlobalPosition = event.globalPosition();
3812 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3814 // If we're clicking into a frame that is selected, the frame will appear
3815 // greyed out even though we're clicking on the selection. This looks
3816 // really strange (having the whole frame be greyed out), so we deselect the
3818 IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3819 if (m_frame->selection().contains(p)) {
3820 VisiblePosition visiblePos(
3821 mev.innerNode()->renderer()->positionForPoint(mev.localPoint()));
3822 VisibleSelection newSelection(visiblePos);
3823 m_frame->selection().setSelection(newSelection);
3826 subframe->eventHandler().handleMousePressEvent(mev.event());
3830 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe, HitTestResult* hoveredNode)
3832 if (m_mouseDownMayStartDrag)
3834 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3838 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3840 subframe->eventHandler().handleMouseReleaseEvent(mev.event());
3844 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
3846 // We can sometimes get a null widget! EventHandlerMac handles a null
3847 // widget by returning false, so we do the same.
3851 // If not a FrameView, then probably a plugin widget. Those will receive
3852 // the event via an EventTargetNode dispatch when this returns false.
3853 if (!widget->isFrameView())
3856 return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
3859 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
3861 // Figure out which view to send the event to.
3862 if (!event.innerNode() || !event.innerNode()->renderer() || !event.innerNode()->renderer()->isRenderPart())
3867 PassRefPtrWillBeRawPtr<DataTransfer> EventHandler::createDraggingDataTransfer() const
3869 return DataTransfer::create(DataTransfer::DragAndDrop, DataTransferWritable, DataObject::create());
3872 void EventHandler::focusDocumentView()
3874 Page* page = m_frame->page();
3877 page->focusController().focusDocumentView(m_frame);
3880 unsigned EventHandler::accessKeyModifiers()
3883 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
3885 return PlatformEvent::AltKey;
3889 } // namespace blink