2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "core/page/EventHandler.h"
31 #include "bindings/v8/ExceptionStatePlaceholder.h"
32 #include "core/HTMLNames.h"
33 #include "core/SVGNames.h"
34 #include "core/clipboard/Clipboard.h"
35 #include "core/clipboard/DataObject.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/DocumentMarkerController.h"
38 #include "core/dom/FullscreenElementStack.h"
39 #include "core/dom/NodeRenderingTraversal.h"
40 #include "core/dom/TouchList.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/editing/Editor.h"
43 #include "core/editing/FrameSelection.h"
44 #include "core/editing/TextIterator.h"
45 #include "core/editing/htmlediting.h"
46 #include "core/events/DOMWindowEventQueue.h"
47 #include "core/events/EventPath.h"
48 #include "core/events/KeyboardEvent.h"
49 #include "core/events/MouseEvent.h"
50 #include "core/events/TextEvent.h"
51 #include "core/events/TouchEvent.h"
52 #include "core/events/WheelEvent.h"
53 #include "core/fetch/ImageResource.h"
54 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h"
56 #include "core/html/HTMLDialogElement.h"
57 #include "core/html/HTMLFrameElementBase.h"
58 #include "core/html/HTMLFrameSetElement.h"
59 #include "core/html/HTMLInputElement.h"
60 #include "core/loader/FrameLoader.h"
61 #include "core/loader/FrameLoaderClient.h"
62 #include "core/page/AutoscrollController.h"
63 #include "core/page/BackForwardClient.h"
64 #include "core/page/Chrome.h"
65 #include "core/page/ChromeClient.h"
66 #include "core/page/DragController.h"
67 #include "core/page/DragState.h"
68 #include "core/page/EditorClient.h"
69 #include "core/page/FocusController.h"
70 #include "core/page/FrameTree.h"
71 #include "core/inspector/InspectorController.h"
72 #include "core/page/MouseEventWithHitTestResults.h"
73 #include "core/page/Page.h"
74 #include "core/frame/Settings.h"
75 #include "core/page/SpatialNavigation.h"
76 #include "core/page/TouchAdjustment.h"
77 #include "core/rendering/HitTestRequest.h"
78 #include "core/rendering/HitTestResult.h"
79 #include "core/rendering/RenderFlowThread.h"
80 #include "core/rendering/RenderLayer.h"
81 #include "core/rendering/RenderTextControlSingleLine.h"
82 #include "core/rendering/RenderView.h"
83 #include "core/rendering/RenderWidget.h"
84 #include "core/rendering/style/RenderStyle.h"
85 #include "core/svg/SVGDocumentExtensions.h"
86 #include "platform/PlatformGestureEvent.h"
87 #include "platform/PlatformKeyboardEvent.h"
88 #include "platform/PlatformTouchEvent.h"
89 #include "platform/PlatformWheelEvent.h"
90 #include "platform/RuntimeEnabledFeatures.h"
91 #include "platform/TraceEvent.h"
92 #include "platform/WindowsKeyboardCodes.h"
93 #include "platform/geometry/FloatPoint.h"
94 #include "platform/graphics/Image.h"
95 #include "platform/heap/Handle.h"
96 #include "platform/scroll/ScrollAnimator.h"
97 #include "platform/scroll/Scrollbar.h"
98 #include "wtf/Assertions.h"
99 #include "wtf/CurrentTime.h"
100 #include "wtf/StdLibExtras.h"
101 #include "wtf/TemporaryChange.h"
105 using namespace HTMLNames;
107 // The link drag hysteresis is much larger than the others because there
108 // needs to be enough space to cancel the link press without starting a link drag,
109 // and because dragging links is rare.
110 static const int LinkDragHysteresis = 40;
111 static const int ImageDragHysteresis = 5;
112 static const int TextDragHysteresis = 3;
113 static const int GeneralDragHysteresis = 3;
115 // The amount of time to wait before sending a fake mouse event, triggered
116 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
117 // otherwise the long interval is used.
118 static const double fakeMouseMoveShortInterval = 0.1;
119 static const double fakeMouseMoveLongInterval = 0.250;
121 // The amount of time to wait for a cursor update on style and layout changes
122 // Set to 50Hz, no need to be faster than common screen refresh rate
123 static const double cursorUpdateInterval = 0.02;
125 static const int maximumCursorSize = 128;
127 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
128 // need to ensure here is that the scale isn't so small that integer overflow can occur when
129 // dividing cursor sizes (limited above) by the scale.
130 static const double minimumCursorScale = 0.001;
132 // The minimum amount of time an element stays active after a ShowPress
133 // This is roughly 9 frames, which should be long enough to be noticeable.
134 static const double minimumActiveInterval = 0.15;
137 static const double TextDragDelay = 0.15;
139 static const double TextDragDelay = 0.0;
142 enum NoCursorChangeType { NoCursorChange };
144 class OptionalCursor {
146 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
147 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
149 bool isCursorChange() const { return m_isCursorChange; }
150 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
153 bool m_isCursorChange;
157 class MaximumDurationTracker {
159 explicit MaximumDurationTracker(double *maxDuration)
160 : m_maxDuration(maxDuration)
161 , m_start(monotonicallyIncreasingTime())
165 ~MaximumDurationTracker()
167 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
171 double* m_maxDuration;
175 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
178 case WheelEvent::DOM_DELTA_PAGE:
180 case WheelEvent::DOM_DELTA_LINE:
182 case WheelEvent::DOM_DELTA_PIXEL:
183 return ScrollByPixel;
185 return ScrollByPixel;
189 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
190 // If a mouse event handler changes the input element type to one that has a widget associated,
191 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
192 // event target node can't still be the shadow node.
193 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
195 Node* targetNode = mev.targetNode();
196 if (!targetNode || !targetNode->parentNode())
198 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host());
201 EventHandler::EventHandler(LocalFrame* frame)
203 , m_mousePressed(false)
204 , m_capturesDragging(false)
205 , m_mouseDownMayStartSelect(false)
206 , m_mouseDownMayStartDrag(false)
207 , m_mouseDownWasSingleClickInSelection(false)
208 , m_selectionInitiationState(HaveNotStartedSelection)
209 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
210 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
211 , m_mouseDownMayStartAutoscroll(false)
212 , m_mouseDownWasInSubframe(false)
213 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
215 , m_resizeScrollableArea(0)
216 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
218 , m_shouldOnlyFireDragOverEvent(false)
219 , m_mousePositionIsUnknown(true)
220 , m_mouseDownTimestamp(0)
221 , m_widgetIsLatched(false)
222 , m_touchPressed(false)
223 , m_scrollGestureHandlingNode(nullptr)
224 , m_lastHitTestResultOverWidget(false)
225 , m_maxMouseMovedDuration(0)
226 , m_baseEventType(PlatformEvent::NoType)
227 , m_didStartDrag(false)
228 , m_longTapShouldInvokeContextMenu(false)
229 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
230 , m_lastShowPressTimestamp(0)
234 EventHandler::~EventHandler()
236 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
239 void EventHandler::trace(Visitor* visitor)
241 visitor->trace(m_mousePressNode);
242 visitor->trace(m_capturingMouseEventsNode);
243 visitor->trace(m_nodeUnderMouse);
244 visitor->trace(m_lastNodeUnderMouse);
245 visitor->trace(m_clickNode);
246 visitor->trace(m_dragTarget);
247 visitor->trace(m_frameSetBeingResized);
248 visitor->trace(m_latchedWheelEventNode);
249 visitor->trace(m_previousWheelScrolledNode);
250 visitor->trace(m_targetForTouchID);
251 visitor->trace(m_touchSequenceDocument);
252 visitor->trace(m_scrollGestureHandlingNode);
253 visitor->trace(m_previousGestureScrolledNode);
254 visitor->trace(m_lastDeferredTapElement);
257 DragState& EventHandler::dragState()
260 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState()));
263 DEFINE_STATIC_LOCAL(DragState, state, ());
268 void EventHandler::clear()
271 m_cursorUpdateTimer.stop();
272 m_fakeMouseMoveEventTimer.stop();
273 m_activeIntervalTimer.stop();
274 m_resizeScrollableArea = 0;
275 m_nodeUnderMouse = nullptr;
276 m_lastNodeUnderMouse = nullptr;
277 m_lastMouseMoveEventSubframe = nullptr;
278 m_lastScrollbarUnderMouse = nullptr;
280 m_clickNode = nullptr;
281 m_frameSetBeingResized = nullptr;
282 m_dragTarget = nullptr;
283 m_shouldOnlyFireDragOverEvent = false;
284 m_mousePositionIsUnknown = true;
285 m_lastKnownMousePosition = IntPoint();
286 m_lastKnownMouseGlobalPosition = IntPoint();
287 m_lastMouseDownUserGestureToken.clear();
288 m_mousePressNode = nullptr;
289 m_mousePressed = false;
290 m_capturesDragging = false;
291 m_capturingMouseEventsNode = nullptr;
292 m_latchedWheelEventNode = nullptr;
293 m_previousWheelScrolledNode = nullptr;
294 m_targetForTouchID.clear();
295 m_touchSequenceDocument.clear();
296 m_touchSequenceUserGestureToken.clear();
297 m_scrollGestureHandlingNode = nullptr;
298 m_lastHitTestResultOverWidget = false;
299 m_previousGestureScrolledNode = nullptr;
300 m_scrollbarHandlingScrollGesture = nullptr;
301 m_maxMouseMovedDuration = 0;
302 m_baseEventType = PlatformEvent::NoType;
303 m_didStartDrag = false;
304 m_touchPressed = false;
305 m_mouseDownMayStartSelect = false;
306 m_mouseDownMayStartDrag = false;
307 m_lastShowPressTimestamp = 0;
308 m_lastDeferredTapElement = nullptr;
311 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
313 if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
315 if (nodeToBeRemoved.isInShadowTree()) {
316 m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
318 // We don't dispatch click events if the mousedown node is removed
319 // before a mouseup event. It is compatible with IE and Firefox.
320 m_clickNode = nullptr;
324 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
326 if (selection.selection() != newSelection)
327 selection.setSelection(newSelection);
330 static inline bool dispatchSelectStart(Node* node)
332 if (!node || !node->renderer())
335 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
338 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
340 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
341 if (!rootUserSelectAll)
344 VisibleSelection newSelection(selection);
345 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
346 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
351 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
353 if (Position::nodeIsUserSelectNone(targetNode))
356 if (!dispatchSelectStart(targetNode))
359 if (selection.isRange())
360 m_selectionInitiationState = ExtendedSelection;
362 granularity = CharacterGranularity;
363 m_selectionInitiationState = PlacedCaret;
366 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
371 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
373 Node* innerNode = result.targetNode();
374 VisibleSelection newSelection;
376 if (innerNode && innerNode->renderer()) {
377 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
378 if (pos.isNotNull()) {
379 newSelection = VisibleSelection(pos);
380 newSelection.expandUsingGranularity(WordGranularity);
383 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
384 newSelection.appendTrailingWhitespace();
386 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
390 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
392 Node* innerNode = result.targetNode();
393 VisibleSelection newSelection;
395 if (innerNode && innerNode->renderer()) {
396 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
397 Position start = pos.deepEquivalent();
398 Position end = pos.deepEquivalent();
399 if (pos.isNotNull()) {
400 WillBeHeapVector<DocumentMarker*> markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
401 if (markers.size() == 1) {
402 start.moveToOffset(markers[0]->startOffset());
403 end.moveToOffset(markers[0]->endOffset());
404 newSelection = VisibleSelection(start, end);
408 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
409 newSelection.appendTrailingWhitespace();
411 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
415 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
417 if (m_mouseDownMayStartSelect) {
418 selectClosestWordFromHitTestResult(result.hitTestResult(),
419 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
423 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
425 if (m_mouseDownMayStartSelect) {
426 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
427 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
431 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
433 if (!result.hitTestResult().isLiveLink())
434 return selectClosestWordFromMouseEvent(result);
436 Node* innerNode = result.targetNode();
438 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
439 VisibleSelection newSelection;
440 Element* URLElement = result.hitTestResult().URLElement();
441 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
442 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
443 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
445 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
449 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
451 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventDoubleClick");
453 if (event.event().button() != LeftButton)
456 if (m_frame->selection().isRange()) {
457 // A double-click when range is already selected
458 // should not change the selection. So, do not call
459 // selectClosestWordFromMouseEvent, but do set
460 // m_beganSelectingText to prevent handleMouseReleaseEvent
461 // from setting caret selection.
462 m_selectionInitiationState = ExtendedSelection;
464 selectClosestWordFromMouseEvent(event);
469 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
471 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventTripleClick");
473 if (event.event().button() != LeftButton)
476 Node* innerNode = event.targetNode();
477 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
480 VisibleSelection newSelection;
481 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
482 if (pos.isNotNull()) {
483 newSelection = VisibleSelection(pos);
484 newSelection.expandUsingGranularity(ParagraphGranularity);
487 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
490 static int textDistance(const Position& start, const Position& end)
492 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, end);
493 return TextIterator::rangeLength(range.get(), true);
496 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
498 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventSingleClick");
500 m_frame->document()->updateLayoutIgnorePendingStylesheets();
501 Node* innerNode = event.targetNode();
502 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
505 // Extend the selection if the Shift key is down, unless the click is in a link.
506 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
508 // Don't restart the selection when the mouse is pressed on an
509 // existing selection so we can allow for text dragging.
510 if (FrameView* view = m_frame->view()) {
511 LayoutPoint vPoint = view->windowToContents(event.event().position());
512 if (!extendSelection && m_frame->selection().contains(vPoint)) {
513 m_mouseDownWasSingleClickInSelection = true;
518 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
519 if (visiblePos.isNull())
520 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
521 Position pos = visiblePos.deepEquivalent();
523 VisibleSelection newSelection = m_frame->selection().selection();
524 TextGranularity granularity = CharacterGranularity;
526 if (extendSelection && newSelection.isCaretOrRange()) {
527 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
528 if (selectionInUserSelectAll.isRange()) {
529 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
530 pos = selectionInUserSelectAll.start();
531 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
532 pos = selectionInUserSelectAll.end();
535 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
536 if (pos.isNotNull()) {
537 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
538 // was created right-to-left
539 Position start = newSelection.start();
540 Position end = newSelection.end();
541 int distanceToStart = textDistance(start, pos);
542 int distanceToEnd = textDistance(pos, end);
543 if (distanceToStart <= distanceToEnd)
544 newSelection = VisibleSelection(end, pos);
546 newSelection = VisibleSelection(start, pos);
549 newSelection.setExtent(pos);
551 if (m_frame->selection().granularity() != CharacterGranularity) {
552 granularity = m_frame->selection().granularity();
553 newSelection.expandUsingGranularity(m_frame->selection().granularity());
556 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos));
559 // Updating the selection is considered side-effect of the event and so it doesn't impact the handled state.
560 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
564 static inline bool canMouseDownStartSelect(Node* node)
566 if (!node || !node->renderer())
569 if (!node->canStartSelection())
575 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
577 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
580 dragState().m_dragSrc = nullptr;
582 cancelFakeMouseMoveEvent();
584 m_frame->document()->updateLayoutIgnorePendingStylesheets();
586 if (ScrollView* scrollView = m_frame->view()) {
587 if (scrollView->isPointInScrollbarCorner(event.event().position()))
591 bool singleClick = event.event().clickCount() <= 1;
593 // If we got the event back, that must mean it wasn't prevented,
594 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
595 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
597 m_mouseDownMayStartDrag = singleClick;
599 m_mouseDownWasSingleClickInSelection = false;
601 m_mouseDown = event.event();
603 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
606 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGExtensions().zoomAndPanEnabled()) {
607 if (event.event().shiftKey() && singleClick) {
609 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()->windowToContents(event.event().position()));
614 // We don't do this at the start of mouse down handling,
615 // because we don't want to do it until we know we didn't hit a widget.
619 Node* innerNode = event.targetNode();
621 m_mousePressNode = innerNode;
622 m_dragStartPos = event.event().position();
624 bool swallowEvent = false;
625 m_mousePressed = true;
626 m_selectionInitiationState = HaveNotStartedSelection;
628 if (event.event().clickCount() == 2)
629 swallowEvent = handleMousePressEventDoubleClick(event);
630 else if (event.event().clickCount() >= 3)
631 swallowEvent = handleMousePressEventTripleClick(event);
633 swallowEvent = handleMousePressEventSingleClick(event);
635 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
636 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
641 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
643 TRACE_EVENT0("webkit", "EventHandler::handleMouseDraggedEvent");
648 if (handleDrag(event, ShouldCheckDragHysteresis))
651 Node* targetNode = event.targetNode();
652 if (event.event().button() != LeftButton || !targetNode)
655 RenderObject* renderer = targetNode->renderer();
657 Node* parent = NodeRenderingTraversal::parent(targetNode);
661 renderer = parent->renderer();
662 if (!renderer || !renderer->isListBox())
666 m_mouseDownMayStartDrag = false;
668 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
669 if (AutoscrollController* controller = autoscrollController()) {
670 controller->startAutoscrollForSelection(renderer);
671 m_mouseDownMayStartAutoscroll = false;
675 if (m_selectionInitiationState != ExtendedSelection) {
676 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
677 HitTestResult result(m_mouseDownPos);
678 m_frame->document()->renderView()->hitTest(request, result);
680 updateSelectionForMouseDrag(result);
682 updateSelectionForMouseDrag(event.hitTestResult());
686 void EventHandler::updateSelectionForMouseDrag()
688 FrameView* view = m_frame->view();
691 RenderView* renderer = m_frame->contentRenderer();
695 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
696 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
697 renderer->hitTest(request, result);
698 updateSelectionForMouseDrag(result);
701 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
703 if (!m_mouseDownMayStartSelect)
706 Node* target = hitTestResult.targetNode();
710 VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
711 // Don't modify the selection if we're not on a node.
712 if (targetPosition.isNull())
715 // Restart the selection if this is the first mouse move. This work is usually
716 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
717 VisibleSelection newSelection = m_frame->selection().selection();
719 // Special case to limit selection to the containing block for SVG text.
720 // FIXME: Isn't there a better non-SVG-specific way to do this?
721 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
722 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
723 if (selectionBaseRenderer->isSVGText())
724 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
727 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
730 if (m_selectionInitiationState != ExtendedSelection) {
731 // Always extend selection here because it's caused by a mouse drag
732 m_selectionInitiationState = ExtendedSelection;
733 newSelection = VisibleSelection(targetPosition);
736 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
737 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
738 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
739 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
740 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
742 // Reset base for user select all when base is inside user-select-all area and extent < base.
743 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
744 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
746 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
747 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
748 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
749 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
750 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
752 newSelection.setExtent(targetPosition);
755 newSelection.setExtent(targetPosition);
758 if (m_frame->selection().granularity() != CharacterGranularity)
759 newSelection.expandUsingGranularity(m_frame->selection().granularity());
761 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
762 FrameSelection::AdjustEndpointsAtBidiBoundary);
765 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
767 AutoscrollController* controller = autoscrollController();
768 if (controller && controller->autoscrollInProgress())
771 // Used to prevent mouseMoveEvent from initiating a drag before
772 // the mouse is pressed again.
773 m_mousePressed = false;
774 m_capturesDragging = false;
775 m_mouseDownMayStartDrag = false;
776 m_mouseDownMayStartSelect = false;
777 m_mouseDownMayStartAutoscroll = false;
778 m_mouseDownWasInSubframe = false;
780 bool handled = false;
782 // Clear the selection if the mouse didn't move after the last mouse
783 // press and it's not a context menu click. We do this so when clicking
784 // on the selection, the selection goes away. However, if we are
785 // editing, place the caret.
786 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
787 && m_dragStartPos == event.event().position()
788 && m_frame->selection().isRange()
789 && event.event().button() != RightButton) {
790 VisibleSelection newSelection;
791 Node* node = event.targetNode();
792 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
793 if (node && node->renderer() && (caretBrowsing || node->rendererIsEditable())) {
794 VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
795 newSelection = VisibleSelection(pos);
798 setSelectionIfNeeded(m_frame->selection(), newSelection);
803 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
805 m_frame->selection().selectFrameElementInParentIfFullySelected();
807 if (event.event().button() == MiddleButton && !event.isOverLink()) {
808 // Ignore handled, since we want to paste to where the caret was placed anyway.
809 handled = handlePasteGlobalSelection(event.event()) || handled;
817 void EventHandler::startPanScrolling(RenderObject* renderer)
819 if (!renderer->isBox())
821 AutoscrollController* controller = autoscrollController();
824 controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
830 AutoscrollController* EventHandler::autoscrollController() const
832 if (Page* page = m_frame->page())
833 return &page->autoscrollController();
837 bool EventHandler::panScrollInProgress() const
839 return autoscrollController() && autoscrollController()->panScrollInProgress();
842 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
844 TRACE_EVENT0("webkit", "EventHandler::hitTestResultAtPoint");
846 // We always send hitTestResultAtPoint to the main frame if we have one,
847 // otherwise we might hit areas that are obscured by higher frames.
848 if (Page* page = m_frame->page()) {
849 LocalFrame* mainFrame = page->mainFrame()->isLocalFrame() ? page->deprecatedLocalMainFrame() : 0;
850 if (mainFrame && m_frame != mainFrame) {
851 FrameView* frameView = m_frame->view();
852 FrameView* mainView = mainFrame->view();
853 if (frameView && mainView) {
854 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
855 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
860 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
862 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
863 // layout because until then, there is nothing shown on the screen - the user can't
864 // have intentionally clicked on something belonging to this page. Furthermore,
865 // mousemove events before the first layout should not lead to a premature layout()
866 // happening, which could show a flash of white.
867 // See also the similar code in Document::prepareMouseEvent.
868 if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
871 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
872 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
873 m_frame->contentRenderer()->hitTest(request, result);
874 if (!request.readOnly())
875 m_frame->document()->updateHoverActiveState(request, result.innerElement());
877 if (request.disallowsShadowContent())
878 result.setToNodesInDocumentTreeScope();
883 void EventHandler::stopAutoscroll()
885 if (AutoscrollController* controller = autoscrollController())
886 controller->stopAutoscroll();
889 Node* EventHandler::mousePressNode() const
891 return m_mousePressNode.get();
894 bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoint absolutePoint)
899 Node* node = startNode;
902 node = m_frame->document()->focusedElement();
905 node = m_mousePressNode.get();
907 if (!node || !node->renderer())
910 RenderBox* curBox = node->renderer()->enclosingBox();
911 while (curBox && !curBox->isRenderView()) {
912 ScrollDirection physicalDirection = toPhysicalDirection(
913 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode());
915 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
916 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *stopNode;
917 bool didScroll = curBox->scroll(physicalDirection, granularity, delta);
919 if (didScroll && stopNode)
920 *stopNode = curBox->node();
922 if (didScroll || shouldStopBubbling) {
923 setFrameWasScrolledByUser();
927 curBox = curBox->containingBlock();
933 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
935 // The layout needs to be up to date to determine if we can scroll. We may be
936 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
937 m_frame->document()->updateLayoutIgnorePendingStylesheets();
938 if (scroll(direction, granularity, startingNode))
940 LocalFrame* frame = m_frame;
941 FrameView* view = frame->view();
942 if (view && view->scroll(direction, granularity))
944 Frame* parentFrame = frame->tree().parent();
945 if (!parentFrame || !parentFrame->isLocalFrame())
947 // FIXME: Broken for OOPI.
948 return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, granularity, m_frame->deprecatedLocalOwner());
951 IntPoint EventHandler::lastKnownMousePosition() const
953 return m_lastKnownMousePosition;
956 static LocalFrame* subframeForTargetNode(Node* node)
961 RenderObject* renderer = node->renderer();
962 if (!renderer || !renderer->isWidget())
965 // FIXME: This explicit check is needed only until RemoteFrames have RemoteFrameViews.
966 if (isHTMLFrameElementBase(node) && toHTMLFrameElementBase(node)->contentFrame() && toHTMLFrameElementBase(node)->contentFrame()->isRemoteFrameTemporary())
969 Widget* widget = toRenderWidget(renderer)->widget();
970 if (!widget || !widget->isFrameView())
973 return &toFrameView(widget)->frame();
976 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
978 if (!hitTestResult.isOverWidget())
980 return subframeForTargetNode(hitTestResult.targetNode());
983 static bool isSubmitImage(Node* node)
985 return isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
988 bool EventHandler::useHandCursor(Node* node, bool isOverLink)
993 return ((isOverLink || isSubmitImage(node)) && !node->rendererIsEditable());
996 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
999 ASSERT(m_frame->document());
1004 void EventHandler::updateCursor()
1006 if (m_mousePositionIsUnknown)
1009 FrameView* view = m_frame->view();
1010 if (!view || !view->shouldSetCursor())
1013 RenderView* renderView = view->renderView();
1017 m_frame->document()->updateLayout();
1019 HitTestRequest request(HitTestRequest::ReadOnly);
1020 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1021 renderView->hitTest(request, result);
1023 OptionalCursor optionalCursor = selectCursor(result);
1024 if (optionalCursor.isCursorChange()) {
1025 m_currentMouseCursor = optionalCursor.cursor();
1026 view->setCursor(m_currentMouseCursor);
1030 OptionalCursor EventHandler::selectCursor(const HitTestResult& result)
1032 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1033 return NoCursorChange;
1035 Page* page = m_frame->page();
1037 return NoCursorChange;
1039 if (panScrollInProgress())
1040 return NoCursorChange;
1043 Node* node = result.innerPossiblyPseudoNode();
1045 return selectAutoCursor(result, node, iBeamCursor());
1047 RenderObject* renderer = node->renderer();
1048 RenderStyle* style = renderer ? renderer->style() : 0;
1051 Cursor overrideCursor;
1052 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1053 case SetCursorBasedOnStyle:
1056 return overrideCursor;
1057 case DoNotSetCursor:
1058 return NoCursorChange;
1062 if (style && style->cursors()) {
1063 const CursorList* cursors = style->cursors();
1064 for (unsigned i = 0; i < cursors->size(); ++i) {
1065 StyleImage* styleImage = (*cursors)[i].image();
1068 ImageResource* cachedImage = styleImage->cachedImage();
1071 float scale = styleImage->imageScaleFactor();
1072 // Get hotspot and convert from logical pixels to physical pixels.
1073 IntPoint hotSpot = (*cursors)[i].hotSpot();
1074 hotSpot.scale(scale, scale);
1075 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1076 if (cachedImage->errorOccurred())
1078 // Limit the size of cursors (in UI pixels) so that they cannot be
1079 // used to cover UI elements in chrome.
1080 size.scale(1 / scale);
1081 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1084 Image* image = cachedImage->imageForRenderer(renderer);
1085 // Ensure no overflow possible in calculations above.
1086 if (scale < minimumCursorScale)
1088 return Cursor(image, hotSpot, scale);
1092 switch (style ? style->cursor() : CURSOR_AUTO) {
1094 bool horizontalText = !style || style->isHorizontalWritingMode();
1095 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1096 return selectAutoCursor(result, node, iBeam);
1099 return crossCursor();
1100 case CURSOR_POINTER:
1101 return handCursor();
1103 return moveCursor();
1104 case CURSOR_ALL_SCROLL:
1105 return moveCursor();
1106 case CURSOR_E_RESIZE:
1107 return eastResizeCursor();
1108 case CURSOR_W_RESIZE:
1109 return westResizeCursor();
1110 case CURSOR_N_RESIZE:
1111 return northResizeCursor();
1112 case CURSOR_S_RESIZE:
1113 return southResizeCursor();
1114 case CURSOR_NE_RESIZE:
1115 return northEastResizeCursor();
1116 case CURSOR_SW_RESIZE:
1117 return southWestResizeCursor();
1118 case CURSOR_NW_RESIZE:
1119 return northWestResizeCursor();
1120 case CURSOR_SE_RESIZE:
1121 return southEastResizeCursor();
1122 case CURSOR_NS_RESIZE:
1123 return northSouthResizeCursor();
1124 case CURSOR_EW_RESIZE:
1125 return eastWestResizeCursor();
1126 case CURSOR_NESW_RESIZE:
1127 return northEastSouthWestResizeCursor();
1128 case CURSOR_NWSE_RESIZE:
1129 return northWestSouthEastResizeCursor();
1130 case CURSOR_COL_RESIZE:
1131 return columnResizeCursor();
1132 case CURSOR_ROW_RESIZE:
1133 return rowResizeCursor();
1135 return iBeamCursor();
1137 return waitCursor();
1139 return helpCursor();
1140 case CURSOR_VERTICAL_TEXT:
1141 return verticalTextCursor();
1143 return cellCursor();
1144 case CURSOR_CONTEXT_MENU:
1145 return contextMenuCursor();
1146 case CURSOR_PROGRESS:
1147 return progressCursor();
1148 case CURSOR_NO_DROP:
1149 return noDropCursor();
1151 return aliasCursor();
1153 return copyCursor();
1155 return noneCursor();
1156 case CURSOR_NOT_ALLOWED:
1157 return notAllowedCursor();
1158 case CURSOR_DEFAULT:
1159 return pointerCursor();
1160 case CURSOR_ZOOM_IN:
1161 return zoomInCursor();
1162 case CURSOR_ZOOM_OUT:
1163 return zoomOutCursor();
1164 case CURSOR_WEBKIT_GRAB:
1165 return grabCursor();
1166 case CURSOR_WEBKIT_GRABBING:
1167 return grabbingCursor();
1169 return pointerCursor();
1172 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam)
1174 bool editable = (node && node->rendererIsEditable());
1176 if (useHandCursor(node, result.isOverLink()))
1177 return handCursor();
1179 bool inResizer = false;
1180 RenderObject* renderer = node ? node->renderer() : 0;
1181 if (renderer && m_frame->view()) {
1182 RenderLayer* layer = renderer->enclosingLayer();
1183 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1186 // During selection, use an I-beam no matter what we're over.
1187 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1188 if (m_mousePressed && m_mouseDownMayStartSelect
1189 && !m_mouseDownMayStartDrag
1190 && m_frame->selection().isCaretOrRange()
1191 && !m_capturingMouseEventsNode) {
1195 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1197 return pointerCursor();
1200 static LayoutPoint documentPointForWindowPoint(LocalFrame* frame, const IntPoint& windowPoint)
1202 FrameView* view = frame->view();
1203 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1204 // Historically the code would just crash; this is clearly no worse than that.
1205 return view ? view->windowToContents(windowPoint) : windowPoint;
1208 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1210 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
1212 RefPtr<FrameView> protector(m_frame->view());
1214 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1215 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1217 cancelFakeMouseMoveEvent();
1218 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1219 m_capturingMouseEventsNode = nullptr;
1220 m_mousePressed = true;
1221 m_capturesDragging = true;
1222 setLastKnownMousePosition(mouseEvent);
1223 m_mouseDownTimestamp = mouseEvent.timestamp();
1224 m_mouseDownMayStartDrag = false;
1225 m_mouseDownMayStartSelect = false;
1226 m_mouseDownMayStartAutoscroll = false;
1227 if (FrameView* view = m_frame->view())
1228 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1233 m_mouseDownWasInSubframe = false;
1235 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1236 if (mouseEvent.fromTouch())
1237 hitType |= HitTestRequest::ReadOnly;
1238 HitTestRequest request(hitType);
1239 // Save the document point we generate in case the window coordinate is invalidated by what happens
1240 // when we dispatch the event.
1241 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1242 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1244 if (!mev.targetNode()) {
1249 m_mousePressNode = mev.targetNode();
1251 RefPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1252 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1253 // Start capturing future events for this frame. We only do this if we didn't clear
1254 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1255 m_capturesDragging = subframe->eventHandler().capturesDragging();
1256 if (m_mousePressed && m_capturesDragging) {
1257 m_capturingMouseEventsNode = mev.targetNode();
1258 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1265 // We store whether pan scrolling is in progress before calling stopAutoscroll()
1266 // because it will set m_autoscrollType to NoAutoscroll on return.
1267 bool isPanScrollInProgress = panScrollInProgress();
1269 if (isPanScrollInProgress) {
1270 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1271 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1277 m_clickCount = mouseEvent.clickCount();
1278 m_clickNode = mev.targetNode()->isTextNode() ? NodeRenderingTraversal::parent(mev.targetNode()) : mev.targetNode();
1280 if (FrameView* view = m_frame->view()) {
1281 RenderLayer* layer = mev.targetNode()->renderer() ? mev.targetNode()->renderer()->enclosingLayer() : 0;
1282 IntPoint p = view->windowToContents(mouseEvent.position());
1283 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1284 m_resizeScrollableArea = layer->scrollableArea();
1285 m_resizeScrollableArea->setInResizeMode(true);
1286 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1292 m_frame->selection().setCaretBlinkingSuspended(true);
1294 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.targetNode(), m_clickCount, mouseEvent, true);
1295 swallowEvent = swallowEvent || !handleMouseFocus(mouseEvent);
1296 m_capturesDragging = !swallowEvent || mev.scrollbar();
1298 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1299 // in case the scrollbar widget was destroyed when the mouse event was handled.
1300 if (mev.scrollbar()) {
1301 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1302 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1303 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1304 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1305 m_lastScrollbarUnderMouse = nullptr;
1309 // scrollbars should get events anyway, even disabled controls might be scrollable
1310 passMousePressEventToScrollbar(mev);
1312 if (shouldRefetchEventTarget(mev)) {
1313 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1314 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1317 if (passMousePressEventToScrollbar(mev))
1318 swallowEvent = true;
1320 swallowEvent = handleMousePressEvent(mev);
1323 return swallowEvent;
1326 static RenderLayer* layerForNode(Node* node)
1331 RenderObject* renderer = node->renderer();
1335 RenderLayer* layer = renderer->enclosingLayer();
1342 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1344 if (RenderLayerScrollableArea* scrollableArea = layer->scrollableArea()) {
1345 if (scrollableArea->scrollsOverflow())
1346 return scrollableArea;
1352 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1354 TRACE_EVENT0("webkit", "EventHandler::handleMouseMoveEvent");
1356 RefPtr<FrameView> protector(m_frame->view());
1357 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1359 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1360 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1362 Page* page = m_frame->page();
1366 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1367 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1368 layerScrollableArea->mouseMovedInContentArea();
1371 if (FrameView* frameView = m_frame->view())
1372 frameView->mouseMovedInContentArea();
1374 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1375 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1376 page->chrome().setToolTip(hoveredNode);
1381 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1383 TRACE_EVENT0("webkit", "EventHandler::handleMouseLeaveEvent");
1385 RefPtr<FrameView> protector(m_frame->view());
1386 handleMouseMoveOrLeaveEvent(event);
1389 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1392 ASSERT(m_frame->view());
1394 setLastKnownMousePosition(mouseEvent);
1396 if (m_hoverTimer.isActive())
1397 m_hoverTimer.stop();
1399 m_cursorUpdateTimer.stop();
1401 cancelFakeMouseMoveEvent();
1404 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1408 if (m_frameSetBeingResized)
1409 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), 0, mouseEvent, false);
1411 // Send events right to a scrollbar if the mouse is pressed.
1412 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1413 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1417 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1418 if (mouseEvent.fromTouch())
1419 hitType |= HitTestRequest::ReadOnly;
1422 hitType |= HitTestRequest::Active;
1423 else if (onlyUpdateScrollbars) {
1424 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1425 // means that :hover and :active freeze in the state they were in, rather than updating
1426 // for nodes the mouse moves while the window is not key (which will be the case if
1427 // onlyUpdateScrollbars is true).
1428 hitType |= HitTestRequest::ReadOnly;
1431 // Treat any mouse move events as readonly if the user is currently touching the screen.
1433 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1434 HitTestRequest request(hitType);
1435 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1437 *hoveredNode = mev.hitTestResult();
1439 Scrollbar* scrollbar = 0;
1441 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1442 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1444 if (FrameView* view = m_frame->view())
1445 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1448 scrollbar = mev.scrollbar();
1450 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1451 if (onlyUpdateScrollbars)
1455 bool swallowEvent = false;
1456 RefPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1458 // 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.
1459 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1460 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1463 // Update over/out state before passing the event to the subframe.
1464 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1466 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1467 // node to be detached from its FrameView, in which case the event should not be passed.
1468 if (newSubframe->view())
1469 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1471 if (scrollbar && !m_mousePressed)
1472 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1473 if (FrameView* view = m_frame->view()) {
1474 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult());
1475 if (optionalCursor.isCursorChange()) {
1476 m_currentMouseCursor = optionalCursor.cursor();
1477 view->setCursor(m_currentMouseCursor);
1482 m_lastMouseMoveEventSubframe = newSubframe;
1487 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.targetNode(), 0, mouseEvent, true);
1489 swallowEvent = handleMouseDraggedEvent(mev);
1491 return swallowEvent;
1494 void EventHandler::invalidateClick()
1497 m_clickNode = nullptr;
1500 static Node* parentForClickEvent(const Node& node)
1502 // IE doesn't dispatch click events for mousedown/mouseup events across form
1504 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1506 return NodeRenderingTraversal::parent(&node);
1509 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1511 TRACE_EVENT0("webkit", "EventHandler::handleMouseReleaseEvent");
1513 RefPtr<FrameView> protector(m_frame->view());
1515 m_frame->selection().setCaretBlinkingSuspended(false);
1517 OwnPtr<UserGestureIndicator> gestureIndicator;
1519 if (m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken)
1520 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1522 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1525 if (Page* page = m_frame->page())
1526 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1529 m_mousePressed = false;
1530 setLastKnownMousePosition(mouseEvent);
1534 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1538 if (m_frameSetBeingResized)
1539 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), m_clickCount, mouseEvent, false);
1541 if (m_lastScrollbarUnderMouse) {
1543 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1544 bool setUnder = false;
1545 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), m_clickCount, mouseEvent, setUnder);
1548 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1549 if (mouseEvent.fromTouch())
1550 hitType |= HitTestRequest::ReadOnly;
1551 HitTestRequest request(hitType);
1552 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1553 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1554 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1555 m_capturingMouseEventsNode = nullptr;
1556 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1559 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.targetNode(), m_clickCount, mouseEvent, false);
1561 bool contextMenuEvent = mouseEvent.button() == RightButton;
1563 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1564 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1565 contextMenuEvent = true;
1568 bool swallowClickEvent = false;
1569 if (m_clickCount > 0 && !contextMenuEvent && mev.targetNode() && m_clickNode) {
1570 if (Node* clickTargetNode = mev.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1571 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, m_clickCount, mouseEvent, true);
1574 if (m_resizeScrollableArea) {
1575 m_resizeScrollableArea->setInResizeMode(false);
1576 m_resizeScrollableArea = 0;
1579 bool swallowMouseReleaseEvent = false;
1580 if (!swallowMouseUpEvent)
1581 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1585 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1588 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1590 // If the event was a middle click, attempt to copy global selection in after
1591 // the newly set caret position.
1593 // This code is called from either the mouse up or mouse down handling. There
1594 // is some debate about when the global selection is pasted:
1595 // xterm: pastes on up.
1596 // GTK: pastes on down.
1597 // Qt: pastes on up.
1598 // Firefox: pastes on up.
1599 // Chromium: pastes on up.
1601 // There is something of a webcompat angle to this well, as highlighted by
1602 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1603 // down then the text is pasted just before the onclick handler runs and
1604 // clears the text box. So it's important this happens after the event
1605 // handlers have been fired.
1606 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1609 if (!m_frame->page())
1611 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1612 // Do not paste here if the focus was moved somewhere else.
1613 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1614 return m_frame->editor().command("PasteGlobalSelection").execute();
1620 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1622 FrameView* view = m_frame->view();
1624 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1628 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType,
1629 true, true, m_frame->document()->domWindow(),
1630 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1631 event.movementDelta().x(), event.movementDelta().y(),
1632 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1633 0, nullptr, clipboard);
1635 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1636 return me->defaultPrevented();
1639 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1641 if (!isHTMLFrameElementBase(target))
1644 // Cross-process drag and drop is not yet supported.
1645 if (toHTMLFrameElementBase(target)->contentFrame() && !toHTMLFrameElementBase(target)->contentFrame()->isLocalFrame())
1648 frame = toLocalFrame(toHTMLFrameElementBase(target)->contentFrame());
1652 static bool findDropZone(Node* target, Clipboard* clipboard)
1654 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1655 for (; element; element = element->parentElement()) {
1656 bool matched = false;
1657 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1659 if (dropZoneStr.isEmpty())
1662 dropZoneStr = dropZoneStr.lower();
1664 SpaceSplitString keywords(dropZoneStr, false);
1665 if (keywords.isNull())
1668 DragOperation dragOperation = DragOperationNone;
1669 for (unsigned i = 0; i < keywords.size(); i++) {
1670 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1671 if (op != DragOperationNone) {
1672 if (dragOperation == DragOperationNone)
1675 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1677 if (matched && dragOperation != DragOperationNone)
1681 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1688 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1690 bool accept = false;
1692 if (!m_frame->view())
1695 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1696 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1698 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1699 RefPtrWillBeRawPtr<Node> newTarget = mev.targetNode();
1700 if (newTarget && newTarget->isTextNode())
1701 newTarget = NodeRenderingTraversal::parent(newTarget.get());
1703 if (AutoscrollController* controller = autoscrollController())
1704 controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1706 if (m_dragTarget != newTarget) {
1707 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1708 // it is sometimes incorrect when dragging within subframes, as seen with
1709 // LayoutTests/fast/events/drag-in-frames.html.
1711 // 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>.
1712 LocalFrame* targetFrame;
1713 if (targetIsFrame(newTarget.get(), targetFrame)) {
1715 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1716 } else if (newTarget) {
1717 // 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.
1718 if (dragState().m_dragSrc) {
1719 // for now we don't care if event handler cancels default behavior, since there is none
1720 dispatchDragSrcEvent(EventTypeNames::drag, event);
1722 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, clipboard);
1724 accept = findDropZone(newTarget.get(), clipboard);
1727 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1729 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1730 } else if (m_dragTarget)
1731 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1734 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1735 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1736 m_shouldOnlyFireDragOverEvent = true;
1739 LocalFrame* targetFrame;
1740 if (targetIsFrame(newTarget.get(), targetFrame)) {
1742 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1743 } else if (newTarget) {
1744 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1745 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1746 // for now we don't care if event handler cancels default behavior, since there is none
1747 dispatchDragSrcEvent(EventTypeNames::drag, event);
1749 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, clipboard);
1751 accept = findDropZone(newTarget.get(), clipboard);
1752 m_shouldOnlyFireDragOverEvent = false;
1755 m_dragTarget = newTarget;
1760 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1762 LocalFrame* targetFrame;
1763 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1765 targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
1766 } else if (m_dragTarget.get()) {
1767 if (dragState().m_dragSrc)
1768 dispatchDragSrcEvent(EventTypeNames::drag, event);
1769 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1774 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1776 LocalFrame* targetFrame;
1777 bool preventedDefault = false;
1778 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1780 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
1781 } else if (m_dragTarget.get())
1782 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, clipboard);
1784 return preventedDefault;
1787 void EventHandler::clearDragState()
1790 m_dragTarget = nullptr;
1791 m_capturingMouseEventsNode = nullptr;
1792 m_shouldOnlyFireDragOverEvent = false;
1795 void EventHandler::setCapturingMouseEventsNode(PassRefPtrWillBeRawPtr<Node> n)
1797 m_capturingMouseEventsNode = n;
1798 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1801 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1804 ASSERT(m_frame->document());
1806 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1809 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1811 Node* result = targetNode;
1813 // If we're capturing, we always go right to that node.
1814 if (m_capturingMouseEventsNode)
1815 result = m_capturingMouseEventsNode.get();
1817 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1818 if (result && result->isTextNode())
1819 result = NodeRenderingTraversal::parent(result);
1821 m_nodeUnderMouse = result;
1823 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1824 if (fireMouseOverOut) {
1825 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1826 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1827 Page* page = m_frame->page();
1829 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1830 // The mouse has moved between frames.
1831 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1832 if (FrameView* frameView = frame->view())
1833 frameView->mouseExitedContentArea();
1835 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1836 // The mouse has moved between layers.
1837 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
1838 scrollableAreaForLastNode->mouseExitedContentArea();
1841 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1842 // The mouse has moved between frames.
1843 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
1844 if (FrameView* frameView = frame->view())
1845 frameView->mouseEnteredContentArea();
1847 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1848 // The mouse has moved between layers.
1849 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
1850 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1853 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1854 m_lastNodeUnderMouse = nullptr;
1855 m_lastScrollbarUnderMouse = nullptr;
1858 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1859 // send mouseout event to the old node
1860 if (m_lastNodeUnderMouse)
1861 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
1862 // send mouseover event to the new node
1863 if (m_nodeUnderMouse)
1864 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
1866 m_lastNodeUnderMouse = m_nodeUnderMouse;
1870 // The return value means 'continue default handling.'
1871 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1873 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1874 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1877 // The return value means 'continue default handling.'
1878 bool EventHandler::handleMouseFocus(const PlatformMouseEvent& mouseEvent)
1880 // If clicking on a frame scrollbar, do not mess up with content focus.
1881 if (FrameView* view = m_frame->view()) {
1882 if (view->scrollbarAtPoint(mouseEvent.position()))
1886 // The layout needs to be up to date to determine if an element is focusable.
1887 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1889 Element* element = 0;
1890 if (m_nodeUnderMouse)
1891 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
1892 for (; element; element = element->parentOrShadowHostElement()) {
1893 if (element->isFocusable() && element->focused())
1895 if (element->isMouseFocusable())
1898 ASSERT(!element || element->isMouseFocusable());
1900 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
1901 // a node on mouse down if it's selected and inside a focused node. It will
1902 // be focused if the user does a mouseup over it, however, because the
1903 // mouseup will set a selection inside it, which will call
1904 // FrameSelection::setFocusedNodeIfNeeded.
1906 && m_frame->selection().isRange()
1907 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
1908 && element->isDescendantOf(m_frame->document()->focusedElement()))
1911 // Only change the focus when clicking scrollbars if it can transfered to a
1912 // mouse focusable node.
1913 if (!element && isInsideScrollbar(mouseEvent.position()))
1916 if (Page* page = m_frame->page()) {
1917 // If focus shift is blocked, we eat the event. Note we should never
1918 // clear swallowEvent if the page already set it (e.g., by canceling
1919 // default behavior).
1921 if (!page->focusController().setFocusedElement(element, m_frame, FocusTypeMouse))
1924 // We call setFocusedElement even with !element in order to blur
1925 // current focus element when a link is clicked; this is expected by
1926 // some sites that rely on onChange handlers running from form
1927 // fields before the button click is processed.
1928 if (!page->focusController().setFocusedElement(0, m_frame))
1936 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
1938 if (RenderView* renderView = m_frame->contentRenderer()) {
1939 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1940 HitTestResult result(windowPoint);
1941 renderView->hitTest(request, result);
1942 return result.scrollbar();
1948 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
1950 #define RETURN_WHEEL_EVENT_HANDLED() \
1952 setFrameWasScrolledByUser(); \
1956 Document* doc = m_frame->document();
1958 if (!doc->renderView())
1961 RefPtr<FrameView> protector(m_frame->view());
1963 FrameView* view = m_frame->view();
1967 LayoutPoint vPoint = view->windowToContents(event.position());
1969 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1970 HitTestResult result(vPoint);
1971 doc->renderView()->hitTest(request, result);
1973 Node* node = result.innerNode();
1974 // Wheel events should not dispatch to text nodes.
1975 if (node && node->isTextNode())
1976 node = NodeRenderingTraversal::parent(node);
1979 if (event.useLatchedEventNode()) {
1980 if (!m_latchedWheelEventNode) {
1981 m_latchedWheelEventNode = node;
1982 m_widgetIsLatched = result.isOverWidget();
1984 node = m_latchedWheelEventNode.get();
1986 isOverWidget = m_widgetIsLatched;
1988 if (m_latchedWheelEventNode)
1989 m_latchedWheelEventNode = nullptr;
1990 if (m_previousWheelScrolledNode)
1991 m_previousWheelScrolledNode = nullptr;
1993 isOverWidget = result.isOverWidget();
1997 // Figure out which view to send the event to.
1998 RenderObject* target = node->renderer();
2000 if (isOverWidget && target && target->isWidget()) {
2001 Widget* widget = toRenderWidget(target)->widget();
2002 if (widget && passWheelEventToWidget(event, widget))
2003 RETURN_WHEEL_EVENT_HANDLED();
2006 if (node && !node->dispatchWheelEvent(event))
2007 RETURN_WHEEL_EVENT_HANDLED();
2010 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2011 view = m_frame->view();
2012 if (!view || !view->wheelEvent(event))
2015 RETURN_WHEEL_EVENT_HANDLED();
2017 #undef RETURN_WHEEL_EVENT_HANDLED
2020 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2022 if (!startNode || !wheelEvent)
2025 // Ctrl + scrollwheel is reserved for triggering zoom in/out actions in Chromium.
2026 if (wheelEvent->ctrlKey())
2029 Node* stopNode = m_previousWheelScrolledNode.get();
2030 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2032 // Break up into two scrolls if we need to. Diagonal movement on
2033 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2034 if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation())))
2035 wheelEvent->setDefaultHandled();
2037 if (scroll(ScrollDown, granularity, startNode, &stopNode, wheelEvent->deltaY(), roundedIntPoint(wheelEvent->absoluteLocation())))
2038 wheelEvent->setDefaultHandled();
2040 if (!m_latchedWheelEventNode)
2041 m_previousWheelScrolledNode = stopNode;
2044 bool EventHandler::handleGestureShowPress()
2046 m_lastShowPressTimestamp = WTF::currentTime();
2048 FrameView* view = m_frame->view();
2051 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2052 scrollAnimator->cancelAnimations();
2053 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2056 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2057 ScrollableArea* sa = *it;
2058 ScrollAnimator* animator = sa->scrollAnimator();
2060 animator->cancelAnimations();
2065 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2067 IntPoint adjustedPoint = gestureEvent.position();
2068 RefPtr<LocalFrame> subframe = nullptr;
2069 switch (gestureEvent.type()) {
2070 case PlatformEvent::GestureScrollBegin:
2071 case PlatformEvent::GestureScrollUpdate:
2072 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2073 case PlatformEvent::GestureScrollEnd:
2074 case PlatformEvent::GestureFlingStart:
2075 // Handle directly in main frame
2078 case PlatformEvent::GestureTap:
2079 case PlatformEvent::GestureTapUnconfirmed:
2080 case PlatformEvent::GestureTapDown:
2081 case PlatformEvent::GestureShowPress:
2082 case PlatformEvent::GestureTapDownCancel:
2083 case PlatformEvent::GestureTwoFingerTap:
2084 case PlatformEvent::GestureLongPress:
2085 case PlatformEvent::GestureLongTap:
2086 case PlatformEvent::GesturePinchBegin:
2087 case PlatformEvent::GesturePinchEnd:
2088 case PlatformEvent::GesturePinchUpdate:
2089 adjustGesturePosition(gestureEvent, adjustedPoint);
2090 subframe = getSubFrameForGestureEvent(adjustedPoint, gestureEvent);
2092 return subframe->eventHandler().handleGestureEvent(gestureEvent);
2096 ASSERT_NOT_REACHED();
2099 RefPtrWillBeRawPtr<Node> eventTarget = nullptr;
2100 RefPtr<Scrollbar> scrollbar;
2101 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2102 || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2103 || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation
2104 || gestureEvent.type() == PlatformEvent::GestureFlingStart) {
2105 scrollbar = m_scrollbarHandlingScrollGesture.get();
2106 eventTarget = m_scrollGestureHandlingNode.get();
2109 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2110 double activeInterval = 0;
2111 bool shouldKeepActiveForMinInterval = false;
2112 if (gestureEvent.type() == PlatformEvent::GestureShowPress
2113 || gestureEvent.type() == PlatformEvent::GestureTapUnconfirmed) {
2114 hitType |= HitTestRequest::Active;
2115 } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) {
2116 hitType |= HitTestRequest::Release;
2117 // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2118 if (!m_frame->document()->activeHoverElement())
2119 hitType |= HitTestRequest::ReadOnly;
2120 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2121 hitType |= HitTestRequest::Release;
2122 // If the Tap is received very shortly after ShowPress, we want to
2123 // delay clearing of the active state so that it's visible to the user
2124 // for at least a couple of frames.
2125 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2126 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2127 if (shouldKeepActiveForMinInterval)
2128 hitType |= HitTestRequest::ReadOnly;
2131 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2133 if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2134 IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2135 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2137 if (shouldKeepActiveForMinInterval) {
2138 m_lastDeferredTapElement = result.innerElement();
2139 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval, FROM_HERE);
2142 eventTarget = result.targetNode();
2144 FrameView* view = m_frame->view();
2145 scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2148 scrollbar = result.scrollbar();
2152 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2153 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed) {
2154 m_scrollbarHandlingScrollGesture = scrollbar;
2155 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2156 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2157 || !eventSwallowed) {
2158 m_scrollbarHandlingScrollGesture = nullptr;
2166 bool eventSwallowed = false;
2167 if (handleScrollGestureOnResizer(eventTarget.get(), gestureEvent))
2168 eventSwallowed = true;
2170 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2171 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2173 m_scrollGestureHandlingNode = eventTarget;
2180 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2181 // eliminate the need for this.
2182 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2184 switch (gestureEvent.type()) {
2185 case PlatformEvent::GestureScrollBegin:
2186 return handleGestureScrollBegin(gestureEvent);
2187 case PlatformEvent::GestureScrollUpdate:
2188 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2189 return handleGestureScrollUpdate(gestureEvent);
2190 case PlatformEvent::GestureScrollEnd:
2191 return handleGestureScrollEnd(gestureEvent);
2192 case PlatformEvent::GestureTap:
2193 return handleGestureTap(gestureEvent, adjustedPoint);
2194 case PlatformEvent::GestureShowPress:
2195 return handleGestureShowPress();
2196 case PlatformEvent::GestureLongPress:
2197 return handleGestureLongPress(gestureEvent, adjustedPoint);
2198 case PlatformEvent::GestureLongTap:
2199 return handleGestureLongTap(gestureEvent, adjustedPoint);
2200 case PlatformEvent::GestureTwoFingerTap:
2201 return handleGestureTwoFingerTap(gestureEvent, adjustedPoint);
2202 case PlatformEvent::GestureTapDown:
2203 case PlatformEvent::GesturePinchBegin:
2204 case PlatformEvent::GesturePinchEnd:
2205 case PlatformEvent::GesturePinchUpdate:
2206 case PlatformEvent::GestureTapDownCancel:
2207 case PlatformEvent::GestureTapUnconfirmed:
2208 case PlatformEvent::GestureFlingStart:
2211 ASSERT_NOT_REACHED();
2217 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2219 // 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.
2221 unsigned modifierFlags = 0;
2222 if (gestureEvent.altKey())
2223 modifierFlags |= PlatformEvent::AltKey;
2224 if (gestureEvent.ctrlKey())
2225 modifierFlags |= PlatformEvent::CtrlKey;
2226 if (gestureEvent.metaKey())
2227 modifierFlags |= PlatformEvent::MetaKey;
2228 if (gestureEvent.shiftKey())
2229 modifierFlags |= PlatformEvent::ShiftKey;
2230 PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2232 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2233 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2234 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2235 handleMouseMoveEvent(fakeMouseMove);
2237 bool defaultPrevented = false;
2238 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2239 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2240 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2241 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2243 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2244 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2245 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2246 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2248 return defaultPrevented;
2251 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2253 m_longTapShouldInvokeContextMenu = false;
2254 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2255 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2256 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2257 m_mouseDown = mouseDownEvent;
2259 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2260 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2261 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2262 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2263 m_didStartDrag = false;
2264 m_mouseDownMayStartDrag = true;
2265 dragState().m_dragSrc = nullptr;
2266 m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2267 RefPtr<FrameView> protector(m_frame->view());
2268 handleDrag(mev, DontCheckDragHysteresis);
2269 if (m_didStartDrag) {
2270 m_longTapShouldInvokeContextMenu = true;
2275 bool shouldLongPressSelectWord = true;
2277 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2279 if (shouldLongPressSelectWord) {
2280 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2281 HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2282 Node* innerNode = result.targetNode();
2283 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2284 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2285 if (m_frame->selection().isRange()) {
2286 focusDocumentView();
2291 return sendContextMenuEventForGesture(gestureEvent);
2294 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2297 if (m_longTapShouldInvokeContextMenu) {
2298 m_longTapShouldInvokeContextMenu = false;
2299 return sendContextMenuEventForGesture(gestureEvent);
2305 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2306 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2307 RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : 0;
2308 IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2309 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2310 m_resizeScrollableArea = layer->scrollableArea();
2311 m_resizeScrollableArea->setInResizeMode(true);
2312 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2315 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2316 gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2317 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2318 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2321 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2322 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2323 m_resizeScrollableArea->setInResizeMode(false);
2324 m_resizeScrollableArea = 0;
2332 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2334 return sendContextMenuEventForGesture(gestureEvent);
2337 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2342 if (!widget->isFrameView())
2345 return toFrameView(widget)->frame().eventHandler().handleGestureEvent(gestureEvent);
2348 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2350 if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2351 Widget* widget = toRenderWidget(renderer)->widget();
2352 return widget && passGestureEventToWidget(gestureEvent, widget);
2357 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2358 RefPtrWillBeRawPtr<Node> node = m_scrollGestureHandlingNode;
2359 clearGestureScrollNodes();
2362 passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2367 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2369 Document* document = m_frame->document();
2370 if (!document->renderView())
2373 FrameView* view = m_frame->view();
2377 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2378 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2379 HitTestResult result(viewPoint);
2380 document->renderView()->hitTest(request, result);
2382 m_lastHitTestResultOverWidget = result.isOverWidget();
2383 m_scrollGestureHandlingNode = result.innerNode();
2384 m_previousGestureScrolledNode = nullptr;
2386 // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2387 // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2388 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2389 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2391 if (!m_scrollGestureHandlingNode)
2394 passGestureEventToWidgetIfPossible(gestureEvent, m_scrollGestureHandlingNode->renderer());
2399 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2401 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2405 const float scaleFactor = m_frame->pageZoomFactor();
2406 delta.scale(1 / scaleFactor, 1 / scaleFactor);
2408 Node* node = m_scrollGestureHandlingNode.get();
2410 return sendScrollEventToView(gestureEvent, delta);
2412 // Ignore this event if the targeted node does not have a valid renderer.
2413 RenderObject* renderer = node->renderer();
2417 RefPtr<FrameView> protector(m_frame->view());
2420 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2422 // Try to send the event to the correct view.
2423 if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) {
2424 if(scrollShouldNotPropagate)
2425 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2430 if (scrollShouldNotPropagate)
2431 stopNode = m_previousGestureScrolledNode.get();
2433 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2434 ScrollGranularity granularity = ScrollByPixel;
2435 bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width());
2436 bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height());
2438 if (scrollShouldNotPropagate)
2439 m_previousGestureScrolledNode = stopNode;
2441 if (horizontalScroll || verticalScroll) {
2442 setFrameWasScrolledByUser();
2446 // Otherwise try to scroll the view.
2447 return sendScrollEventToView(gestureEvent, delta);
2450 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2452 FrameView* view = m_frame->view();
2456 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2457 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2458 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2459 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2460 scaledDelta.width(), scaledDelta.height(),
2461 scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2462 ScrollByPixelWheelEvent,
2463 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2464 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2466 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2468 setFrameWasScrolledByUser();
2470 return scrolledFrame;
2473 LocalFrame* EventHandler::getSubFrameForGestureEvent(const IntPoint& touchAdjustedPoint, const PlatformGestureEvent& gestureEvent)
2475 PlatformMouseEvent mouseDown(touchAdjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2476 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2477 HitTestRequest request(HitTestRequest::ReadOnly);
2478 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDown);
2479 return subframeForHitTestResult(mev);
2482 void EventHandler::clearGestureScrollNodes()
2484 m_scrollGestureHandlingNode = nullptr;
2485 m_previousGestureScrolledNode = nullptr;
2488 bool EventHandler::isScrollbarHandlingGestures() const
2490 return m_scrollbarHandlingScrollGesture.get();
2493 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2495 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2497 return !event.area().isEmpty();
2500 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2502 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2503 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2505 // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2506 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2507 // scrollbars being untouchable.
2508 if (result.scrollbar())
2511 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2512 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2513 copyToVector(result.rectBasedTestResult(), nodes);
2515 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2516 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2517 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2518 // handle targetNode being a shadow DOM node.
2520 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2521 // FIXME: targetNode and success are only used by Internals functions. We should
2522 // instead have dedicated test methods so we only do this work in tests.
2523 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> > (nodes));
2524 if (success && targetNode)
2525 targetNode = targetNode->deprecatedShadowAncestorNode();
2529 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2531 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2532 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2534 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2535 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2536 copyToVector(result.rectBasedTestResult(), nodes);
2538 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2539 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> >(nodes));
2542 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2544 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2545 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, touchRadius);
2547 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2548 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2549 copyToVector(result.rectBasedTestResult(), nodes);
2551 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2552 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> >(nodes));
2555 void EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2557 if (!shouldApplyTouchAdjustment(gestureEvent))
2560 Node* targetNode = 0;
2561 switch (gestureEvent.type()) {
2562 case PlatformEvent::GestureTap:
2563 case PlatformEvent::GestureTapUnconfirmed:
2564 case PlatformEvent::GestureTapDown:
2565 case PlatformEvent::GestureShowPress:
2566 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2568 case PlatformEvent::GestureLongPress:
2569 case PlatformEvent::GestureLongTap:
2570 case PlatformEvent::GestureTwoFingerTap:
2571 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2574 // FIXME: Implement handling for other types as needed.
2575 ASSERT_NOT_REACHED();
2579 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2581 Document* doc = m_frame->document();
2582 FrameView* v = m_frame->view();
2586 // Clear mouse press state to avoid initiating a drag while context menu is up.
2587 m_mousePressed = false;
2588 LayoutPoint viewportPos = v->windowToContents(event.position());
2589 HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2590 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2592 if (!m_frame->selection().contains(viewportPos)
2594 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2595 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2596 // available for text selections. But only if we're above text.
2597 && (m_frame->selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2598 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2600 if (mev.hitTestResult().isMisspelled())
2601 selectClosestMisspellingFromMouseEvent(mev);
2602 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2603 selectClosestWordOrLinkFromMouseEvent(mev);
2606 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.targetNode(), 0, event, false);
2609 bool EventHandler::sendContextMenuEventForKey()
2611 FrameView* view = m_frame->view();
2615 Document* doc = m_frame->document();
2619 // Clear mouse press state to avoid initiating a drag while context menu is up.
2620 m_mousePressed = false;
2622 static const int kContextMenuMargin = 1;
2625 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2627 int rightAligned = 0;
2631 Element* focusedElement = doc->focusedElement();
2632 FrameSelection& selection = m_frame->selection();
2633 Position start = selection.selection().start();
2634 bool shouldTranslateToRootView = true;
2636 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2637 RefPtrWillBeRawPtr<Range> selectionRange = selection.toNormalizedRange();
2638 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2640 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2641 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2642 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2643 location = IntPoint(x, y);
2644 } else if (focusedElement) {
2645 IntRect clippedRect = focusedElement->boundsInRootViewSpace();
2646 location = IntPoint(clippedRect.center());
2648 location = IntPoint(
2649 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2650 kContextMenuMargin);
2651 shouldTranslateToRootView = false;
2654 m_frame->view()->setCursor(pointerCursor());
2656 IntPoint position = shouldTranslateToRootView ? view->contentsToRootView(location) : location;
2657 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2659 Node* targetNode = doc->focusedElement();
2663 // Use the focused node as the target for hover and active.
2664 HitTestResult result(position);
2665 result.setInnerNode(targetNode);
2666 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, result.innerElement());
2668 // The contextmenu event is a mouse event even when invoked using the keyboard.
2669 // This is required for web compatibility.
2672 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2674 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2677 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2679 handleMousePressEvent(mouseEvent);
2680 return sendContextMenuEvent(mouseEvent);
2683 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2686 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2688 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2691 IntPoint adjustedPoint = event.position();
2692 adjustGesturePosition(event, adjustedPoint);
2693 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2694 // To simulate right-click behavior, we send a right mouse down and then
2695 // context menu event.
2696 handleMousePressEvent(mouseEvent);
2697 return sendContextMenuEvent(mouseEvent);
2698 // We do not need to send a corresponding mouse release because in case of
2699 // right-click, the context menu takes capture and consumes all events.
2702 void EventHandler::scheduleHoverStateUpdate()
2704 if (!m_hoverTimer.isActive())
2705 m_hoverTimer.startOneShot(0, FROM_HERE);
2708 void EventHandler::scheduleCursorUpdate()
2710 if (!m_cursorUpdateTimer.isActive())
2711 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
2714 void EventHandler::dispatchFakeMouseMoveEventSoon()
2719 if (m_mousePositionIsUnknown)
2722 Settings* settings = m_frame->settings();
2723 if (settings && !settings->deviceSupportsMouse())
2726 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2727 // reschedule the timer and use a longer time. This will cause the content
2728 // to receive these moves only after the user is done scrolling, reducing
2729 // pauses during the scroll.
2730 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2731 if (m_fakeMouseMoveEventTimer.isActive())
2732 m_fakeMouseMoveEventTimer.stop();
2733 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_HERE);
2735 if (!m_fakeMouseMoveEventTimer.isActive())
2736 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, FROM_HERE);
2740 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2742 FrameView* view = m_frame->view();
2746 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2749 dispatchFakeMouseMoveEventSoon();
2752 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2754 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2755 ASSERT(!m_mousePressed);
2757 Settings* settings = m_frame->settings();
2758 if (settings && !settings->deviceSupportsMouse())
2761 FrameView* view = m_frame->view();
2765 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2768 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2769 if (!isCursorVisible())
2776 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2777 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2778 handleMouseMoveEvent(fakeMouseMoveEvent);
2781 void EventHandler::cancelFakeMouseMoveEvent()
2783 m_fakeMouseMoveEventTimer.stop();
2786 bool EventHandler::isCursorVisible() const
2788 return m_frame->page()->isCursorVisible();
2791 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2793 m_frameSetBeingResized = frameSet;
2796 void EventHandler::resizeScrollableAreaDestroyed()
2798 ASSERT(m_resizeScrollableArea);
2799 m_resizeScrollableArea = 0;
2802 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2804 m_hoverTimer.stop();
2807 ASSERT(m_frame->document());
2809 if (RenderView* renderer = m_frame->contentRenderer()) {
2810 if (FrameView* view = m_frame->view()) {
2811 HitTestRequest request(HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2812 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2813 renderer->hitTest(request, result);
2814 m_frame->document()->updateHoverActiveState(request, result.innerElement());
2819 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
2821 m_activeIntervalTimer.stop();
2824 && m_frame->document()
2825 && m_lastDeferredTapElement) {
2826 // FIXME: Enable condition when http://crbug.com/226842 lands
2827 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2828 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
2829 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
2831 m_lastDeferredTapElement = nullptr;
2834 void EventHandler::notifyElementActivated()
2836 // Since another element has been set to active, stop current timer and clear reference.
2837 if (m_activeIntervalTimer.isActive())
2838 m_activeIntervalTimer.stop();
2839 m_lastDeferredTapElement = nullptr;
2842 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2844 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2845 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2846 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2847 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2848 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2849 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2851 String key = evt.unmodifiedText();
2852 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2855 elem->accessKeyAction(false);
2859 bool EventHandler::isKeyEventAllowedInFullScreen(FullscreenElementStack* fullscreen, const PlatformKeyboardEvent& keyEvent) const
2861 if (fullscreen->webkitFullScreenKeyboardInputAllowed())
2864 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2865 if (keyEvent.text().length() != 1)
2867 UChar character = keyEvent.text()[0];
2868 return character == ' ';
2871 int keyCode = keyEvent.windowsVirtualKeyCode();
2872 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2873 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2874 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2875 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2878 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2880 RefPtr<FrameView> protector(m_frame->view());
2882 ASSERT(m_frame->document());
2883 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(*m_frame->document())) {
2884 if (fullscreen->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent))
2888 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2889 capsLockStateMayHaveChanged();
2892 if (panScrollInProgress()) {
2893 // If a key is pressed while the panScroll is in progress then we want to stop
2894 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2897 // If we were in panscroll mode, we swallow the key event
2902 // Check for cases where we are too early for events -- possible unmatched key up
2903 // from pressing return in the location bar.
2904 RefPtrWillBeRawPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2908 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2910 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2911 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2912 // with access keys. Then we dispatch keydown, but suppress its default handling.
2913 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2914 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2915 bool matchedAnAccessKey = false;
2916 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2917 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2919 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2920 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2921 return !node->dispatchKeyEvent(initialKeyEvent);
2923 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2924 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2925 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
2926 RefPtrWillBeRawPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
2927 if (matchedAnAccessKey)
2928 keydown->setDefaultPrevented(true);
2929 keydown->setTarget(node);
2931 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2932 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2933 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2934 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2935 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2938 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2939 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2940 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2941 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2943 return keydownResult;
2945 // Focus may have changed during keydown handling, so refetch node.
2946 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2947 node = eventTargetNodeForDocument(m_frame->document());
2951 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2952 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
2953 if (keyPressEvent.text().isEmpty())
2954 return keydownResult;
2955 RefPtrWillBeRawPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
2956 keypress->setTarget(node);
2958 keypress->setDefaultPrevented(true);
2959 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
2961 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2964 static FocusType focusDirectionForKey(const AtomicString& keyIdentifier)
2966 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
2967 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
2968 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
2969 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
2971 FocusType retVal = FocusTypeNone;
2973 if (keyIdentifier == Down)
2974 retVal = FocusTypeDown;
2975 else if (keyIdentifier == Up)
2976 retVal = FocusTypeUp;
2977 else if (keyIdentifier == Left)
2978 retVal = FocusTypeLeft;
2979 else if (keyIdentifier == Right)
2980 retVal = FocusTypeRight;
2985 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2987 if (event->type() == EventTypeNames::keydown) {
2988 m_frame->editor().handleKeyboardEvent(event);
2989 if (event->defaultHandled())
2991 if (event->keyIdentifier() == "U+0009")
2992 defaultTabEventHandler(event);
2993 else if (event->keyIdentifier() == "U+0008")
2994 defaultBackspaceEventHandler(event);
2995 else if (event->keyIdentifier() == "U+001B")
2996 defaultEscapeEventHandler(event);
2998 FocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
2999 if (type != FocusTypeNone)
3000 defaultArrowEventHandler(type, event);
3003 if (event->type() == EventTypeNames::keypress) {
3004 m_frame->editor().handleKeyboardEvent(event);
3005 if (event->defaultHandled())
3007 if (event->charCode() == ' ')
3008 defaultSpaceEventHandler(event);
3012 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
3014 return dragHysteresisExceeded(flooredIntPoint(floatDragViewportLocation));
3017 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
3019 FrameView* view = m_frame->view();
3022 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
3023 IntSize delta = dragLocation - m_mouseDownPos;
3025 int threshold = GeneralDragHysteresis;
3026 switch (dragState().m_dragType) {
3027 case DragSourceActionSelection:
3028 threshold = TextDragHysteresis;
3030 case DragSourceActionImage:
3031 threshold = ImageDragHysteresis;
3033 case DragSourceActionLink:
3034 threshold = LinkDragHysteresis;
3036 case DragSourceActionDHTML:
3038 case DragSourceActionNone:
3039 ASSERT_NOT_REACHED();
3042 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3045 void EventHandler::freeClipboard()
3047 if (dragState().m_dragClipboard) {
3048 dragState().m_dragClipboard->clearDragImage();
3049 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3053 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3055 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3056 HitTestRequest request(HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3057 prepareMouseEvent(request, event);
3059 if (dragState().m_dragSrc) {
3060 dragState().m_dragClipboard->setDestinationOperation(operation);
3061 // for now we don't care if event handler cancels default behavior, since there is none
3062 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3065 dragState().m_dragSrc = nullptr;
3066 // In case the drag was ended due to an escape key press we need to ensure
3067 // that consecutive mousemove events don't reinitiate the drag and drop.
3068 m_mouseDownMayStartDrag = false;
3071 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3073 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3074 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3075 dragState().m_dragSrc = rootEditableElement;
3078 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3079 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3081 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3084 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3086 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3087 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3088 // events, causing page/FrameView to go away.
3090 ASSERT(m_frame->view());
3091 if (!m_frame->page())
3094 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3095 // If we allowed the other side of the bridge to handle a drag
3096 // last time, then m_mousePressed might still be set. So we
3097 // clear it now to make sure the next move after a drag
3098 // doesn't look like a drag.
3099 m_mousePressed = false;
3103 if (m_mouseDownMayStartDrag) {
3104 HitTestRequest request(HitTestRequest::ReadOnly);
3105 HitTestResult result(m_mouseDownPos);
3106 m_frame->contentRenderer()->hitTest(request, result);
3107 Node* node = result.innerNode();
3109 DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3110 ? DragController::DelayedSelectionDragResolution
3111 : DragController::ImmediateSelectionDragResolution;
3112 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3114 dragState().m_dragSrc = nullptr;
3117 if (!dragState().m_dragSrc)
3118 m_mouseDownMayStartDrag = false; // no element is draggable
3121 if (!m_mouseDownMayStartDrag)
3122 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3124 // We are starting a text/image/url drag, so the cursor should be an arrow
3125 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3126 m_frame->view()->setCursor(pointerCursor());
3128 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3131 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3134 if (!tryStartDrag(event)) {
3135 // Something failed to start the drag, clean up.
3137 dragState().m_dragSrc = nullptr;
3140 m_mouseDownMayStartDrag = false;
3141 // Whether or not the drag actually started, no more default handling (like selection).
3145 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3147 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3148 // to make sure it gets numbified
3149 dragState().m_dragClipboard = createDraggingClipboard();
3151 // Check to see if this a DOM based drag, if it is get the DOM specified drag
3153 if (dragState().m_dragType == DragSourceActionDHTML) {
3154 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3155 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), UseTransforms);
3156 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3157 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3159 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3160 // the element in some way. In this case we just kill the drag.
3165 DragController& dragController = m_frame->page()->dragController();
3166 if (!dragController.populateDragClipboard(m_frame, dragState(), m_mouseDownPos))
3168 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3169 && !m_frame->selection().isInPasswordField();
3171 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3172 // image can still be changed as we drag, but not the pasteboard data.
3173 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3175 if (m_mouseDownMayStartDrag) {
3176 // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3177 m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3178 // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3179 // whether or not the drag started, but perhaps it can simply use the return value from
3180 // handleDrag(), even though it doesn't mean exactly the same thing.
3183 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3184 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3190 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3192 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3193 // and avoid dispatching text input events from keydown default handlers.
3194 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3199 EventTarget* target;
3200 if (underlyingEvent)
3201 target = underlyingEvent->target();
3203 target = eventTargetNodeForDocument(m_frame->document());
3207 RefPtrWillBeRawPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3208 event->setUnderlyingEvent(underlyingEvent);
3210 target->dispatchEvent(event, IGNORE_EXCEPTION);
3211 return event->defaultHandled();
3214 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3216 if (m_frame->editor().handleTextEvent(event))
3217 event->setDefaultHandled();
3220 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3222 ASSERT(event->type() == EventTypeNames::keypress);
3224 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3227 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3228 if (scroll(direction, ScrollByPage)) {
3229 event->setDefaultHandled();
3233 FrameView* view = m_frame->view();
3237 if (view->scroll(direction, ScrollByPage))
3238 event->setDefaultHandled();
3241 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3243 ASSERT(event->type() == EventTypeNames::keydown);
3245 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3248 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3251 Page* page = m_frame->page();
3252 if (!page || !page->mainFrame()->isLocalFrame())
3254 bool handledEvent = page->deprecatedLocalMainFrame()->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3256 event->setDefaultHandled();
3259 void EventHandler::defaultArrowEventHandler(FocusType focusType, KeyboardEvent* event)
3261 ASSERT(event->type() == EventTypeNames::keydown);
3263 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3266 Page* page = m_frame->page();
3270 if (!isSpatialNavigationEnabled(m_frame))
3273 // Arrows and other possible directional navigation keys can be used in design
3275 if (m_frame->document()->inDesignMode())
3278 if (page->focusController().advanceFocus(focusType))
3279 event->setDefaultHandled();
3282 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3284 ASSERT(event->type() == EventTypeNames::keydown);
3286 // We should only advance focus on tabs if no special modifier keys are held down.
3287 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3290 Page* page = m_frame->page();
3293 if (!page->tabKeyCyclesThroughElements())
3296 FocusType focusType = event->shiftKey() ? FocusTypeBackward : FocusTypeForward;
3298 // Tabs can be used in design mode editing.
3299 if (m_frame->document()->inDesignMode())
3302 if (page->focusController().advanceFocus(focusType))
3303 event->setDefaultHandled();
3306 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3308 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3309 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3312 void EventHandler::capsLockStateMayHaveChanged()
3314 if (Element* element = m_frame->document()->focusedElement()) {
3315 if (RenderObject* r = element->renderer()) {
3316 if (r->isTextField())
3317 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3322 void EventHandler::setFrameWasScrolledByUser()
3324 if (FrameView* view = m_frame->view())
3325 view->setWasScrolledByUser(true);
3328 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev)
3330 // First try to use the frame scrollbar.
3331 FrameView* view = m_frame->view();
3332 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mev.event().position()) : 0;
3334 // Then try the scrollbar in the hit test.
3336 scrollbar = mev.scrollbar();
3338 updateLastScrollbarUnderMouse(scrollbar, true);
3340 if (!scrollbar || !scrollbar->enabled())
3342 setFrameWasScrolledByUser();
3343 scrollbar->mouseDown(mev.event());
3347 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3348 // last to scrollbar if setLast is true; else set last to 0.
3349 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3351 if (m_lastScrollbarUnderMouse != scrollbar) {
3352 // Send mouse exited to the old scrollbar.
3353 if (m_lastScrollbarUnderMouse)
3354 m_lastScrollbarUnderMouse->mouseExited();
3356 // Send mouse entered if we're setting a new scrollbar.
3357 if (scrollbar && setLast)
3358 scrollbar->mouseEntered();
3360 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3364 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3367 case PlatformTouchPoint::TouchReleased:
3368 return EventTypeNames::touchend;
3369 case PlatformTouchPoint::TouchCancelled:
3370 return EventTypeNames::touchcancel;
3371 case PlatformTouchPoint::TouchPressed:
3372 return EventTypeNames::touchstart;
3373 case PlatformTouchPoint::TouchMoved:
3374 return EventTypeNames::touchmove;
3375 case PlatformTouchPoint::TouchStationary:
3376 // TouchStationary state is not converted to touch events, so fall through to assert.
3378 ASSERT_NOT_REACHED();
3383 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3385 HitTestResult result(point);
3387 if (!frame || !frame->contentRenderer())
3389 if (frame->view()) {
3390 IntRect rect = frame->view()->visibleContentRect();
3391 if (!rect.contains(roundedIntPoint(point)))
3394 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3398 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3400 TRACE_EVENT0("webkit", "EventHandler::handleTouchEvent");
3402 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3405 bool freshTouchEvents = true;
3406 bool allTouchReleased = true;
3407 for (i = 0; i < points.size(); ++i) {
3408 const PlatformTouchPoint& point = points[i];
3409 if (point.state() != PlatformTouchPoint::TouchPressed)
3410 freshTouchEvents = false;
3411 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3412 allTouchReleased = false;
3414 if (freshTouchEvents) {
3415 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3416 // have cleared the active document when we saw the last release. But we
3417 // have some tests that violate this, ClusterFuzz could trigger it, and
3418 // there may be cases where the browser doesn't reliably release all
3419 // touches. http://crbug.com/345372 tracks this.
3420 m_touchSequenceDocument.clear();
3421 m_touchSequenceUserGestureToken.clear();
3424 OwnPtr<UserGestureIndicator> gestureIndicator;
3426 if (m_touchSequenceUserGestureToken)
3427 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequenceUserGestureToken.release()));
3429 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
3431 m_touchSequenceUserGestureToken = gestureIndicator->currentToken();
3433 ASSERT(m_frame->view());
3434 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touchSequenceDocument->frame()->view())) {
3435 // If the active touch document has no frame or view, it's probably being destroyed
3436 // so we can't dispatch events.
3440 // First do hit tests for any new touch points.
3441 for (i = 0; i < points.size(); ++i) {
3442 const PlatformTouchPoint& point = points[i];
3444 // Touch events implicitly capture to the touched node, and don't change
3445 // active/hover states themselves (Gesture events do). So we only need
3446 // to hit-test on touchstart, and it can be read-only.
3447 if (point.state() == PlatformTouchPoint::TouchPressed) {
3448 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3449 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->windowToContents(point.pos()));
3450 HitTestResult result;
3451 if (!m_touchSequenceDocument) {
3452 result = hitTestResultAtPoint(pagePoint, hitType);
3453 } else if (m_touchSequenceDocument->frame()) {
3454 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocument->frame()->view()->windowToContents(point.pos()));
3455 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), framePoint, hitType);
3459 Node* node = result.innerNode();
3463 // Touch events should not go to text nodes
3464 if (node->isTextNode())
3465 node = NodeRenderingTraversal::parent(node);
3467 if (!m_touchSequenceDocument) {
3468 // Keep track of which document should receive all touch events
3469 // in the active sequence. This must be a single document to
3470 // ensure we don't leak Nodes between documents.
3471 m_touchSequenceDocument = &(result.innerNode()->document());
3472 ASSERT(m_touchSequenceDocument->frame()->view());
3475 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3476 // since we shouldn't get a touchstart for a touch that's already
3477 // down. However EventSender allows this to be violated and there's
3478 // some tests that take advantage of it. There may also be edge
3479 // cases in the browser where this happens.
3480 // See http://crbug.com/345372.
3481 m_targetForTouchID.set(point.id(), node);
3483 TouchAction effectiveTouchAction = computeEffectiveTouchAction(*node);
3484 if (effectiveTouchAction != TouchActionAuto)
3485 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3489 m_touchPressed = !allTouchReleased;
3491 // If there's no document receiving touch events, or no handlers on the
3492 // document set to receive the events, then we can skip all the rest of
3494 if (!m_touchSequenceDocument || !m_touchSequenceDocument->hasTouchEventHandlers() || !m_touchSequenceDocument->frame()) {
3495 if (allTouchReleased) {
3496 m_touchSequenceDocument.clear();
3497 m_touchSequenceUserGestureToken.clear();
3502 // Build up the lists to use for the 'touches', 'targetTouches' and
3503 // 'changedTouches' attributes in the JS event. See
3504 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3505 // lists fit together.
3507 // Holds the complete set of touches on the screen.
3508 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3510 // A different view on the 'touches' list above, filtered and grouped by
3511 // event target. Used for the 'targetTouches' list in the JS event.
3512 typedef WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList> > TargetTouchesHeapMap;
3513 TargetTouchesHeapMap touchesByTarget;
3515 // Array of touches per state, used to assemble the 'changedTouches' list.
3516 typedef WillBeHeapHashSet<RefPtrWillBeMember<EventTarget> > EventTargetSet;
3518 // The touches corresponding to the particular change state this struct
3519 // instance represents.
3520 RefPtrWillBeMember<TouchList> m_touches;
3521 // Set of targets involved in m_touches.
3522 EventTargetSet m_targets;
3523 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3525 for (i = 0; i < points.size(); ++i) {
3526 const PlatformTouchPoint& point = points[i];
3527 PlatformTouchPoint::State pointState = point.state();
3528 RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr;
3530 if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3531 // The target should be the original target for this touch, so get
3532 // it from the hashmap. As it's a release or cancel we also remove
3534 touchTarget = m_targetForTouchID.take(point.id());
3536 // No hittest is performed on move or stationary, since the target
3537 // is not allowed to change anyway.
3538 touchTarget = m_targetForTouchID.get(point.id());
3541 LocalFrame* targetFrame;
3544 Document& doc = touchTarget->toNode()->document();
3545 ASSERT(&doc == m_touchSequenceDocument.get());
3546 targetFrame = doc.frame();
3549 // If we don't have a target registered for the point it means we've
3550 // missed our opportunity to do a hit test for it (due to some
3551 // optimization that prevented blink from ever seeing the
3552 // touchstart), or that the touch started outside the active touch
3553 // sequence document. We should still include the touch in the
3554 // Touches list reported to the application (eg. so it can
3555 // differentiate between a one and two finger gesture), but we won't
3556 // actually dispatch any events for it. Set the target to the
3557 // Document so that there's some valid node here. Perhaps this
3558 // should really be LocalDOMWindow, but in all other cases the target of
3559 // a Touch is a Node so using the window could be a breaking change.
3560 // Since we know there was no handler invoked, the specific target
3561 // should be completely irrelevant to the application.
3562 // FIXME: Oilpan: We can remove the following .get() if EventTarget
3564 touchTarget = m_touchSequenceDocument.get();
3565 targetFrame = m_touchSequenceDocument->frame();
3566 knownTarget = false;
3568 ASSERT(targetFrame);
3570 // pagePoint should always be relative to the target elements
3571 // containing frame.
3572 FloatPoint pagePoint = targetFrame->view()->windowToContents(point.pos());
3574 float scaleFactor = 1.0f / targetFrame->pageZoomFactor();
3576 FloatPoint adjustedPagePoint = pagePoint.scaledBy(scaleFactor);
3577 FloatSize adjustedRadius = point.radius().scaledBy(scaleFactor);
3579 RefPtrWillBeRawPtr<Touch> touch = Touch::create(
3580 targetFrame, touchTarget.get(), point.id(), point.screenPos(), adjustedPagePoint, adjustedRadius, point.rotationAngle(), point.force());
3582 // Ensure this target's touch list exists, even if it ends up empty, so
3583 // it can always be passed to TouchEvent::Create below.
3584 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3585 if (targetTouchesIterator == touchesByTarget.end()) {
3586 touchesByTarget.set(touchTarget.get(), TouchList::create());
3587 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3590 // touches and targetTouches should only contain information about
3591 // touches still on the screen, so if this point is released or
3592 // cancelled it will only appear in the changedTouches list.
3593 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3594 touches->append(touch);
3595 targetTouchesIterator->value->append(touch);
3598 // Now build up the correct list for changedTouches.
3599 // Note that any touches that are in the TouchStationary state (e.g. if
3600 // the user had several points touched but did not move them all) should
3601 // never be in the changedTouches list so we do not handle them
3602 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
3603 // for further discussion about the TouchStationary state.
3604 if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) {
3605 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3606 if (!changedTouches[pointState].m_touches)
3607 changedTouches[pointState].m_touches = TouchList::create();
3608 changedTouches[pointState].m_touches->append(touch);
3609 changedTouches[pointState].m_targets.add(touchTarget);
3612 if (allTouchReleased) {
3613 m_touchSequenceDocument.clear();
3614 m_touchSequenceUserGestureToken.clear();
3617 // Now iterate the changedTouches list and m_targets within it, sending
3618 // events to the targets as required.
3619 bool swallowedEvent = false;
3620 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3621 if (!changedTouches[state].m_touches)
3624 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3625 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3626 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3627 EventTarget* touchEventTarget = it->get();
3628 RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create(
3629 touches.get(), touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(),
3630 stateName, touchEventTarget->toNode()->document().domWindow(),
3631 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.cancelable());
3632 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3633 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3637 return swallowedEvent;
3640 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
3642 if (action1 == TouchActionNone || action2 == TouchActionNone)
3643 return TouchActionNone;
3644 if (action1 == TouchActionAuto)
3646 if (action2 == TouchActionAuto)
3648 if (!(action1 & action2))
3649 return TouchActionNone;
3650 return action1 & action2;
3653 TouchAction EventHandler::computeEffectiveTouchAction(const Node& node)
3655 // Optimization to minimize risk of this new feature (behavior should be identical
3656 // since there's no way to get non-default touch-action values).
3657 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
3658 return TouchActionAuto;
3660 // Start by permitting all actions, then walk the elements supporting
3661 // touch-action from the target node up to the nearest scrollable ancestor
3662 // and exclude any prohibited actions.
3663 TouchAction effectiveTouchAction = TouchActionAuto;
3664 for (const Node* curNode = &node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3665 if (RenderObject* renderer = curNode->renderer()) {
3666 if (renderer->supportsTouchAction()) {
3667 TouchAction action = renderer->style()->touchAction();
3668 effectiveTouchAction = intersectTouchAction(action, effectiveTouchAction);
3669 if (effectiveTouchAction == TouchActionNone)
3673 // If we've reached an ancestor that supports a touch action, search no further.
3674 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3678 return effectiveTouchAction;
3681 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3683 m_mousePositionIsUnknown = false;
3684 m_lastKnownMousePosition = event.position();
3685 m_lastKnownMouseGlobalPosition = event.globalPosition();
3688 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3690 // If we're clicking into a frame that is selected, the frame will appear
3691 // greyed out even though we're clicking on the selection. This looks
3692 // really strange (having the whole frame be greyed out), so we deselect the
3694 IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3695 if (m_frame->selection().contains(p)) {
3696 VisiblePosition visiblePos(
3697 mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
3698 VisibleSelection newSelection(visiblePos);
3699 m_frame->selection().setSelection(newSelection);
3702 subframe->eventHandler().handleMousePressEvent(mev.event());
3706 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe, HitTestResult* hoveredNode)
3708 if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
3710 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3714 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3716 subframe->eventHandler().handleMouseReleaseEvent(mev.event());
3720 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
3722 // We can sometimes get a null widget! EventHandlerMac handles a null
3723 // widget by returning false, so we do the same.
3727 // If not a FrameView, then probably a plugin widget. Those will receive
3728 // the event via an EventTargetNode dispatch when this returns false.
3729 if (!widget->isFrameView())
3732 return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
3735 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
3737 // Figure out which view to send the event to.
3738 if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
3743 PassRefPtrWillBeRawPtr<Clipboard> EventHandler::createDraggingClipboard() const
3745 return Clipboard::create(Clipboard::DragAndDrop, ClipboardWritable, DataObject::create());
3748 void EventHandler::focusDocumentView()
3750 Page* page = m_frame->page();
3753 page->focusController().focusDocumentView(m_frame);
3756 unsigned EventHandler::accessKeyModifiers()
3759 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
3761 return PlatformEvent::AltKey;
3765 } // namespace WebCore