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 "HTMLNames.h"
32 #include "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ExceptionStatePlaceholder.h"
35 #include "core/clipboard/Clipboard.h"
36 #include "core/clipboard/DataObject.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/DocumentMarkerController.h"
39 #include "core/dom/FullscreenElementStack.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/FrameView.h"
56 #include "core/frame/LocalFrame.h"
57 #include "core/html/HTMLDialogElement.h"
58 #include "core/html/HTMLFrameElementBase.h"
59 #include "core/html/HTMLFrameSetElement.h"
60 #include "core/html/HTMLInputElement.h"
61 #include "core/loader/FrameLoader.h"
62 #include "core/loader/FrameLoaderClient.h"
63 #include "core/page/AutoscrollController.h"
64 #include "core/page/BackForwardClient.h"
65 #include "core/page/Chrome.h"
66 #include "core/page/ChromeClient.h"
67 #include "core/page/DragController.h"
68 #include "core/page/DragState.h"
69 #include "core/page/EditorClient.h"
70 #include "core/page/FocusController.h"
71 #include "core/page/FrameTree.h"
72 #include "core/inspector/InspectorController.h"
73 #include "core/page/MouseEventWithHitTestResults.h"
74 #include "core/page/Page.h"
75 #include "core/frame/Settings.h"
76 #include "core/page/SpatialNavigation.h"
77 #include "core/page/TouchAdjustment.h"
78 #include "core/rendering/HitTestRequest.h"
79 #include "core/rendering/HitTestResult.h"
80 #include "core/rendering/RenderFlowThread.h"
81 #include "core/rendering/RenderLayer.h"
82 #include "core/rendering/RenderTextControlSingleLine.h"
83 #include "core/rendering/RenderView.h"
84 #include "core/rendering/RenderWidget.h"
85 #include "core/rendering/style/CursorList.h"
86 #include "core/rendering/style/RenderStyle.h"
87 #include "core/svg/SVGDocument.h"
88 #include "core/svg/SVGElementInstance.h"
89 #include "core/svg/SVGUseElement.h"
90 #include "heap/Handle.h"
91 #include "platform/PlatformGestureEvent.h"
92 #include "platform/PlatformKeyboardEvent.h"
93 #include "platform/PlatformTouchEvent.h"
94 #include "platform/PlatformWheelEvent.h"
95 #include "platform/WindowsKeyboardCodes.h"
96 #include "platform/geometry/FloatPoint.h"
97 #include "platform/graphics/Image.h"
98 #include "platform/scroll/ScrollAnimator.h"
99 #include "platform/scroll/Scrollbar.h"
100 #include "wtf/Assertions.h"
101 #include "wtf/CurrentTime.h"
102 #include "wtf/StdLibExtras.h"
103 #include "wtf/TemporaryChange.h"
107 using namespace HTMLNames;
108 using namespace SVGNames;
110 // The link drag hysteresis is much larger than the others because there
111 // needs to be enough space to cancel the link press without starting a link drag,
112 // and because dragging links is rare.
113 static const int LinkDragHysteresis = 40;
114 static const int ImageDragHysteresis = 5;
115 static const int TextDragHysteresis = 3;
116 static const int GeneralDragHysteresis = 3;
118 // The amount of time to wait before sending a fake mouse event, triggered
119 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
120 // otherwise the long interval is used.
121 static const double fakeMouseMoveShortInterval = 0.1;
122 static const double fakeMouseMoveLongInterval = 0.250;
124 // The amount of time to wait for a cursor update on style and layout changes
125 // Set to 50Hz, no need to be faster than common screen refresh rate
126 static const double cursorUpdateInterval = 0.02;
128 static const int maximumCursorSize = 128;
130 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
131 // need to ensure here is that the scale isn't so small that integer overflow can occur when
132 // dividing cursor sizes (limited above) by the scale.
133 static const double minimumCursorScale = 0.001;
135 // The minimum amount of time an element stays active after a ShowPress
136 // This is roughly 2 frames, which should be long enough to be noticeable.
137 static const double minimumActiveInterval = 0.032;
140 static const double TextDragDelay = 0.15;
142 static const double TextDragDelay = 0.0;
145 enum NoCursorChangeType { NoCursorChange };
147 class OptionalCursor {
149 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
150 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
152 bool isCursorChange() const { return m_isCursorChange; }
153 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
156 bool m_isCursorChange;
160 class MaximumDurationTracker {
162 explicit MaximumDurationTracker(double *maxDuration)
163 : m_maxDuration(maxDuration)
164 , m_start(monotonicallyIncreasingTime())
168 ~MaximumDurationTracker()
170 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
174 double* m_maxDuration;
178 class SyntheticTouchPoint : public PlatformTouchPoint {
181 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
182 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
184 const static int idDefaultValue = 0;
185 const static int radiusYDefaultValue = 1;
186 const static int radiusXDefaultValue = 1;
187 const static float rotationAngleDefaultValue = 0.0f;
188 const static float forceDefaultValue = 1.0f;
190 m_id = idDefaultValue; // There is only one active TouchPoint.
191 m_screenPos = event.globalPosition();
192 m_pos = event.position();
193 m_radiusY = radiusYDefaultValue;
194 m_radiusX = radiusXDefaultValue;
195 m_rotationAngle = rotationAngleDefaultValue;
196 m_force = forceDefaultValue;
198 PlatformEvent::Type type = event.type();
199 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
202 case PlatformEvent::MouseMoved:
203 m_state = TouchMoved;
205 case PlatformEvent::MousePressed:
206 m_state = TouchPressed;
208 case PlatformEvent::MouseReleased:
209 m_state = TouchReleased;
212 ASSERT_NOT_REACHED();
218 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
220 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
222 switch (event.type()) {
223 case PlatformEvent::MouseMoved:
226 case PlatformEvent::MousePressed:
229 case PlatformEvent::MouseReleased:
233 ASSERT_NOT_REACHED();
237 m_timestamp = event.timestamp();
238 m_modifiers = event.modifiers();
239 m_touchPoints.append(SyntheticTouchPoint(event));
243 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
246 case WheelEvent::DOM_DELTA_PAGE:
248 case WheelEvent::DOM_DELTA_LINE:
250 case WheelEvent::DOM_DELTA_PIXEL:
251 return ScrollByPixel;
253 return ScrollByPixel;
257 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
258 // If a mouse event handler changes the input element type to one that has a widget associated,
259 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
260 // event target node can't still be the shadow node.
261 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
263 Node* targetNode = mev.targetNode();
264 if (!targetNode || !targetNode->parentNode())
266 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host());
269 EventHandler::EventHandler(LocalFrame* frame)
271 , m_mousePressed(false)
272 , m_capturesDragging(false)
273 , m_mouseDownMayStartSelect(false)
274 , m_mouseDownMayStartDrag(false)
275 , m_mouseDownWasSingleClickInSelection(false)
276 , m_selectionInitiationState(HaveNotStartedSelection)
277 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
278 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
279 , m_mouseDownMayStartAutoscroll(false)
280 , m_mouseDownWasInSubframe(false)
281 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
283 , m_resizeScrollableArea(0)
284 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
286 , m_shouldOnlyFireDragOverEvent(false)
287 , m_mousePositionIsUnknown(true)
288 , m_mouseDownTimestamp(0)
289 , m_widgetIsLatched(false)
290 , m_originatingTouchPointTargetKey(0)
291 , m_touchPressed(false)
292 , m_scrollGestureHandlingNode(nullptr)
293 , m_lastHitTestResultOverWidget(false)
294 , m_maxMouseMovedDuration(0)
295 , m_baseEventType(PlatformEvent::NoType)
296 , m_didStartDrag(false)
297 , m_longTapShouldInvokeContextMenu(false)
298 , m_syntheticPageScaleFactor(0)
299 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
300 , m_lastShowPressTimestamp(0)
304 EventHandler::~EventHandler()
306 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
309 DragState& EventHandler::dragState()
312 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState()));
315 DEFINE_STATIC_LOCAL(DragState, state, ());
320 void EventHandler::clear()
323 m_cursorUpdateTimer.stop();
324 m_fakeMouseMoveEventTimer.stop();
325 m_activeIntervalTimer.stop();
326 m_resizeScrollableArea = 0;
327 m_nodeUnderMouse = nullptr;
328 m_lastNodeUnderMouse = nullptr;
329 m_instanceUnderMouse = nullptr;
330 m_lastInstanceUnderMouse = nullptr;
331 m_lastMouseMoveEventSubframe = nullptr;
332 m_lastScrollbarUnderMouse = nullptr;
334 m_clickNode = nullptr;
335 m_frameSetBeingResized = nullptr;
336 m_dragTarget = nullptr;
337 m_shouldOnlyFireDragOverEvent = false;
338 m_mousePositionIsUnknown = true;
339 m_lastKnownMousePosition = IntPoint();
340 m_lastKnownMouseGlobalPosition = IntPoint();
341 m_lastMouseDownUserGestureToken.clear();
342 m_mousePressNode = nullptr;
343 m_mousePressed = false;
344 m_capturesDragging = false;
345 m_capturingMouseEventsNode = nullptr;
346 m_latchedWheelEventNode = nullptr;
347 m_previousWheelScrolledNode = nullptr;
348 m_originatingTouchPointTargets.clear();
349 m_originatingTouchPointDocument.clear();
350 m_originatingTouchPointTargetKey = 0;
351 m_scrollGestureHandlingNode = nullptr;
352 m_lastHitTestResultOverWidget = false;
353 m_previousGestureScrolledNode = nullptr;
354 m_scrollbarHandlingScrollGesture = nullptr;
355 m_maxMouseMovedDuration = 0;
356 m_baseEventType = PlatformEvent::NoType;
357 m_didStartDrag = false;
358 m_touchPressed = false;
359 m_mouseDownMayStartSelect = false;
360 m_mouseDownMayStartDrag = false;
361 m_lastShowPressTimestamp = 0;
362 m_lastDeferredTapElement = nullptr;
365 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
367 if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
369 if (nodeToBeRemoved.isInShadowTree()) {
370 m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
372 // We don't dispatch click events if the mousedown node is removed
373 // before a mouseup event. It is compatible with IE and Firefox.
374 m_clickNode = nullptr;
378 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
380 if (selection.selection() != newSelection)
381 selection.setSelection(newSelection);
384 static inline bool dispatchSelectStart(Node* node)
386 if (!node || !node->renderer())
389 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
392 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
394 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
395 if (!rootUserSelectAll)
398 VisibleSelection newSelection(selection);
399 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
400 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
405 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
407 if (Position::nodeIsUserSelectNone(targetNode))
410 if (!dispatchSelectStart(targetNode))
413 if (selection.isRange())
414 m_selectionInitiationState = ExtendedSelection;
416 granularity = CharacterGranularity;
417 m_selectionInitiationState = PlacedCaret;
420 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
425 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
427 Node* innerNode = result.targetNode();
428 VisibleSelection newSelection;
430 if (innerNode && innerNode->renderer()) {
431 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
432 if (pos.isNotNull()) {
433 newSelection = VisibleSelection(pos);
434 newSelection.expandUsingGranularity(WordGranularity);
437 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
438 newSelection.appendTrailingWhitespace();
440 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
444 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
446 Node* innerNode = result.targetNode();
447 VisibleSelection newSelection;
449 if (innerNode && innerNode->renderer()) {
450 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
451 Position start = pos.deepEquivalent();
452 Position end = pos.deepEquivalent();
453 if (pos.isNotNull()) {
454 Vector<DocumentMarker*> markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
455 if (markers.size() == 1) {
456 start.moveToOffset(markers[0]->startOffset());
457 end.moveToOffset(markers[0]->endOffset());
458 newSelection = VisibleSelection(start, end);
462 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
463 newSelection.appendTrailingWhitespace();
465 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
469 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
471 if (m_mouseDownMayStartSelect) {
472 selectClosestWordFromHitTestResult(result.hitTestResult(),
473 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
477 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
479 if (m_mouseDownMayStartSelect) {
480 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
481 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
485 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
487 if (!result.hitTestResult().isLiveLink())
488 return selectClosestWordFromMouseEvent(result);
490 Node* innerNode = result.targetNode();
492 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
493 VisibleSelection newSelection;
494 Element* URLElement = result.hitTestResult().URLElement();
495 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
496 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
497 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
499 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
503 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
505 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventDoubleClick");
507 if (event.event().button() != LeftButton)
510 if (m_frame->selection().isRange()) {
511 // A double-click when range is already selected
512 // should not change the selection. So, do not call
513 // selectClosestWordFromMouseEvent, but do set
514 // m_beganSelectingText to prevent handleMouseReleaseEvent
515 // from setting caret selection.
516 m_selectionInitiationState = ExtendedSelection;
518 selectClosestWordFromMouseEvent(event);
523 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
525 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventTripleClick");
527 if (event.event().button() != LeftButton)
530 Node* innerNode = event.targetNode();
531 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
534 VisibleSelection newSelection;
535 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
536 if (pos.isNotNull()) {
537 newSelection = VisibleSelection(pos);
538 newSelection.expandUsingGranularity(ParagraphGranularity);
541 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
544 static int textDistance(const Position& start, const Position& end)
546 RefPtr<Range> range = Range::create(*start.document(), start, end);
547 return TextIterator::rangeLength(range.get(), true);
550 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
552 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventSingleClick");
554 m_frame->document()->updateLayoutIgnorePendingStylesheets();
555 Node* innerNode = event.targetNode();
556 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
559 // Extend the selection if the Shift key is down, unless the click is in a link.
560 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
562 // Don't restart the selection when the mouse is pressed on an
563 // existing selection so we can allow for text dragging.
564 if (FrameView* view = m_frame->view()) {
565 LayoutPoint vPoint = view->windowToContents(event.event().position());
566 if (!extendSelection && m_frame->selection().contains(vPoint)) {
567 m_mouseDownWasSingleClickInSelection = true;
572 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
573 if (visiblePos.isNull())
574 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
575 Position pos = visiblePos.deepEquivalent();
577 VisibleSelection newSelection = m_frame->selection().selection();
578 TextGranularity granularity = CharacterGranularity;
580 if (extendSelection && newSelection.isCaretOrRange()) {
581 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
582 if (selectionInUserSelectAll.isRange()) {
583 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
584 pos = selectionInUserSelectAll.start();
585 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
586 pos = selectionInUserSelectAll.end();
589 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
590 if (pos.isNotNull()) {
591 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
592 // was created right-to-left
593 Position start = newSelection.start();
594 Position end = newSelection.end();
595 int distanceToStart = textDistance(start, pos);
596 int distanceToEnd = textDistance(pos, end);
597 if (distanceToStart <= distanceToEnd)
598 newSelection = VisibleSelection(end, pos);
600 newSelection = VisibleSelection(start, pos);
603 newSelection.setExtent(pos);
605 if (m_frame->selection().granularity() != CharacterGranularity) {
606 granularity = m_frame->selection().granularity();
607 newSelection.expandUsingGranularity(m_frame->selection().granularity());
610 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos));
613 bool handled = updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
617 static inline bool canMouseDownStartSelect(Node* node)
619 if (!node || !node->renderer())
622 if (!node->canStartSelection())
628 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
630 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
633 dragState().m_dragSrc = nullptr;
635 cancelFakeMouseMoveEvent();
637 m_frame->document()->updateLayoutIgnorePendingStylesheets();
639 if (ScrollView* scrollView = m_frame->view()) {
640 if (scrollView->isPointInScrollbarCorner(event.event().position()))
644 bool singleClick = event.event().clickCount() <= 1;
646 // If we got the event back, that must mean it wasn't prevented,
647 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
648 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
650 m_mouseDownMayStartDrag = singleClick;
652 m_mouseDownWasSingleClickInSelection = false;
654 m_mouseDown = event.event();
656 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
659 if (m_frame->document()->isSVGDocument()
660 && toSVGDocument(m_frame->document())->zoomAndPanEnabled()) {
661 if (event.event().shiftKey() && singleClick) {
663 toSVGDocument(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
668 // We don't do this at the start of mouse down handling,
669 // because we don't want to do it until we know we didn't hit a widget.
673 Node* innerNode = event.targetNode();
675 m_mousePressNode = innerNode;
676 m_dragStartPos = event.event().position();
678 bool swallowEvent = false;
679 m_mousePressed = true;
680 m_selectionInitiationState = HaveNotStartedSelection;
682 if (event.event().clickCount() == 2)
683 swallowEvent = handleMousePressEventDoubleClick(event);
684 else if (event.event().clickCount() >= 3)
685 swallowEvent = handleMousePressEventTripleClick(event);
687 swallowEvent = handleMousePressEventSingleClick(event);
689 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
690 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
695 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
697 TRACE_EVENT0("webkit", "EventHandler::handleMouseDraggedEvent");
702 if (handleDrag(event, ShouldCheckDragHysteresis))
705 Node* targetNode = event.targetNode();
706 if (event.event().button() != LeftButton || !targetNode)
709 RenderObject* renderer = targetNode->renderer();
711 Node* parent = NodeRenderingTraversal::parent(targetNode);
715 renderer = parent->renderer();
716 if (!renderer || !renderer->isListBox())
720 m_mouseDownMayStartDrag = false;
722 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
723 if (AutoscrollController* controller = autoscrollController()) {
724 controller->startAutoscrollForSelection(renderer);
725 m_mouseDownMayStartAutoscroll = false;
729 if (m_selectionInitiationState != ExtendedSelection) {
730 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
731 HitTestResult result(m_mouseDownPos);
732 m_frame->document()->renderView()->hitTest(request, result);
734 updateSelectionForMouseDrag(result);
736 updateSelectionForMouseDrag(event.hitTestResult());
740 void EventHandler::updateSelectionForMouseDrag()
742 FrameView* view = m_frame->view();
745 RenderView* renderer = m_frame->contentRenderer();
749 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
750 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
751 renderer->hitTest(request, result);
752 updateSelectionForMouseDrag(result);
755 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
757 if (!m_mouseDownMayStartSelect)
760 Node* target = hitTestResult.targetNode();
764 VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
765 // Don't modify the selection if we're not on a node.
766 if (targetPosition.isNull())
769 // Restart the selection if this is the first mouse move. This work is usually
770 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
771 VisibleSelection newSelection = m_frame->selection().selection();
773 // Special case to limit selection to the containing block for SVG text.
774 // FIXME: Isn't there a better non-SVG-specific way to do this?
775 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
776 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
777 if (selectionBaseRenderer->isSVGText())
778 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
781 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
784 if (m_selectionInitiationState != ExtendedSelection) {
785 // Always extend selection here because it's caused by a mouse drag
786 m_selectionInitiationState = ExtendedSelection;
787 newSelection = VisibleSelection(targetPosition);
790 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
791 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
792 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
793 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
794 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
796 // Reset base for user select all when base is inside user-select-all area and extent < base.
797 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
798 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
800 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
801 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
802 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
803 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
804 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
806 newSelection.setExtent(targetPosition);
809 newSelection.setExtent(targetPosition);
812 if (m_frame->selection().granularity() != CharacterGranularity)
813 newSelection.expandUsingGranularity(m_frame->selection().granularity());
815 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
816 FrameSelection::AdjustEndpointsAtBidiBoundary);
819 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
821 AutoscrollController* controller = autoscrollController();
822 if (controller && controller->autoscrollInProgress())
825 // Used to prevent mouseMoveEvent from initiating a drag before
826 // the mouse is pressed again.
827 m_mousePressed = false;
828 m_capturesDragging = false;
829 m_mouseDownMayStartDrag = false;
830 m_mouseDownMayStartSelect = false;
831 m_mouseDownMayStartAutoscroll = false;
832 m_mouseDownWasInSubframe = false;
834 bool handled = false;
836 // Clear the selection if the mouse didn't move after the last mouse
837 // press and it's not a context menu click. We do this so when clicking
838 // on the selection, the selection goes away. However, if we are
839 // editing, place the caret.
840 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
841 && m_dragStartPos == event.event().position()
842 && m_frame->selection().isRange()
843 && event.event().button() != RightButton) {
844 VisibleSelection newSelection;
845 Node* node = event.targetNode();
846 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
847 if (node && node->renderer() && (caretBrowsing || node->rendererIsEditable())) {
848 VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
849 newSelection = VisibleSelection(pos);
852 setSelectionIfNeeded(m_frame->selection(), newSelection);
857 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
859 m_frame->selection().selectFrameElementInParentIfFullySelected();
861 if (event.event().button() == MiddleButton && !event.isOverLink()) {
862 // Ignore handled, since we want to paste to where the caret was placed anyway.
863 handled = handlePasteGlobalSelection(event.event()) || handled;
871 void EventHandler::startPanScrolling(RenderObject* renderer)
873 if (!renderer->isBox())
875 AutoscrollController* controller = autoscrollController();
878 controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
884 AutoscrollController* EventHandler::autoscrollController() const
886 if (Page* page = m_frame->page())
887 return &page->autoscrollController();
891 bool EventHandler::panScrollInProgress() const
893 return autoscrollController() && autoscrollController()->panScrollInProgress();
896 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
898 TRACE_EVENT0("webkit", "EventHandler::hitTestResultAtPoint");
900 // We always send hitTestResultAtPoint to the main frame if we have one,
901 // otherwise we might hit areas that are obscured by higher frames.
902 if (Page* page = m_frame->page()) {
903 LocalFrame* mainFrame = page->mainFrame();
904 if (m_frame != mainFrame) {
905 FrameView* frameView = m_frame->view();
906 FrameView* mainView = mainFrame->view();
907 if (frameView && mainView) {
908 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
909 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
914 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
916 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
917 // layout because until then, there is nothing shown on the screen - the user can't
918 // have intentionally clicked on something belonging to this page. Furthermore,
919 // mousemove events before the first layout should not lead to a premature layout()
920 // happening, which could show a flash of white.
921 // See also the similar code in Document::prepareMouseEvent.
922 if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
925 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
926 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
927 m_frame->contentRenderer()->hitTest(request, result);
928 if (!request.readOnly())
929 m_frame->document()->updateHoverActiveState(request, result.innerElement());
931 if (request.disallowsShadowContent())
932 result.setToNodesInDocumentTreeScope();
937 void EventHandler::stopAutoscroll()
939 if (AutoscrollController* controller = autoscrollController())
940 controller->stopAutoscroll();
943 Node* EventHandler::mousePressNode() const
945 return m_mousePressNode.get();
948 bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoint absolutePoint)
953 Node* node = startNode;
956 node = m_frame->document()->focusedElement();
959 node = m_mousePressNode.get();
961 if (!node || !node->renderer())
964 RenderBox* curBox = node->renderer()->enclosingBox();
965 while (curBox && !curBox->isRenderView()) {
966 ScrollDirection physicalDirection = toPhysicalDirection(
967 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode());
969 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
970 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *stopNode;
971 bool didScroll = curBox->scroll(physicalDirection, granularity, delta);
973 if (didScroll && stopNode)
974 *stopNode = curBox->node();
976 if (didScroll || shouldStopBubbling) {
977 setFrameWasScrolledByUser();
981 curBox = curBox->containingBlock();
987 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
989 // The layout needs to be up to date to determine if we can scroll. We may be
990 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
991 m_frame->document()->updateLayoutIgnorePendingStylesheets();
992 if (scroll(direction, granularity, startingNode))
994 LocalFrame* frame = m_frame;
995 FrameView* view = frame->view();
996 if (view && view->scroll(direction, granularity))
998 frame = frame->tree().parent();
1001 return frame->eventHandler().bubblingScroll(direction, granularity, m_frame->ownerElement());
1004 IntPoint EventHandler::lastKnownMousePosition() const
1006 return m_lastKnownMousePosition;
1009 static LocalFrame* subframeForTargetNode(Node* node)
1014 RenderObject* renderer = node->renderer();
1015 if (!renderer || !renderer->isWidget())
1018 Widget* widget = toRenderWidget(renderer)->widget();
1019 if (!widget || !widget->isFrameView())
1022 return &toFrameView(widget)->frame();
1025 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1027 if (!hitTestResult.isOverWidget())
1029 return subframeForTargetNode(hitTestResult.targetNode());
1032 static bool isSubmitImage(Node* node)
1034 return isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
1037 // Returns true if the node's editable block is not current focused for editing
1038 static bool nodeIsNotBeingEdited(Node* node, LocalFrame* frame)
1040 return frame->selection().rootEditableElement() != node->rootEditableElement();
1043 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1048 bool editable = node->rendererIsEditable();
1049 bool editableLinkEnabled = false;
1051 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1053 ASSERT(m_frame->settings());
1054 switch (m_frame->settings()->editableLinkBehavior()) {
1056 case EditableLinkDefaultBehavior:
1057 case EditableLinkAlwaysLive:
1058 editableLinkEnabled = true;
1061 case EditableLinkNeverLive:
1062 editableLinkEnabled = false;
1065 case EditableLinkLiveWhenNotFocused:
1066 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || shiftKey;
1069 case EditableLinkOnlyLiveWithShiftKey:
1070 editableLinkEnabled = shiftKey;
1075 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1078 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
1081 ASSERT(m_frame->document());
1086 void EventHandler::updateCursor()
1088 if (m_mousePositionIsUnknown)
1091 FrameView* view = m_frame->view();
1092 if (!view || !view->shouldSetCursor())
1095 RenderView* renderView = view->renderView();
1103 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1105 m_frame->document()->updateLayout();
1107 HitTestRequest request(HitTestRequest::ReadOnly);
1108 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1109 renderView->hitTest(request, result);
1111 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1112 if (optionalCursor.isCursorChange()) {
1113 m_currentMouseCursor = optionalCursor.cursor();
1114 view->setCursor(m_currentMouseCursor);
1118 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1120 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1121 return NoCursorChange;
1123 Page* page = m_frame->page();
1125 return NoCursorChange;
1127 if (panScrollInProgress())
1128 return NoCursorChange;
1131 Node* node = result.targetNode();
1133 return selectAutoCursor(result, node, iBeamCursor(), shiftKey);
1135 RenderObject* renderer = node->renderer();
1136 RenderStyle* style = renderer ? renderer->style() : 0;
1139 Cursor overrideCursor;
1140 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1141 case SetCursorBasedOnStyle:
1144 return overrideCursor;
1145 case DoNotSetCursor:
1146 return NoCursorChange;
1150 if (style && style->cursors()) {
1151 const CursorList* cursors = style->cursors();
1152 for (unsigned i = 0; i < cursors->size(); ++i) {
1153 StyleImage* styleImage = (*cursors)[i].image();
1156 ImageResource* cachedImage = styleImage->cachedImage();
1159 float scale = styleImage->imageScaleFactor();
1160 // Get hotspot and convert from logical pixels to physical pixels.
1161 IntPoint hotSpot = (*cursors)[i].hotSpot();
1162 hotSpot.scale(scale, scale);
1163 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1164 if (cachedImage->errorOccurred())
1166 // Limit the size of cursors (in UI pixels) so that they cannot be
1167 // used to cover UI elements in chrome.
1168 size.scale(1 / scale);
1169 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1172 Image* image = cachedImage->imageForRenderer(renderer);
1173 // Ensure no overflow possible in calculations above.
1174 if (scale < minimumCursorScale)
1176 return Cursor(image, hotSpot, scale);
1180 switch (style ? style->cursor() : CURSOR_AUTO) {
1182 bool horizontalText = !style || style->isHorizontalWritingMode();
1183 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1184 return selectAutoCursor(result, node, iBeam, shiftKey);
1187 return crossCursor();
1188 case CURSOR_POINTER:
1189 return handCursor();
1191 return moveCursor();
1192 case CURSOR_ALL_SCROLL:
1193 return moveCursor();
1194 case CURSOR_E_RESIZE:
1195 return eastResizeCursor();
1196 case CURSOR_W_RESIZE:
1197 return westResizeCursor();
1198 case CURSOR_N_RESIZE:
1199 return northResizeCursor();
1200 case CURSOR_S_RESIZE:
1201 return southResizeCursor();
1202 case CURSOR_NE_RESIZE:
1203 return northEastResizeCursor();
1204 case CURSOR_SW_RESIZE:
1205 return southWestResizeCursor();
1206 case CURSOR_NW_RESIZE:
1207 return northWestResizeCursor();
1208 case CURSOR_SE_RESIZE:
1209 return southEastResizeCursor();
1210 case CURSOR_NS_RESIZE:
1211 return northSouthResizeCursor();
1212 case CURSOR_EW_RESIZE:
1213 return eastWestResizeCursor();
1214 case CURSOR_NESW_RESIZE:
1215 return northEastSouthWestResizeCursor();
1216 case CURSOR_NWSE_RESIZE:
1217 return northWestSouthEastResizeCursor();
1218 case CURSOR_COL_RESIZE:
1219 return columnResizeCursor();
1220 case CURSOR_ROW_RESIZE:
1221 return rowResizeCursor();
1223 return iBeamCursor();
1225 return waitCursor();
1227 return helpCursor();
1228 case CURSOR_VERTICAL_TEXT:
1229 return verticalTextCursor();
1231 return cellCursor();
1232 case CURSOR_CONTEXT_MENU:
1233 return contextMenuCursor();
1234 case CURSOR_PROGRESS:
1235 return progressCursor();
1236 case CURSOR_NO_DROP:
1237 return noDropCursor();
1239 return aliasCursor();
1241 return copyCursor();
1243 return noneCursor();
1244 case CURSOR_NOT_ALLOWED:
1245 return notAllowedCursor();
1246 case CURSOR_DEFAULT:
1247 return pointerCursor();
1248 case CURSOR_WEBKIT_ZOOM_IN:
1249 return zoomInCursor();
1250 case CURSOR_WEBKIT_ZOOM_OUT:
1251 return zoomOutCursor();
1252 case CURSOR_WEBKIT_GRAB:
1253 return grabCursor();
1254 case CURSOR_WEBKIT_GRABBING:
1255 return grabbingCursor();
1257 return pointerCursor();
1260 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam, bool shiftKey)
1262 bool editable = (node && node->rendererIsEditable());
1264 if (useHandCursor(node, result.isOverLink(), shiftKey))
1265 return handCursor();
1267 bool inResizer = false;
1268 RenderObject* renderer = node ? node->renderer() : 0;
1269 if (renderer && m_frame->view()) {
1270 RenderLayer* layer = renderer->enclosingLayer();
1271 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1274 // During selection, use an I-beam no matter what we're over.
1275 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1276 if (m_mousePressed && m_mouseDownMayStartSelect
1277 && !m_mouseDownMayStartDrag
1278 && m_frame->selection().isCaretOrRange()
1279 && !m_capturingMouseEventsNode) {
1283 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1285 return pointerCursor();
1288 static LayoutPoint documentPointForWindowPoint(LocalFrame* frame, const IntPoint& windowPoint)
1290 FrameView* view = frame->view();
1291 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1292 // Historically the code would just crash; this is clearly no worse than that.
1293 return view ? view->windowToContents(windowPoint) : windowPoint;
1296 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1298 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
1300 RefPtr<FrameView> protector(m_frame->view());
1302 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1303 if (defaultPrevented)
1306 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1307 m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1309 cancelFakeMouseMoveEvent();
1310 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1311 m_capturingMouseEventsNode = nullptr;
1312 m_mousePressed = true;
1313 m_capturesDragging = true;
1314 setLastKnownMousePosition(mouseEvent);
1315 m_mouseDownTimestamp = mouseEvent.timestamp();
1316 m_mouseDownMayStartDrag = false;
1317 m_mouseDownMayStartSelect = false;
1318 m_mouseDownMayStartAutoscroll = false;
1319 if (FrameView* view = m_frame->view())
1320 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1325 m_mouseDownWasInSubframe = false;
1327 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1328 if (mouseEvent.fromTouch())
1329 hitType |= HitTestRequest::ReadOnly;
1330 HitTestRequest request(hitType);
1331 // Save the document point we generate in case the window coordinate is invalidated by what happens
1332 // when we dispatch the event.
1333 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1334 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1336 if (!mev.targetNode()) {
1341 m_mousePressNode = mev.targetNode();
1343 RefPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1344 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1345 // Start capturing future events for this frame. We only do this if we didn't clear
1346 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1347 m_capturesDragging = subframe->eventHandler().capturesDragging();
1348 if (m_mousePressed && m_capturesDragging) {
1349 m_capturingMouseEventsNode = mev.targetNode();
1350 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1357 // We store whether pan scrolling is in progress before calling stopAutoscroll()
1358 // because it will set m_autoscrollType to NoAutoscroll on return.
1359 bool isPanScrollInProgress = panScrollInProgress();
1361 if (isPanScrollInProgress) {
1362 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1363 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1369 m_clickCount = mouseEvent.clickCount();
1370 m_clickNode = mev.targetNode()->isTextNode() ? mev.targetNode()->parentOrShadowHostNode() : mev.targetNode();
1372 if (FrameView* view = m_frame->view()) {
1373 RenderLayer* layer = mev.targetNode()->renderer() ? mev.targetNode()->renderer()->enclosingLayer() : 0;
1374 IntPoint p = view->windowToContents(mouseEvent.position());
1375 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1376 m_resizeScrollableArea = layer->scrollableArea();
1377 m_resizeScrollableArea->setInResizeMode(true);
1378 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1384 m_frame->selection().setCaretBlinkingSuspended(true);
1386 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1387 m_capturesDragging = !swallowEvent || mev.scrollbar();
1389 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1390 // in case the scrollbar widget was destroyed when the mouse event was handled.
1391 if (mev.scrollbar()) {
1392 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1393 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1394 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1395 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1396 m_lastScrollbarUnderMouse = nullptr;
1400 // scrollbars should get events anyway, even disabled controls might be scrollable
1401 Scrollbar* scrollbar = mev.scrollbar();
1403 updateLastScrollbarUnderMouse(scrollbar, true);
1406 passMousePressEventToScrollbar(mev, scrollbar);
1408 if (shouldRefetchEventTarget(mev)) {
1409 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1410 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1413 FrameView* view = m_frame->view();
1414 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1416 scrollbar = mev.scrollbar();
1418 updateLastScrollbarUnderMouse(scrollbar, true);
1420 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1421 swallowEvent = true;
1423 swallowEvent = handleMousePressEvent(mev);
1426 return swallowEvent;
1429 static RenderLayer* layerForNode(Node* node)
1434 RenderObject* renderer = node->renderer();
1438 RenderLayer* layer = renderer->enclosingLayer();
1445 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1447 ScrollableArea* layerScrollableArea = layer->scrollableArea();
1448 if (!layerScrollableArea)
1451 if (FrameView* frameView = m_frame->view()) {
1452 if (frameView->containsScrollableArea(layerScrollableArea))
1453 return layerScrollableArea;
1459 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1461 TRACE_EVENT0("webkit", "EventHandler::handleMouseMoveEvent");
1463 RefPtr<FrameView> protector(m_frame->view());
1464 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1466 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1467 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1469 Page* page = m_frame->page();
1473 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1474 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1475 layerScrollableArea->mouseMovedInContentArea();
1478 if (FrameView* frameView = m_frame->view())
1479 frameView->mouseMovedInContentArea();
1481 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1482 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1483 page->chrome().setToolTip(hoveredNode);
1488 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1490 TRACE_EVENT0("webkit", "EventHandler::handleMouseLeaveEvent");
1492 RefPtr<FrameView> protector(m_frame->view());
1493 handleMouseMoveOrLeaveEvent(event);
1496 static Cursor& syntheticTouchCursor()
1498 DEFINE_STATIC_LOCAL(Cursor, c, (Image::loadPlatformResource("syntheticTouchCursor").get(), IntPoint(10, 10)));
1502 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1505 ASSERT(m_frame->view());
1507 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1508 if (defaultPrevented) {
1509 m_frame->view()->setCursor(syntheticTouchCursor());
1513 setLastKnownMousePosition(mouseEvent);
1515 if (m_hoverTimer.isActive())
1516 m_hoverTimer.stop();
1518 m_cursorUpdateTimer.stop();
1520 cancelFakeMouseMoveEvent();
1523 toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1527 if (m_frameSetBeingResized)
1528 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1530 // Send events right to a scrollbar if the mouse is pressed.
1531 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1532 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1536 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1537 if (mouseEvent.fromTouch())
1538 hitType |= HitTestRequest::ReadOnly;
1541 hitType |= HitTestRequest::Active;
1542 else if (onlyUpdateScrollbars) {
1543 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1544 // means that :hover and :active freeze in the state they were in, rather than updating
1545 // for nodes the mouse moves while the window is not key (which will be the case if
1546 // onlyUpdateScrollbars is true).
1547 hitType |= HitTestRequest::ReadOnly;
1550 // Treat any mouse move events as readonly if the user is currently touching the screen.
1552 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1553 HitTestRequest request(hitType);
1554 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1556 *hoveredNode = mev.hitTestResult();
1558 Scrollbar* scrollbar = 0;
1560 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1561 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1563 if (FrameView* view = m_frame->view())
1564 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1567 scrollbar = mev.scrollbar();
1569 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1570 if (onlyUpdateScrollbars)
1574 bool swallowEvent = false;
1575 RefPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1577 // 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.
1578 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1579 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1582 // Update over/out state before passing the event to the subframe.
1583 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1585 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1586 // node to be detached from its FrameView, in which case the event should not be passed.
1587 if (newSubframe->view())
1588 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1590 if (scrollbar && !m_mousePressed)
1591 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1592 if (FrameView* view = m_frame->view()) {
1593 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey());
1594 if (optionalCursor.isCursorChange()) {
1595 m_currentMouseCursor = optionalCursor.cursor();
1596 view->setCursor(m_currentMouseCursor);
1601 m_lastMouseMoveEventSubframe = newSubframe;
1606 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.targetNode(), false, 0, mouseEvent, true);
1608 swallowEvent = handleMouseDraggedEvent(mev);
1610 return swallowEvent;
1613 void EventHandler::invalidateClick()
1616 m_clickNode = nullptr;
1619 static Node* parentForClickEvent(const Node& node)
1621 // IE doesn't dispatch click events for mousedown/mouseup events across form
1623 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1625 return node.parentOrShadowHostNode();
1628 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1630 TRACE_EVENT0("webkit", "EventHandler::handleMouseReleaseEvent");
1632 RefPtr<FrameView> protector(m_frame->view());
1634 m_frame->selection().setCaretBlinkingSuspended(false);
1636 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1637 if (defaultPrevented)
1640 OwnPtr<UserGestureIndicator> gestureIndicator;
1642 if (m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken)
1643 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1645 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1648 if (Page* page = m_frame->page())
1649 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1652 m_mousePressed = false;
1653 setLastKnownMousePosition(mouseEvent);
1657 toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1661 if (m_frameSetBeingResized)
1662 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1664 if (m_lastScrollbarUnderMouse) {
1666 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1667 bool cancelable = true;
1668 bool setUnder = false;
1669 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder);
1672 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1673 if (mouseEvent.fromTouch())
1674 hitType |= HitTestRequest::ReadOnly;
1675 HitTestRequest request(hitType);
1676 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1677 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1678 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1679 m_capturingMouseEventsNode = nullptr;
1680 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1683 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1685 bool contextMenuEvent = mouseEvent.button() == RightButton;
1687 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1688 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1689 contextMenuEvent = true;
1692 bool swallowClickEvent = false;
1693 if (m_clickCount > 0 && !contextMenuEvent && mev.targetNode() && m_clickNode) {
1694 if (Node* clickTargetNode = mev.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1695 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, true, m_clickCount, mouseEvent, true);
1698 if (m_resizeScrollableArea) {
1699 m_resizeScrollableArea->setInResizeMode(false);
1700 m_resizeScrollableArea = 0;
1703 bool swallowMouseReleaseEvent = false;
1704 if (!swallowMouseUpEvent)
1705 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1709 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1712 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1714 // If the event was a middle click, attempt to copy global selection in after
1715 // the newly set caret position.
1717 // This code is called from either the mouse up or mouse down handling. There
1718 // is some debate about when the global selection is pasted:
1719 // xterm: pastes on up.
1720 // GTK: pastes on down.
1721 // Qt: pastes on up.
1722 // Firefox: pastes on up.
1723 // Chromium: pastes on up.
1725 // There is something of a webcompat angle to this well, as highlighted by
1726 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1727 // down then the text is pasted just before the onclick handler runs and
1728 // clears the text box. So it's important this happens after the event
1729 // handlers have been fired.
1730 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1733 if (!m_frame->page())
1735 LocalFrame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1736 // Do not paste here if the focus was moved somewhere else.
1737 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1738 return m_frame->editor().command("PasteGlobalSelection").execute();
1744 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1746 FrameView* view = m_frame->view();
1748 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1752 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1753 true, true, m_frame->document()->domWindow(),
1754 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1755 event.movementDelta().x(), event.movementDelta().y(),
1756 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1757 0, nullptr, clipboard);
1759 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1760 return me->defaultPrevented();
1763 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1765 if (!isHTMLFrameElementBase(target))
1768 frame = toHTMLFrameElementBase(target)->contentFrame();
1772 static bool findDropZone(Node* target, Clipboard* clipboard)
1774 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1775 for (; element; element = element->parentElement()) {
1776 bool matched = false;
1777 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1779 if (dropZoneStr.isEmpty())
1782 dropZoneStr = dropZoneStr.lower();
1784 SpaceSplitString keywords(dropZoneStr, false);
1785 if (keywords.isNull())
1788 DragOperation dragOperation = DragOperationNone;
1789 for (unsigned i = 0; i < keywords.size(); i++) {
1790 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1791 if (op != DragOperationNone) {
1792 if (dragOperation == DragOperationNone)
1795 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1797 if (matched && dragOperation != DragOperationNone)
1801 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1808 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1810 bool accept = false;
1812 if (!m_frame->view())
1815 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1816 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1818 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1819 RefPtr<Node> newTarget = mev.targetNode();
1820 if (newTarget && newTarget->isTextNode())
1821 newTarget = NodeRenderingTraversal::parent(newTarget.get());
1823 if (AutoscrollController* controller = autoscrollController())
1824 controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1826 if (m_dragTarget != newTarget) {
1827 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1828 // it is sometimes incorrect when dragging within subframes, as seen with
1829 // LayoutTests/fast/events/drag-in-frames.html.
1831 // 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>.
1832 LocalFrame* targetFrame;
1833 if (targetIsFrame(newTarget.get(), targetFrame)) {
1835 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1836 } else if (newTarget) {
1837 // 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.
1838 if (dragState().m_dragSrc) {
1839 // for now we don't care if event handler cancels default behavior, since there is none
1840 dispatchDragSrcEvent(EventTypeNames::drag, event);
1842 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, clipboard);
1844 accept = findDropZone(newTarget.get(), clipboard);
1847 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1849 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1850 } else if (m_dragTarget)
1851 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1854 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1855 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1856 m_shouldOnlyFireDragOverEvent = true;
1859 LocalFrame* targetFrame;
1860 if (targetIsFrame(newTarget.get(), targetFrame)) {
1862 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1863 } else if (newTarget) {
1864 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1865 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1866 // for now we don't care if event handler cancels default behavior, since there is none
1867 dispatchDragSrcEvent(EventTypeNames::drag, event);
1869 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, clipboard);
1871 accept = findDropZone(newTarget.get(), clipboard);
1872 m_shouldOnlyFireDragOverEvent = false;
1875 m_dragTarget = newTarget;
1880 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1882 LocalFrame* targetFrame;
1883 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1885 targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
1886 } else if (m_dragTarget.get()) {
1887 if (dragState().m_dragSrc)
1888 dispatchDragSrcEvent(EventTypeNames::drag, event);
1889 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1894 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1896 LocalFrame* targetFrame;
1897 bool preventedDefault = false;
1898 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1900 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
1901 } else if (m_dragTarget.get())
1902 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, clipboard);
1904 return preventedDefault;
1907 void EventHandler::clearDragState()
1910 m_dragTarget = nullptr;
1911 m_capturingMouseEventsNode = nullptr;
1912 m_shouldOnlyFireDragOverEvent = false;
1915 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1917 m_capturingMouseEventsNode = n;
1918 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1921 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1924 ASSERT(m_frame->document());
1926 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1929 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1931 if (!referenceNode || !referenceNode->isSVGElement())
1934 ShadowRoot* shadowRoot = referenceNode->containingShadowRoot();
1938 Element* shadowTreeParentElement = shadowRoot->host();
1939 if (!isSVGUseElement(shadowTreeParentElement))
1942 return toSVGUseElement(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1945 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1947 Node* result = targetNode;
1949 // If we're capturing, we always go right to that node.
1950 if (m_capturingMouseEventsNode)
1951 result = m_capturingMouseEventsNode.get();
1953 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1954 if (result && result->isTextNode())
1955 result = NodeRenderingTraversal::parent(result);
1957 m_nodeUnderMouse = result;
1958 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1960 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1961 if (m_lastInstanceUnderMouse) {
1962 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1963 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1965 if (lastCorrespondingElement && lastCorrespondingUseElement) {
1966 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1968 // Locate the recloned shadow tree element for our corresponding instance
1969 HashSet<SVGElementInstance*>::iterator end = instances.end();
1970 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1971 SVGElementInstance* instance = (*it);
1972 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1974 if (instance == m_lastInstanceUnderMouse)
1977 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1980 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1981 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1984 m_lastNodeUnderMouse = shadowTreeElement;
1985 m_lastInstanceUnderMouse = instance;
1991 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1992 if (fireMouseOverOut) {
1993 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1994 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1995 Page* page = m_frame->page();
1997 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1998 // The mouse has moved between frames.
1999 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
2000 if (FrameView* frameView = frame->view())
2001 frameView->mouseExitedContentArea();
2003 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2004 // The mouse has moved between layers.
2005 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
2006 scrollableAreaForLastNode->mouseExitedContentArea();
2009 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2010 // The mouse has moved between frames.
2011 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
2012 if (FrameView* frameView = frame->view())
2013 frameView->mouseEnteredContentArea();
2015 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2016 // The mouse has moved between layers.
2017 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
2018 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
2021 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2022 m_lastNodeUnderMouse = nullptr;
2023 m_lastScrollbarUnderMouse = nullptr;
2024 m_lastInstanceUnderMouse = nullptr;
2027 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2028 // send mouseout event to the old node
2029 if (m_lastNodeUnderMouse)
2030 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
2031 // send mouseover event to the new node
2032 if (m_nodeUnderMouse)
2033 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
2035 m_lastNodeUnderMouse = m_nodeUnderMouse;
2036 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2040 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2042 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2044 bool swallowEvent = false;
2046 if (m_nodeUnderMouse)
2047 swallowEvent = !(m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount));
2049 if (swallowEvent || eventType != EventTypeNames::mousedown)
2050 return !swallowEvent;
2052 // If clicking on a frame scrollbar, do not mess up with content focus.
2053 if (FrameView* view = m_frame->view()) {
2054 if (view->scrollbarAtPoint(mouseEvent.position()))
2058 // The layout needs to be up to date to determine if an element is focusable.
2059 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2061 Element* element = 0;
2062 if (m_nodeUnderMouse)
2063 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
2064 for (; element; element = element->parentOrShadowHostElement()) {
2065 if (element->isFocusable() && element->focused())
2066 return !swallowEvent;
2067 if (element->isMouseFocusable())
2070 ASSERT(!element || element->isMouseFocusable());
2072 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
2073 // a node on mouse down if it's selected and inside a focused node. It will
2074 // be focused if the user does a mouseup over it, however, because the
2075 // mouseup will set a selection inside it, which will call
2076 // FrameSelection::setFocusedNodeIfNeeded.
2078 && m_frame->selection().isRange()
2079 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2080 && element->isDescendantOf(m_frame->document()->focusedElement()))
2083 // Only change the focus when clicking scrollbars if it can transfered to a
2084 // mouse focusable node.
2085 if (!element && isInsideScrollbar(mouseEvent.position()))
2088 if (Page* page = m_frame->page()) {
2089 // If focus shift is blocked, we eat the event. Note we should never
2090 // clear swallowEvent if the page already set it (e.g., by canceling
2091 // default behavior).
2093 if (!page->focusController().setFocusedElement(element, m_frame, FocusTypeMouse))
2094 swallowEvent = true;
2096 // We call setFocusedElement even with !element in order to blur
2097 // current focus element when a link is clicked; this is expected by
2098 // some sites that rely on onChange handlers running from form
2099 // fields before the button click is processed.
2100 if (!page->focusController().setFocusedElement(0, m_frame))
2101 swallowEvent = true;
2105 return !swallowEvent;
2108 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2110 if (RenderView* renderView = m_frame->contentRenderer()) {
2111 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2112 HitTestResult result(windowPoint);
2113 renderView->hitTest(request, result);
2114 return result.scrollbar();
2120 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result, const PlatformWheelEvent& event) const
2122 #if OS(ANDROID) || OS(MACOSX) || OS(WIN)
2125 // GTK+ must scroll horizontally if the mouse pointer is on top of the
2126 // horizontal scrollbar while scrolling with the wheel.
2127 // This code comes from gtk/EventHandlerGtk.cpp.
2128 return !event.hasPreciseScrollingDeltas() && result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar;
2132 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2134 #define RETURN_WHEEL_EVENT_HANDLED() \
2136 setFrameWasScrolledByUser(); \
2140 Document* doc = m_frame->document();
2142 if (!doc->renderer())
2145 RefPtr<FrameView> protector(m_frame->view());
2147 FrameView* view = m_frame->view();
2151 if (handleWheelEventAsEmulatedGesture(e))
2154 LayoutPoint vPoint = view->windowToContents(e.position());
2156 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2157 HitTestResult result(vPoint);
2158 doc->renderView()->hitTest(request, result);
2160 Node* node = result.innerNode();
2161 // Wheel events should not dispatch to text nodes.
2162 if (node && node->isTextNode())
2163 node = NodeRenderingTraversal::parent(node);
2166 if (e.useLatchedEventNode()) {
2167 if (!m_latchedWheelEventNode) {
2168 m_latchedWheelEventNode = node;
2169 m_widgetIsLatched = result.isOverWidget();
2171 node = m_latchedWheelEventNode.get();
2173 isOverWidget = m_widgetIsLatched;
2175 if (m_latchedWheelEventNode)
2176 m_latchedWheelEventNode = nullptr;
2177 if (m_previousWheelScrolledNode)
2178 m_previousWheelScrolledNode = nullptr;
2180 isOverWidget = result.isOverWidget();
2183 // FIXME: It should not be necessary to do this mutation here.
2184 // Instead, the handlers should know convert vertical scrolls
2186 PlatformWheelEvent event = e;
2187 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2188 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2191 // Figure out which view to send the event to.
2192 RenderObject* target = node->renderer();
2194 if (isOverWidget && target && target->isWidget()) {
2195 Widget* widget = toRenderWidget(target)->widget();
2196 if (widget && passWheelEventToWidget(e, widget))
2197 RETURN_WHEEL_EVENT_HANDLED();
2200 if (node && !node->dispatchWheelEvent(event))
2201 RETURN_WHEEL_EVENT_HANDLED();
2204 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2205 view = m_frame->view();
2206 if (!view || !view->wheelEvent(event))
2209 RETURN_WHEEL_EVENT_HANDLED();
2211 #undef RETURN_WHEEL_EVENT_HANDLED
2214 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2216 if (!startNode || !wheelEvent)
2219 // Ctrl + scrollwheel is reserved for triggering zoom in/out actions in Chromium.
2220 if (wheelEvent->ctrlKey())
2223 Node* stopNode = m_previousWheelScrolledNode.get();
2224 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2226 // Break up into two scrolls if we need to. Diagonal movement on
2227 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2228 if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation())))
2229 wheelEvent->setDefaultHandled();
2231 if (scroll(ScrollDown, granularity, startNode, &stopNode, wheelEvent->deltaY(), roundedIntPoint(wheelEvent->absoluteLocation())))
2232 wheelEvent->setDefaultHandled();
2234 if (!m_latchedWheelEventNode)
2235 m_previousWheelScrolledNode = stopNode;
2238 bool EventHandler::handleGestureShowPress()
2240 m_lastShowPressTimestamp = WTF::currentTime();
2242 FrameView* view = m_frame->view();
2245 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2246 scrollAnimator->cancelAnimations();
2247 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2250 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2251 ScrollableArea* sa = *it;
2252 ScrollAnimator* animator = sa->scrollAnimator();
2254 animator->cancelAnimations();
2259 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2261 IntPoint adjustedPoint = gestureEvent.position();
2262 RefPtr<LocalFrame> subframe = nullptr;
2263 switch (gestureEvent.type()) {
2264 case PlatformEvent::GestureScrollBegin:
2265 case PlatformEvent::GestureScrollUpdate:
2266 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2267 case PlatformEvent::GestureScrollEnd:
2268 case PlatformEvent::GestureFlingStart:
2269 // Handle directly in main frame
2272 case PlatformEvent::GestureTap:
2273 case PlatformEvent::GestureTapUnconfirmed:
2274 case PlatformEvent::GestureTapDown:
2275 case PlatformEvent::GestureShowPress:
2276 case PlatformEvent::GestureTapDownCancel:
2277 case PlatformEvent::GestureTwoFingerTap:
2278 case PlatformEvent::GestureLongPress:
2279 case PlatformEvent::GestureLongTap:
2280 case PlatformEvent::GesturePinchBegin:
2281 case PlatformEvent::GesturePinchEnd:
2282 case PlatformEvent::GesturePinchUpdate:
2283 adjustGesturePosition(gestureEvent, adjustedPoint);
2284 subframe = getSubFrameForGestureEvent(adjustedPoint, gestureEvent);
2286 return subframe->eventHandler().handleGestureEvent(gestureEvent);
2290 ASSERT_NOT_REACHED();
2293 RefPtr<Node> eventTarget;
2294 RefPtr<Scrollbar> scrollbar;
2295 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2296 || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2297 || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation
2298 || gestureEvent.type() == PlatformEvent::GestureFlingStart) {
2299 scrollbar = m_scrollbarHandlingScrollGesture.get();
2300 eventTarget = m_scrollGestureHandlingNode.get();
2303 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2304 double activeInterval = 0;
2305 bool shouldKeepActiveForMinInterval = false;
2306 if (gestureEvent.type() == PlatformEvent::GestureShowPress
2307 || gestureEvent.type() == PlatformEvent::GestureTapUnconfirmed) {
2308 hitType |= HitTestRequest::Active;
2309 } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) {
2310 hitType |= HitTestRequest::Release;
2311 // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2312 if (!m_frame->document()->activeHoverElement())
2313 hitType |= HitTestRequest::ReadOnly;
2314 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2315 hitType |= HitTestRequest::Release;
2316 // If the Tap is received very shortly after ShowPress, we want to delay clearing
2317 // of the active state so that it's visible to the user for at least one frame.
2318 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2319 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2320 if (shouldKeepActiveForMinInterval)
2321 hitType |= HitTestRequest::ReadOnly;
2324 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2326 if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2327 IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2328 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2330 if (shouldKeepActiveForMinInterval) {
2331 m_lastDeferredTapElement = result.innerElement();
2332 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval, FROM_HERE);
2335 eventTarget = result.targetNode();
2337 FrameView* view = m_frame->view();
2338 scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2341 scrollbar = result.scrollbar();
2345 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2346 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed) {
2347 m_scrollbarHandlingScrollGesture = scrollbar;
2348 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2349 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2350 || !eventSwallowed) {
2351 m_scrollbarHandlingScrollGesture = nullptr;
2359 bool eventSwallowed = false;
2360 if (handleScrollGestureOnResizer(eventTarget.get(), gestureEvent))
2361 eventSwallowed = true;
2363 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2364 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2366 m_scrollGestureHandlingNode = eventTarget;
2373 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2374 // eliminate the need for this.
2375 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2377 switch (gestureEvent.type()) {
2378 case PlatformEvent::GestureScrollBegin:
2379 return handleGestureScrollBegin(gestureEvent);
2380 case PlatformEvent::GestureScrollUpdate:
2381 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2382 return handleGestureScrollUpdate(gestureEvent);
2383 case PlatformEvent::GestureScrollEnd:
2384 return handleGestureScrollEnd(gestureEvent);
2385 case PlatformEvent::GestureTap:
2386 return handleGestureTap(gestureEvent, adjustedPoint);
2387 case PlatformEvent::GestureShowPress:
2388 return handleGestureShowPress();
2389 case PlatformEvent::GestureLongPress:
2390 return handleGestureLongPress(gestureEvent, adjustedPoint);
2391 case PlatformEvent::GestureLongTap:
2392 return handleGestureLongTap(gestureEvent, adjustedPoint);
2393 case PlatformEvent::GestureTwoFingerTap:
2394 return handleGestureTwoFingerTap(gestureEvent, adjustedPoint);
2395 case PlatformEvent::GestureTapDown:
2396 case PlatformEvent::GesturePinchBegin:
2397 case PlatformEvent::GesturePinchEnd:
2398 case PlatformEvent::GesturePinchUpdate:
2399 case PlatformEvent::GestureTapDownCancel:
2400 case PlatformEvent::GestureTapUnconfirmed:
2401 case PlatformEvent::GestureFlingStart:
2404 ASSERT_NOT_REACHED();
2410 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2412 // FIXME: Refactor this code to not hit test multiple times. We use the adjusted position to ensure that the correct node is targeted by the later redundant hit tests.
2414 unsigned modifierFlags = 0;
2415 if (gestureEvent.altKey())
2416 modifierFlags |= PlatformEvent::AltKey;
2417 if (gestureEvent.ctrlKey())
2418 modifierFlags |= PlatformEvent::CtrlKey;
2419 if (gestureEvent.metaKey())
2420 modifierFlags |= PlatformEvent::MetaKey;
2421 if (gestureEvent.shiftKey())
2422 modifierFlags |= PlatformEvent::ShiftKey;
2423 PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2425 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2426 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2427 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2428 handleMouseMoveEvent(fakeMouseMove);
2430 bool defaultPrevented = false;
2431 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2432 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2433 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2434 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2436 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2437 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2438 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2439 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2441 return defaultPrevented;
2444 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2446 m_longTapShouldInvokeContextMenu = false;
2447 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2448 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2449 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2450 m_mouseDown = mouseDownEvent;
2452 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2453 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2454 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2455 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2456 m_didStartDrag = false;
2457 m_mouseDownMayStartDrag = true;
2458 dragState().m_dragSrc = nullptr;
2459 m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2460 RefPtr<FrameView> protector(m_frame->view());
2461 handleDrag(mev, DontCheckDragHysteresis);
2462 if (m_didStartDrag) {
2463 m_longTapShouldInvokeContextMenu = true;
2468 bool shouldLongPressSelectWord = true;
2470 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2472 if (shouldLongPressSelectWord) {
2473 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2474 HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2475 Node* innerNode = result.targetNode();
2476 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2477 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2478 if (m_frame->selection().isRange()) {
2479 focusDocumentView();
2484 return sendContextMenuEventForGesture(gestureEvent);
2487 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2490 if (m_longTapShouldInvokeContextMenu) {
2491 m_longTapShouldInvokeContextMenu = false;
2492 return sendContextMenuEventForGesture(gestureEvent);
2498 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2499 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2500 RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : 0;
2501 IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2502 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2503 m_resizeScrollableArea = layer->scrollableArea();
2504 m_resizeScrollableArea->setInResizeMode(true);
2505 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2508 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2509 gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2510 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2511 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2514 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2515 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2516 m_resizeScrollableArea->setInResizeMode(false);
2517 m_resizeScrollableArea = 0;
2525 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2527 return sendContextMenuEventForGesture(gestureEvent);
2530 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2535 if (!widget->isFrameView())
2538 return toFrameView(widget)->frame().eventHandler().handleGestureEvent(gestureEvent);
2541 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2543 if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2544 Widget* widget = toRenderWidget(renderer)->widget();
2545 return widget && passGestureEventToWidget(gestureEvent, widget);
2550 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2551 RefPtr<Node> node = m_scrollGestureHandlingNode;
2552 clearGestureScrollNodes();
2555 ASSERT(node->refCount() > 0);
2556 passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2562 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2564 Document* document = m_frame->document();
2565 if (!document->renderView())
2568 FrameView* view = m_frame->view();
2572 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2573 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2574 HitTestResult result(viewPoint);
2575 document->renderView()->hitTest(request, result);
2577 m_lastHitTestResultOverWidget = result.isOverWidget();
2578 m_scrollGestureHandlingNode = result.innerNode();
2579 m_previousGestureScrolledNode = nullptr;
2581 // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2582 // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2583 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2584 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2586 if (!m_scrollGestureHandlingNode)
2589 passGestureEventToWidgetIfPossible(gestureEvent, m_scrollGestureHandlingNode->renderer());
2594 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2596 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2600 const float scaleFactor = m_frame->pageZoomFactor();
2601 delta.scale(1 / scaleFactor, 1 / scaleFactor);
2603 Node* node = m_scrollGestureHandlingNode.get();
2605 return sendScrollEventToView(gestureEvent, delta);
2607 // Ignore this event if the targeted node does not have a valid renderer.
2608 RenderObject* renderer = node->renderer();
2612 RefPtr<FrameView> protector(m_frame->view());
2615 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2617 // Try to send the event to the correct view.
2618 if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) {
2619 if(scrollShouldNotPropagate)
2620 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2625 if (scrollShouldNotPropagate)
2626 stopNode = m_previousGestureScrolledNode.get();
2628 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2629 ScrollGranularity granularity = ScrollByPixel;
2630 bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width());
2631 bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height());
2633 if (scrollShouldNotPropagate)
2634 m_previousGestureScrolledNode = stopNode;
2636 if (horizontalScroll || verticalScroll) {
2637 setFrameWasScrolledByUser();
2641 // Otherwise try to scroll the view.
2642 return sendScrollEventToView(gestureEvent, delta);
2645 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2647 FrameView* view = m_frame->view();
2651 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2652 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2653 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2654 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2655 scaledDelta.width(), scaledDelta.height(),
2656 scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2657 ScrollByPixelWheelEvent,
2658 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2659 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2661 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2663 setFrameWasScrolledByUser();
2665 return scrolledFrame;
2668 LocalFrame* EventHandler::getSubFrameForGestureEvent(const IntPoint& touchAdjustedPoint, const PlatformGestureEvent& gestureEvent)
2670 PlatformMouseEvent mouseDown(touchAdjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2671 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2672 HitTestRequest request(HitTestRequest::ReadOnly);
2673 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDown);
2674 return subframeForHitTestResult(mev);
2677 void EventHandler::clearGestureScrollNodes()
2679 m_scrollGestureHandlingNode = nullptr;
2680 m_previousGestureScrolledNode = nullptr;
2683 bool EventHandler::isScrollbarHandlingGestures() const
2685 return m_scrollbarHandlingScrollGesture.get();
2688 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2690 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2692 return !event.area().isEmpty();
2695 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2697 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2698 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2700 // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2701 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2702 // scrollbars being untouchable.
2703 if (result.scrollbar())
2706 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2707 Vector<RefPtr<Node>, 11> nodes;
2708 copyToVector(result.rectBasedTestResult(), nodes);
2710 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2711 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2712 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2713 // handle targetNode being a shadow DOM node.
2715 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2716 // FIXME: targetNode and success are only used by Internals functions. We should
2717 // instead have dedicated test methods so we only do this work in tests.
2718 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> > (nodes));
2719 if (success && targetNode)
2720 targetNode = targetNode->deprecatedShadowAncestorNode();
2724 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2726 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2727 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2729 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2730 Vector<RefPtr<Node>, 11> nodes;
2731 copyToVector(result.rectBasedTestResult(), nodes);
2733 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2734 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2737 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2739 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2740 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, touchRadius);
2742 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2743 Vector<RefPtr<Node>, 11> nodes;
2744 copyToVector(result.rectBasedTestResult(), nodes);
2746 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2747 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2750 void EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2752 if (!shouldApplyTouchAdjustment(gestureEvent))
2755 Node* targetNode = 0;
2756 switch (gestureEvent.type()) {
2757 case PlatformEvent::GestureTap:
2758 case PlatformEvent::GestureTapUnconfirmed:
2759 case PlatformEvent::GestureTapDown:
2760 case PlatformEvent::GestureShowPress:
2761 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2763 case PlatformEvent::GestureLongPress:
2764 case PlatformEvent::GestureLongTap:
2765 case PlatformEvent::GestureTwoFingerTap:
2766 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2769 // FIXME: Implement handling for other types as needed.
2770 ASSERT_NOT_REACHED();
2774 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2776 Document* doc = m_frame->document();
2777 FrameView* v = m_frame->view();
2781 // Clear mouse press state to avoid initiating a drag while context menu is up.
2782 m_mousePressed = false;
2784 LayoutPoint viewportPos = v->windowToContents(event.position());
2785 HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2786 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2788 if (!m_frame->selection().contains(viewportPos)
2790 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2791 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2792 // available for text selections. But only if we're above text.
2793 && (m_frame->selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2794 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2796 if (mev.hitTestResult().isMisspelled())
2797 selectClosestMisspellingFromMouseEvent(mev);
2798 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2799 selectClosestWordOrLinkFromMouseEvent(mev);
2802 swallowEvent = !dispatchMouseEvent(EventTypeNames::contextmenu, mev.targetNode(), true, 0, event, false);
2804 return swallowEvent;
2807 bool EventHandler::sendContextMenuEventForKey()
2809 FrameView* view = m_frame->view();
2813 Document* doc = m_frame->document();
2817 // Clear mouse press state to avoid initiating a drag while context menu is up.
2818 m_mousePressed = false;
2820 static const int kContextMenuMargin = 1;
2823 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2825 int rightAligned = 0;
2829 Element* focusedElement = doc->focusedElement();
2830 FrameSelection& selection = m_frame->selection();
2831 Position start = selection.selection().start();
2832 bool shouldTranslateToRootView = true;
2834 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2835 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2836 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2838 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2839 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2840 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2841 location = IntPoint(x, y);
2842 } else if (focusedElement) {
2843 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2846 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2847 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2849 location = IntPoint(
2850 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2851 kContextMenuMargin);
2852 shouldTranslateToRootView = false;
2855 m_frame->view()->setCursor(pointerCursor());
2857 IntPoint position = shouldTranslateToRootView ? view->contentsToRootView(location) : location;
2858 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2860 Node* targetNode = doc->focusedElement();
2864 // Use the focused node as the target for hover and active.
2865 HitTestResult result(position);
2866 result.setInnerNode(targetNode);
2867 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, result.innerElement());
2869 // The contextmenu event is a mouse event even when invoked using the keyboard.
2870 // This is required for web compatibility.
2873 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2875 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2878 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2880 handleMousePressEvent(mouseEvent);
2881 return sendContextMenuEvent(mouseEvent);
2884 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2887 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2889 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2892 IntPoint adjustedPoint = event.position();
2893 adjustGesturePosition(event, adjustedPoint);
2894 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2895 // To simulate right-click behavior, we send a right mouse down and then
2896 // context menu event.
2897 handleMousePressEvent(mouseEvent);
2898 return sendContextMenuEvent(mouseEvent);
2899 // We do not need to send a corresponding mouse release because in case of
2900 // right-click, the context menu takes capture and consumes all events.
2903 void EventHandler::scheduleHoverStateUpdate()
2905 if (!m_hoverTimer.isActive())
2906 m_hoverTimer.startOneShot(0, FROM_HERE);
2909 void EventHandler::scheduleCursorUpdate()
2911 if (!m_cursorUpdateTimer.isActive())
2912 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
2915 void EventHandler::dispatchFakeMouseMoveEventSoon()
2920 if (m_mousePositionIsUnknown)
2923 Settings* settings = m_frame->settings();
2924 if (settings && !settings->deviceSupportsMouse())
2927 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2928 // reschedule the timer and use a longer time. This will cause the content
2929 // to receive these moves only after the user is done scrolling, reducing
2930 // pauses during the scroll.
2931 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2932 if (m_fakeMouseMoveEventTimer.isActive())
2933 m_fakeMouseMoveEventTimer.stop();
2934 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_HERE);
2936 if (!m_fakeMouseMoveEventTimer.isActive())
2937 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, FROM_HERE);
2941 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2943 FrameView* view = m_frame->view();
2947 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2950 dispatchFakeMouseMoveEventSoon();
2953 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2955 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2956 ASSERT(!m_mousePressed);
2958 Settings* settings = m_frame->settings();
2959 if (settings && !settings->deviceSupportsMouse())
2962 FrameView* view = m_frame->view();
2966 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2969 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2970 if (!isCursorVisible())
2977 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2978 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2979 handleMouseMoveEvent(fakeMouseMoveEvent);
2982 void EventHandler::cancelFakeMouseMoveEvent()
2984 m_fakeMouseMoveEventTimer.stop();
2987 bool EventHandler::isCursorVisible() const
2989 return m_frame->page()->isCursorVisible();
2992 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2994 m_frameSetBeingResized = frameSet;
2997 void EventHandler::resizeScrollableAreaDestroyed()
2999 ASSERT(m_resizeScrollableArea);
3000 m_resizeScrollableArea = 0;
3003 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
3005 m_hoverTimer.stop();
3008 ASSERT(m_frame->document());
3010 if (RenderView* renderer = m_frame->contentRenderer()) {
3011 if (FrameView* view = m_frame->view()) {
3012 HitTestRequest request(HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3013 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
3014 renderer->hitTest(request, result);
3015 m_frame->document()->updateHoverActiveState(request, result.innerElement());
3020 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
3022 m_activeIntervalTimer.stop();
3025 && m_frame->document()
3026 && m_lastDeferredTapElement) {
3027 // FIXME: Enable condition when http://crbug.com/226842 lands
3028 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
3029 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
3030 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
3032 m_lastDeferredTapElement = nullptr;
3035 void EventHandler::notifyElementActivated()
3037 // Since another element has been set to active, stop current timer and clear reference.
3038 if (m_activeIntervalTimer.isActive())
3039 m_activeIntervalTimer.stop();
3040 m_lastDeferredTapElement = nullptr;
3043 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
3045 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3046 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3047 // lower case variants are present in a document, the correct element is matched based on Shift key state.
3048 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3049 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
3050 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
3052 String key = evt.unmodifiedText();
3053 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
3056 elem->accessKeyAction(false);
3060 bool EventHandler::isKeyEventAllowedInFullScreen(FullscreenElementStack* fullscreen, const PlatformKeyboardEvent& keyEvent) const
3062 if (fullscreen->webkitFullScreenKeyboardInputAllowed())
3065 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3066 if (keyEvent.text().length() != 1)
3068 UChar character = keyEvent.text()[0];
3069 return character == ' ';
3072 int keyCode = keyEvent.windowsVirtualKeyCode();
3073 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3074 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3075 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3076 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3079 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3081 RefPtr<FrameView> protector(m_frame->view());
3083 ASSERT(m_frame->document());
3084 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(*m_frame->document())) {
3085 if (fullscreen->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent))
3089 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3090 capsLockStateMayHaveChanged();
3093 if (panScrollInProgress()) {
3094 // If a key is pressed while the panScroll is in progress then we want to stop
3095 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3098 // If we were in panscroll mode, we swallow the key event
3103 // Check for cases where we are too early for events -- possible unmatched key up
3104 // from pressing return in the location bar.
3105 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
3109 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3111 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3112 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3113 // with access keys. Then we dispatch keydown, but suppress its default handling.
3114 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3115 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3116 bool matchedAnAccessKey = false;
3117 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3118 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3120 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3121 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3122 return !node->dispatchKeyEvent(initialKeyEvent);
3124 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3125 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3126 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
3127 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
3128 if (matchedAnAccessKey)
3129 keydown->setDefaultPrevented(true);
3130 keydown->setTarget(node);
3132 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3133 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3134 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3135 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3136 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3139 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3140 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3141 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3142 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3144 return keydownResult;
3146 // Focus may have changed during keydown handling, so refetch node.
3147 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3148 node = eventTargetNodeForDocument(m_frame->document());
3152 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3153 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
3154 if (keyPressEvent.text().isEmpty())
3155 return keydownResult;
3156 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
3157 keypress->setTarget(node);
3159 keypress->setDefaultPrevented(true);
3160 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
3162 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3165 static FocusType focusDirectionForKey(const AtomicString& keyIdentifier)
3167 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3168 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3169 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3170 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3172 FocusType retVal = FocusTypeNone;
3174 if (keyIdentifier == Down)
3175 retVal = FocusTypeDown;
3176 else if (keyIdentifier == Up)
3177 retVal = FocusTypeUp;
3178 else if (keyIdentifier == Left)
3179 retVal = FocusTypeLeft;
3180 else if (keyIdentifier == Right)
3181 retVal = FocusTypeRight;
3186 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3188 if (event->type() == EventTypeNames::keydown) {
3189 m_frame->editor().handleKeyboardEvent(event);
3190 if (event->defaultHandled())
3192 if (event->keyIdentifier() == "U+0009")
3193 defaultTabEventHandler(event);
3194 else if (event->keyIdentifier() == "U+0008")
3195 defaultBackspaceEventHandler(event);
3196 else if (event->keyIdentifier() == "U+001B")
3197 defaultEscapeEventHandler(event);
3199 FocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
3200 if (type != FocusTypeNone)
3201 defaultArrowEventHandler(type, event);
3204 if (event->type() == EventTypeNames::keypress) {
3205 m_frame->editor().handleKeyboardEvent(event);
3206 if (event->defaultHandled())
3208 if (event->charCode() == ' ')
3209 defaultSpaceEventHandler(event);
3213 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3215 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3216 return dragHysteresisExceeded(dragViewportLocation);
3219 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3221 FrameView* view = m_frame->view();
3224 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3225 IntSize delta = dragLocation - m_mouseDownPos;
3227 int threshold = GeneralDragHysteresis;
3228 switch (dragState().m_dragType) {
3229 case DragSourceActionSelection:
3230 threshold = TextDragHysteresis;
3232 case DragSourceActionImage:
3233 threshold = ImageDragHysteresis;
3235 case DragSourceActionLink:
3236 threshold = LinkDragHysteresis;
3238 case DragSourceActionDHTML:
3240 case DragSourceActionNone:
3241 ASSERT_NOT_REACHED();
3244 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3247 void EventHandler::freeClipboard()
3249 if (dragState().m_dragClipboard)
3250 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3253 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3255 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3256 HitTestRequest request(HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3257 prepareMouseEvent(request, event);
3259 if (dragState().m_dragSrc) {
3260 dragState().m_dragClipboard->setDestinationOperation(operation);
3261 // for now we don't care if event handler cancels default behavior, since there is none
3262 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3265 dragState().m_dragSrc = nullptr;
3266 // In case the drag was ended due to an escape key press we need to ensure
3267 // that consecutive mousemove events don't reinitiate the drag and drop.
3268 m_mouseDownMayStartDrag = false;
3271 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3273 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3274 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3275 dragState().m_dragSrc = rootEditableElement;
3278 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3279 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3281 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3284 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3286 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3287 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3288 // events, causing page/FrameView to go away.
3290 ASSERT(m_frame->view());
3291 if (!m_frame->page())
3294 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3295 // If we allowed the other side of the bridge to handle a drag
3296 // last time, then m_mousePressed might still be set. So we
3297 // clear it now to make sure the next move after a drag
3298 // doesn't look like a drag.
3299 m_mousePressed = false;
3303 if (m_mouseDownMayStartDrag) {
3304 HitTestRequest request(HitTestRequest::ReadOnly);
3305 HitTestResult result(m_mouseDownPos);
3306 m_frame->contentRenderer()->hitTest(request, result);
3307 Node* node = result.innerNode();
3309 DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3310 ? DragController::DelayedSelectionDragResolution
3311 : DragController::ImmediateSelectionDragResolution;
3312 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3314 dragState().m_dragSrc = nullptr;
3317 if (!dragState().m_dragSrc)
3318 m_mouseDownMayStartDrag = false; // no element is draggable
3321 if (!m_mouseDownMayStartDrag)
3322 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3324 // We are starting a text/image/url drag, so the cursor should be an arrow
3325 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3326 m_frame->view()->setCursor(pointerCursor());
3328 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3331 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3334 if (!tryStartDrag(event)) {
3335 // Something failed to start the drag, clean up.
3337 dragState().m_dragSrc = nullptr;
3340 m_mouseDownMayStartDrag = false;
3341 // Whether or not the drag actually started, no more default handling (like selection).
3345 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3347 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3348 // to make sure it gets numbified
3349 dragState().m_dragClipboard = createDraggingClipboard();
3351 // Check to see if this a DOM based drag, if it is get the DOM specified drag
3353 if (dragState().m_dragType == DragSourceActionDHTML) {
3354 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3355 // FIXME: This doesn't work correctly with transforms.
3356 FloatPoint absPos = renderer->localToAbsolute();
3357 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3358 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3360 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3361 // the element in some way. In this case we just kill the drag.
3366 DragController& dragController = m_frame->page()->dragController();
3367 if (!dragController.populateDragClipboard(m_frame, dragState(), m_mouseDownPos))
3369 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3370 && !m_frame->selection().isInPasswordField();
3372 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3373 // image can still be changed as we drag, but not the pasteboard data.
3374 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3376 if (m_mouseDownMayStartDrag) {
3377 // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3378 m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3379 // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3380 // whether or not the drag started, but perhaps it can simply use the return value from
3381 // handleDrag(), even though it doesn't mean exactly the same thing.
3384 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3385 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3391 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3393 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3394 // and avoid dispatching text input events from keydown default handlers.
3395 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3400 EventTarget* target;
3401 if (underlyingEvent)
3402 target = underlyingEvent->target();
3404 target = eventTargetNodeForDocument(m_frame->document());
3408 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3409 event->setUnderlyingEvent(underlyingEvent);
3411 target->dispatchEvent(event, IGNORE_EXCEPTION);
3412 return event->defaultHandled();
3415 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3417 if (m_frame->editor().handleTextEvent(event))
3418 event->setDefaultHandled();
3421 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3423 ASSERT(event->type() == EventTypeNames::keypress);
3425 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3428 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3429 if (scroll(direction, ScrollByPage)) {
3430 event->setDefaultHandled();
3434 FrameView* view = m_frame->view();
3438 if (view->scroll(direction, ScrollByPage))
3439 event->setDefaultHandled();
3442 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3444 ASSERT(event->type() == EventTypeNames::keydown);
3446 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3449 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3452 Page* page = m_frame->page();
3455 bool handledEvent = page->mainFrame()->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3457 event->setDefaultHandled();
3460 void EventHandler::defaultArrowEventHandler(FocusType focusType, KeyboardEvent* event)
3462 ASSERT(event->type() == EventTypeNames::keydown);
3464 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3467 Page* page = m_frame->page();
3471 if (!isSpatialNavigationEnabled(m_frame))
3474 // Arrows and other possible directional navigation keys can be used in design
3476 if (m_frame->document()->inDesignMode())
3479 if (page->focusController().advanceFocus(focusType))
3480 event->setDefaultHandled();
3483 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3485 ASSERT(event->type() == EventTypeNames::keydown);
3487 // We should only advance focus on tabs if no special modifier keys are held down.
3488 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3491 Page* page = m_frame->page();
3494 if (!page->tabKeyCyclesThroughElements())
3497 FocusType focusType = event->shiftKey() ? FocusTypeBackward : FocusTypeForward;
3499 // Tabs can be used in design mode editing.
3500 if (m_frame->document()->inDesignMode())
3503 if (page->focusController().advanceFocus(focusType))
3504 event->setDefaultHandled();
3507 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3509 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3510 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3513 void EventHandler::capsLockStateMayHaveChanged()
3515 if (Element* element = m_frame->document()->focusedElement()) {
3516 if (RenderObject* r = element->renderer()) {
3517 if (r->isTextField())
3518 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3523 void EventHandler::setFrameWasScrolledByUser()
3525 if (FrameView* view = m_frame->view())
3526 view->setWasScrolledByUser(true);
3529 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3531 if (!scrollbar || !scrollbar->enabled())
3533 setFrameWasScrolledByUser();
3534 scrollbar->mouseDown(mev.event());
3538 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3539 // last to scrollbar if setLast is true; else set last to 0.
3540 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3542 if (m_lastScrollbarUnderMouse != scrollbar) {
3543 // Send mouse exited to the old scrollbar.
3544 if (m_lastScrollbarUnderMouse)
3545 m_lastScrollbarUnderMouse->mouseExited();
3547 // Send mouse entered if we're setting a new scrollbar.
3548 if (scrollbar && setLast)
3549 scrollbar->mouseEntered();
3551 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3555 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3558 case PlatformTouchPoint::TouchReleased:
3559 return EventTypeNames::touchend;
3560 case PlatformTouchPoint::TouchCancelled:
3561 return EventTypeNames::touchcancel;
3562 case PlatformTouchPoint::TouchPressed:
3563 return EventTypeNames::touchstart;
3564 case PlatformTouchPoint::TouchMoved:
3565 return EventTypeNames::touchmove;
3566 case PlatformTouchPoint::TouchStationary:
3567 // TouchStationary state is not converted to touch events, so fall through to assert.
3569 ASSERT_NOT_REACHED();
3574 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3576 HitTestResult result(point);
3578 if (!frame || !frame->contentRenderer())
3580 if (frame->view()) {
3581 IntRect rect = frame->view()->visibleContentRect();
3582 if (!rect.contains(roundedIntPoint(point)))
3585 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3589 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3591 TRACE_EVENT0("webkit", "EventHandler::handleTouchEvent");
3593 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3594 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3595 // for an overview of how these lists fit together.
3597 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3598 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3600 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3601 // 'targetTouches' list in the JS event.
3602 typedef WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList> > TargetTouchesHeapMap;
3603 TargetTouchesHeapMap touchesByTarget;
3605 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3606 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3608 // The touches corresponding to the particular change state this struct instance represents.
3609 RefPtrWillBeMember<TouchList> m_touches;
3610 // Set of targets involved in m_touches.
3611 EventTargetSet m_targets;
3612 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3614 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3616 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3619 bool freshTouchEvents = true;
3620 bool allTouchReleased = true;
3621 for (i = 0; i < points.size(); ++i) {
3622 const PlatformTouchPoint& point = points[i];
3623 if (point.state() != PlatformTouchPoint::TouchPressed)
3624 freshTouchEvents = false;
3625 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3626 allTouchReleased = false;
3629 for (i = 0; i < points.size(); ++i) {
3630 const PlatformTouchPoint& point = points[i];
3631 PlatformTouchPoint::State pointState = point.state();
3632 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3634 // Gesture events trigger the active state, not touch events,
3635 // so touch event hit tests can always be read only.
3636 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly;
3637 // The HitTestRequest types used for mouse events map quite adequately
3638 // to touch events. Note that in addition to meaning that the hit test
3639 // should affect the active state of the current node if necessary,
3640 // HitTestRequest::Active signifies that the hit test is taking place
3641 // with the mouse (or finger in this case) being pressed.
3642 switch (pointState) {
3643 case PlatformTouchPoint::TouchPressed:
3644 hitType |= HitTestRequest::Active;
3646 case PlatformTouchPoint::TouchMoved:
3647 hitType |= HitTestRequest::Active | HitTestRequest::Move;
3649 case PlatformTouchPoint::TouchReleased:
3650 case PlatformTouchPoint::TouchCancelled:
3651 hitType |= HitTestRequest::Release;
3653 case PlatformTouchPoint::TouchStationary:
3654 hitType |= HitTestRequest::Active;
3657 ASSERT_NOT_REACHED();
3661 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3662 unsigned touchPointTargetKey = point.id() + 1;
3663 RefPtr<EventTarget> touchTarget;
3664 if (pointState == PlatformTouchPoint::TouchPressed) {
3665 HitTestResult result;
3666 if (freshTouchEvents) {
3667 result = hitTestResultAtPoint(pagePoint, hitType);
3668 m_originatingTouchPointTargetKey = touchPointTargetKey;
3669 } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) {
3670 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(m_originatingTouchPointDocument->frame(), point.pos());
3671 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType);
3675 Node* node = result.innerNode();
3679 // Touch events should not go to text nodes
3680 if (node->isTextNode())
3681 node = NodeRenderingTraversal::parent(node);
3683 Document& doc = node->document();
3684 // Record the originating touch document even if it does not have a touch listener.
3685 if (freshTouchEvents) {
3686 m_originatingTouchPointDocument = &doc;
3687 freshTouchEvents = false;
3689 if (!doc.hasTouchEventHandlers())
3691 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3694 TouchAction effectiveTouchAction = computeEffectiveTouchAction(pagePoint);
3695 if (effectiveTouchAction != TouchActionAuto)
3696 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3698 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3699 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3700 // we also remove it from the map.
3701 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3703 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3704 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3706 if (!touchTarget.get())
3708 Document& doc = touchTarget->toNode()->document();
3709 if (!doc.hasTouchEventHandlers())
3711 LocalFrame* targetFrame = doc.frame();
3715 if (m_frame != targetFrame) {
3716 // pagePoint should always be relative to the target elements containing frame.
3717 pagePoint = documentPointForWindowPoint(targetFrame, point.pos());
3720 float scaleFactor = targetFrame->pageZoomFactor();
3722 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3723 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3724 int adjustedRadiusX = lroundf(point.radiusX() / scaleFactor);
3725 int adjustedRadiusY = lroundf(point.radiusY() / scaleFactor);
3727 RefPtrWillBeRawPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3728 point.screenPos().x(), point.screenPos().y(),
3729 adjustedPageX, adjustedPageY,
3730 adjustedRadiusX, adjustedRadiusY,
3731 point.rotationAngle(), point.force());
3733 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3734 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3735 if (targetTouchesIterator == touchesByTarget.end()) {
3736 touchesByTarget.set(touchTarget.get(), TouchList::create());
3737 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3740 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3741 // released or cancelled it will only appear in the changedTouches list.
3742 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3743 touches->append(touch);
3744 targetTouchesIterator->value->append(touch);
3747 // Now build up the correct list for changedTouches.
3748 // Note that any touches that are in the TouchStationary state (e.g. if
3749 // the user had several points touched but did not move them all) should
3750 // never be in the changedTouches list so we do not handle them explicitly here.
3751 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3752 // about the TouchStationary state.
3753 if (pointState != PlatformTouchPoint::TouchStationary) {
3754 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3755 if (!changedTouches[pointState].m_touches)
3756 changedTouches[pointState].m_touches = TouchList::create();
3757 changedTouches[pointState].m_touches->append(touch);
3758 changedTouches[pointState].m_targets.add(touchTarget);
3761 m_touchPressed = touches->length() > 0;
3762 if (allTouchReleased)
3763 m_originatingTouchPointDocument.clear();
3765 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3766 bool swallowedEvent = false;
3767 RefPtrWillBeRawPtr<TouchList> emptyList = TouchList::create();
3768 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3769 if (!changedTouches[state].m_touches)
3772 // When sending a touch cancel event, use empty touches and targetTouches lists.
3773 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3774 RefPtrWillBeRawPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3775 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3776 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3778 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3779 EventTarget* touchEventTarget = it->get();
3780 RefPtrWillBeRawPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList.get() : touchesByTarget.get(touchEventTarget));
3781 ASSERT(targetTouches);
3783 RefPtr<TouchEvent> touchEvent =
3784 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3785 stateName, touchEventTarget->toNode()->document().domWindow(),
3786 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3787 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3788 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3792 return swallowedEvent;
3795 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
3797 if (!m_frame || !m_frame->settings() || !m_frame->settings()->touchEventEmulationEnabled())
3800 PlatformEvent::Type eventType = event.type();
3801 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
3804 HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3805 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
3806 if (mev.scrollbar() || subframeForHitTestResult(mev))
3809 // The order is important. This check should follow the subframe test: http://webkit.org/b/111292.
3810 if (eventType == PlatformEvent::MouseMoved && event.button() == NoButton)
3813 SyntheticSingleTouchEvent touchEvent(event);
3814 if (handleTouchEvent(touchEvent))
3817 return handleMouseEventAsEmulatedGesture(event);
3820 bool EventHandler::handleMouseEventAsEmulatedGesture(const PlatformMouseEvent& event)
3822 PlatformEvent::Type eventType = event.type();
3823 if (event.button() != LeftButton || !m_frame->isMainFrame())
3826 // Simulate pinch / scroll gesture.
3827 const IntPoint& position = event.position();
3828 bool swallowEvent = false;
3830 FrameView* view = m_frame->view();
3831 if (event.shiftKey()) {
3832 // Shift pressed - consider it gesture.
3833 swallowEvent = true;
3834 Page* page = m_frame->page();
3835 float pageScaleFactor = page->pageScaleFactor();
3836 switch (eventType) {
3837 case PlatformEvent::MousePressed:
3838 m_lastSyntheticPinchAnchorCss = adoptPtr(new IntPoint(view->scrollPosition() + position));
3839 m_lastSyntheticPinchAnchorDip = adoptPtr(new IntPoint(position));
3840 m_lastSyntheticPinchAnchorDip->scale(pageScaleFactor, pageScaleFactor);
3841 m_syntheticPageScaleFactor = pageScaleFactor;
3843 case PlatformEvent::MouseMoved:
3845 if (!m_lastSyntheticPinchAnchorCss)
3848 float dy = m_lastSyntheticPinchAnchorDip->y() - position.y() * pageScaleFactor;
3849 float magnifyDelta = exp(dy * 0.002f);
3850 float newPageScaleFactor = m_syntheticPageScaleFactor * magnifyDelta;
3852 IntPoint anchorCss(*m_lastSyntheticPinchAnchorDip.get());
3853 anchorCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor);
3854 page->inspectorController().requestPageScaleFactor(newPageScaleFactor, *m_lastSyntheticPinchAnchorCss.get() - toIntSize(anchorCss));
3857 case PlatformEvent::MouseReleased:
3858 m_lastSyntheticPinchAnchorCss.clear();
3859 m_lastSyntheticPinchAnchorDip.clear();
3864 switch (eventType) {
3865 case PlatformEvent::MouseMoved:
3867 // Always consume move events.
3868 swallowEvent = true;
3869 int dx = m_lastSyntheticPanLocation ? position.x() - m_lastSyntheticPanLocation->x() : 0;
3870 int dy = m_lastSyntheticPanLocation ? position.y() - m_lastSyntheticPanLocation->y() : 0;
3872 view->scrollBy(IntSize(-dx, -dy));
3873 // Mouse dragged - consider it gesture.
3874 m_lastSyntheticPanLocation = adoptPtr(new IntPoint(position));
3877 case PlatformEvent::MouseReleased:
3878 // There was a drag -> gesture.
3879 swallowEvent = !!m_lastSyntheticPanLocation;
3880 m_lastSyntheticPanLocation.clear();
3886 return swallowEvent;
3889 bool EventHandler::handleWheelEventAsEmulatedGesture(const PlatformWheelEvent& event)
3891 if (!m_frame || !m_frame->settings() || !m_frame->settings()->touchEventEmulationEnabled())
3894 // Only convert vertical wheel w/ shift into pinch for touch-enabled device convenience.
3895 if (!event.shiftKey() || !event.deltaY())
3898 Page* page = m_frame->page();
3899 FrameView* view = m_frame->view();
3900 float pageScaleFactor = page->pageScaleFactor();
3901 IntPoint anchorBeforeCss(view->scrollPosition() + event.position());
3902 IntPoint anchorBeforeDip(event.position());
3903 anchorBeforeDip.scale(pageScaleFactor, pageScaleFactor);
3905 float magnifyDelta = exp(event.deltaY() * 0.002f);
3906 float newPageScaleFactor = pageScaleFactor * magnifyDelta;
3908 IntPoint anchorAfterCss(anchorBeforeDip);
3909 anchorAfterCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor);
3910 page->inspectorController().requestPageScaleFactor(newPageScaleFactor, anchorBeforeCss - toIntSize(anchorAfterCss));
3914 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
3916 if (action1 == TouchActionNone || action2 == TouchActionNone)
3917 return TouchActionNone;
3918 if (action1 == TouchActionAuto)
3920 if (action2 == TouchActionAuto)
3922 if (!(action1 & action2))
3923 return TouchActionNone;
3924 return action1 & action2;
3927 TouchAction EventHandler::computeEffectiveTouchAction(const LayoutPoint& point)
3929 // Optimization to minimize risk of this new feature (behavior should be identical
3930 // since there's no way to get non-default touch-action values).
3931 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
3932 return TouchActionAuto;
3934 HitTestResult taResult = hitTestResultAtPoint(point, HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::TouchAction);
3935 Node* node = taResult.innerNode();
3937 return TouchActionAuto;
3939 // Start by permitting all actions, then walk the block level elements from
3940 // the target node up to the nearest scrollable ancestor and exclude any
3941 // prohibited actions. For now this is trivial, but when we add more types
3942 // of actions it'll get a little more complex.
3943 TouchAction effectiveTouchAction = TouchActionAuto;
3944 for (const Node* curNode = node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3945 // The spec says only block and SVG elements get touch-action.
3946 // FIXME(rbyers): Add correct support for SVG, crbug.com/247396.
3947 if (RenderObject* renderer = curNode->renderer()) {
3948 if (renderer->isRenderBlockFlow()) {
3949 TouchAction action = renderer->style()->touchAction();
3950 effectiveTouchAction = intersectTouchAction(action, effectiveTouchAction);
3951 if (effectiveTouchAction == TouchActionNone)
3955 // If we've reached an ancestor that supports a touch action, search no further.
3956 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3960 return effectiveTouchAction;
3963 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3965 m_mousePositionIsUnknown = false;
3966 m_lastKnownMousePosition = event.position();
3967 m_lastKnownMouseGlobalPosition = event.globalPosition();
3970 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3972 // If we're clicking into a frame that is selected, the frame will appear
3973 // greyed out even though we're clicking on the selection. This looks
3974 // really strange (having the whole frame be greyed out), so we deselect the
3976 IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3977 if (m_frame->selection().contains(p)) {
3978 VisiblePosition visiblePos(
3979 mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
3980 VisibleSelection newSelection(visiblePos);
3981 m_frame->selection().setSelection(newSelection);
3984 subframe->eventHandler().handleMousePressEvent(mev.event());
3988 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe, HitTestResult* hoveredNode)
3990 if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
3992 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3996 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3998 subframe->eventHandler().handleMouseReleaseEvent(mev.event());
4002 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
4004 // We can sometimes get a null widget! EventHandlerMac handles a null
4005 // widget by returning false, so we do the same.
4009 // If not a FrameView, then probably a plugin widget. Those will receive
4010 // the event via an EventTargetNode dispatch when this returns false.
4011 if (!widget->isFrameView())
4014 return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
4017 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
4019 // Figure out which view to send the event to.
4020 if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
4025 PassRefPtrWillBeRawPtr<Clipboard> EventHandler::createDraggingClipboard() const
4027 return Clipboard::create(Clipboard::DragAndDrop, ClipboardWritable, DataObject::create());
4030 void EventHandler::focusDocumentView()
4032 Page* page = m_frame->page();
4035 page->focusController().setFocusedFrame(m_frame);
4038 unsigned EventHandler::accessKeyModifiers()
4041 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
4043 return PlatformEvent::AltKey;
4047 } // namespace WebCore