2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "core/page/EventHandler.h"
31 #include "HTMLNames.h"
32 #include "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ExceptionStatePlaceholder.h"
35 #include "core/clipboard/Clipboard.h"
36 #include "core/clipboard/DataObject.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/DocumentMarkerController.h"
39 #include "core/dom/FullscreenElementStack.h"
40 #include "core/dom/NodeRenderingTraversal.h"
41 #include "core/dom/TouchList.h"
42 #include "core/dom/shadow/ShadowRoot.h"
43 #include "core/editing/Editor.h"
44 #include "core/editing/FrameSelection.h"
45 #include "core/editing/TextIterator.h"
46 #include "core/editing/htmlediting.h"
47 #include "core/events/DOMWindowEventQueue.h"
48 #include "core/events/EventPath.h"
49 #include "core/events/KeyboardEvent.h"
50 #include "core/events/MouseEvent.h"
51 #include "core/events/TextEvent.h"
52 #include "core/events/TouchEvent.h"
53 #include "core/events/WheelEvent.h"
54 #include "core/fetch/ImageResource.h"
55 #include "core/frame/FrameView.h"
56 #include "core/frame/LocalFrame.h"
57 #include "core/html/HTMLDialogElement.h"
58 #include "core/html/HTMLFrameElementBase.h"
59 #include "core/html/HTMLFrameSetElement.h"
60 #include "core/html/HTMLInputElement.h"
61 #include "core/loader/FrameLoader.h"
62 #include "core/loader/FrameLoaderClient.h"
63 #include "core/page/AutoscrollController.h"
64 #include "core/page/BackForwardClient.h"
65 #include "core/page/Chrome.h"
66 #include "core/page/ChromeClient.h"
67 #include "core/page/DragController.h"
68 #include "core/page/DragState.h"
69 #include "core/page/EditorClient.h"
70 #include "core/page/FocusController.h"
71 #include "core/page/FrameTree.h"
72 #include "core/inspector/InspectorController.h"
73 #include "core/page/MouseEventWithHitTestResults.h"
74 #include "core/page/Page.h"
75 #include "core/frame/Settings.h"
76 #include "core/page/SpatialNavigation.h"
77 #include "core/page/TouchAdjustment.h"
78 #include "core/rendering/HitTestRequest.h"
79 #include "core/rendering/HitTestResult.h"
80 #include "core/rendering/RenderFlowThread.h"
81 #include "core/rendering/RenderLayer.h"
82 #include "core/rendering/RenderTextControlSingleLine.h"
83 #include "core/rendering/RenderView.h"
84 #include "core/rendering/RenderWidget.h"
85 #include "core/rendering/style/CursorList.h"
86 #include "core/rendering/style/RenderStyle.h"
87 #include "core/svg/SVGDocumentExtensions.h"
88 #include "core/svg/SVGUseElement.h"
89 #include "platform/PlatformGestureEvent.h"
90 #include "platform/PlatformKeyboardEvent.h"
91 #include "platform/PlatformTouchEvent.h"
92 #include "platform/PlatformWheelEvent.h"
93 #include "platform/WindowsKeyboardCodes.h"
94 #include "platform/geometry/FloatPoint.h"
95 #include "platform/graphics/Image.h"
96 #include "platform/heap/Handle.h"
97 #include "platform/scroll/ScrollAnimator.h"
98 #include "platform/scroll/Scrollbar.h"
99 #include "wtf/Assertions.h"
100 #include "wtf/CurrentTime.h"
101 #include "wtf/StdLibExtras.h"
102 #include "wtf/TemporaryChange.h"
106 using namespace HTMLNames;
107 using namespace SVGNames;
109 // The link drag hysteresis is much larger than the others because there
110 // needs to be enough space to cancel the link press without starting a link drag,
111 // and because dragging links is rare.
112 static const int LinkDragHysteresis = 40;
113 static const int ImageDragHysteresis = 5;
114 static const int TextDragHysteresis = 3;
115 static const int GeneralDragHysteresis = 3;
117 // The amount of time to wait before sending a fake mouse event, triggered
118 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
119 // otherwise the long interval is used.
120 static const double fakeMouseMoveShortInterval = 0.1;
121 static const double fakeMouseMoveLongInterval = 0.250;
123 // The amount of time to wait for a cursor update on style and layout changes
124 // Set to 50Hz, no need to be faster than common screen refresh rate
125 static const double cursorUpdateInterval = 0.02;
127 static const int maximumCursorSize = 128;
129 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
130 // need to ensure here is that the scale isn't so small that integer overflow can occur when
131 // dividing cursor sizes (limited above) by the scale.
132 static const double minimumCursorScale = 0.001;
134 // The minimum amount of time an element stays active after a ShowPress
135 // This is roughly 9 frames, which should be long enough to be noticeable.
136 static const double minimumActiveInterval = 0.15;
139 static const double TextDragDelay = 0.15;
141 static const double TextDragDelay = 0.0;
144 enum NoCursorChangeType { NoCursorChange };
146 class OptionalCursor {
148 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
149 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
151 bool isCursorChange() const { return m_isCursorChange; }
152 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
155 bool m_isCursorChange;
159 class MaximumDurationTracker {
161 explicit MaximumDurationTracker(double *maxDuration)
162 : m_maxDuration(maxDuration)
163 , m_start(monotonicallyIncreasingTime())
167 ~MaximumDurationTracker()
169 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
173 double* m_maxDuration;
177 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
180 case WheelEvent::DOM_DELTA_PAGE:
182 case WheelEvent::DOM_DELTA_LINE:
184 case WheelEvent::DOM_DELTA_PIXEL:
185 return ScrollByPixel;
187 return ScrollByPixel;
191 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
192 // If a mouse event handler changes the input element type to one that has a widget associated,
193 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
194 // event target node can't still be the shadow node.
195 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
197 Node* targetNode = mev.targetNode();
198 if (!targetNode || !targetNode->parentNode())
200 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host());
203 EventHandler::EventHandler(LocalFrame* frame)
205 , m_mousePressed(false)
206 , m_capturesDragging(false)
207 , m_mouseDownMayStartSelect(false)
208 , m_mouseDownMayStartDrag(false)
209 , m_mouseDownWasSingleClickInSelection(false)
210 , m_selectionInitiationState(HaveNotStartedSelection)
211 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
212 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
213 , m_mouseDownMayStartAutoscroll(false)
214 , m_mouseDownWasInSubframe(false)
215 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
217 , m_resizeScrollableArea(0)
218 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
220 , m_shouldOnlyFireDragOverEvent(false)
221 , m_mousePositionIsUnknown(true)
222 , m_mouseDownTimestamp(0)
223 , m_widgetIsLatched(false)
224 , m_touchPressed(false)
225 , m_scrollGestureHandlingNode(nullptr)
226 , m_lastHitTestResultOverWidget(false)
227 , m_maxMouseMovedDuration(0)
228 , m_baseEventType(PlatformEvent::NoType)
229 , m_didStartDrag(false)
230 , m_longTapShouldInvokeContextMenu(false)
231 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
232 , m_lastShowPressTimestamp(0)
236 EventHandler::~EventHandler()
238 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
241 DragState& EventHandler::dragState()
244 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState()));
247 DEFINE_STATIC_LOCAL(DragState, state, ());
252 void EventHandler::clear()
255 m_cursorUpdateTimer.stop();
256 m_fakeMouseMoveEventTimer.stop();
257 m_activeIntervalTimer.stop();
258 m_resizeScrollableArea = 0;
259 m_nodeUnderMouse = nullptr;
260 m_lastNodeUnderMouse = nullptr;
261 m_lastMouseMoveEventSubframe = nullptr;
262 m_lastScrollbarUnderMouse = nullptr;
264 m_clickNode = nullptr;
265 m_frameSetBeingResized = nullptr;
266 m_dragTarget = nullptr;
267 m_shouldOnlyFireDragOverEvent = false;
268 m_mousePositionIsUnknown = true;
269 m_lastKnownMousePosition = IntPoint();
270 m_lastKnownMouseGlobalPosition = IntPoint();
271 m_lastMouseDownUserGestureToken.clear();
272 m_mousePressNode = nullptr;
273 m_mousePressed = false;
274 m_capturesDragging = false;
275 m_capturingMouseEventsNode = nullptr;
276 m_latchedWheelEventNode = nullptr;
277 m_previousWheelScrolledNode = nullptr;
278 m_targetForTouchID.clear();
279 m_touchSequenceDocument.clear();
280 m_scrollGestureHandlingNode = nullptr;
281 m_lastHitTestResultOverWidget = false;
282 m_previousGestureScrolledNode = nullptr;
283 m_scrollbarHandlingScrollGesture = nullptr;
284 m_maxMouseMovedDuration = 0;
285 m_baseEventType = PlatformEvent::NoType;
286 m_didStartDrag = false;
287 m_touchPressed = false;
288 m_mouseDownMayStartSelect = false;
289 m_mouseDownMayStartDrag = false;
290 m_lastShowPressTimestamp = 0;
291 m_lastDeferredTapElement = nullptr;
294 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
296 if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
298 if (nodeToBeRemoved.isInShadowTree()) {
299 m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
301 // We don't dispatch click events if the mousedown node is removed
302 // before a mouseup event. It is compatible with IE and Firefox.
303 m_clickNode = nullptr;
307 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
309 if (selection.selection() != newSelection)
310 selection.setSelection(newSelection);
313 static inline bool dispatchSelectStart(Node* node)
315 if (!node || !node->renderer())
318 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
321 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
323 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
324 if (!rootUserSelectAll)
327 VisibleSelection newSelection(selection);
328 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
329 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
334 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
336 if (Position::nodeIsUserSelectNone(targetNode))
339 if (!dispatchSelectStart(targetNode))
342 if (selection.isRange())
343 m_selectionInitiationState = ExtendedSelection;
345 granularity = CharacterGranularity;
346 m_selectionInitiationState = PlacedCaret;
349 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
354 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
356 Node* innerNode = result.targetNode();
357 VisibleSelection newSelection;
359 if (innerNode && innerNode->renderer()) {
360 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
361 if (pos.isNotNull()) {
362 newSelection = VisibleSelection(pos);
363 newSelection.expandUsingGranularity(WordGranularity);
366 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
367 newSelection.appendTrailingWhitespace();
369 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
373 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
375 Node* innerNode = result.targetNode();
376 VisibleSelection newSelection;
378 if (innerNode && innerNode->renderer()) {
379 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
380 Position start = pos.deepEquivalent();
381 Position end = pos.deepEquivalent();
382 if (pos.isNotNull()) {
383 Vector<DocumentMarker*> markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
384 if (markers.size() == 1) {
385 start.moveToOffset(markers[0]->startOffset());
386 end.moveToOffset(markers[0]->endOffset());
387 newSelection = VisibleSelection(start, end);
391 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
392 newSelection.appendTrailingWhitespace();
394 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
398 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
400 if (m_mouseDownMayStartSelect) {
401 selectClosestWordFromHitTestResult(result.hitTestResult(),
402 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
406 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
408 if (m_mouseDownMayStartSelect) {
409 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
410 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
414 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
416 if (!result.hitTestResult().isLiveLink())
417 return selectClosestWordFromMouseEvent(result);
419 Node* innerNode = result.targetNode();
421 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
422 VisibleSelection newSelection;
423 Element* URLElement = result.hitTestResult().URLElement();
424 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
425 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
426 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
428 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
432 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
434 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventDoubleClick");
436 if (event.event().button() != LeftButton)
439 if (m_frame->selection().isRange()) {
440 // A double-click when range is already selected
441 // should not change the selection. So, do not call
442 // selectClosestWordFromMouseEvent, but do set
443 // m_beganSelectingText to prevent handleMouseReleaseEvent
444 // from setting caret selection.
445 m_selectionInitiationState = ExtendedSelection;
447 selectClosestWordFromMouseEvent(event);
452 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
454 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventTripleClick");
456 if (event.event().button() != LeftButton)
459 Node* innerNode = event.targetNode();
460 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
463 VisibleSelection newSelection;
464 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
465 if (pos.isNotNull()) {
466 newSelection = VisibleSelection(pos);
467 newSelection.expandUsingGranularity(ParagraphGranularity);
470 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
473 static int textDistance(const Position& start, const Position& end)
475 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, end);
476 return TextIterator::rangeLength(range.get(), true);
479 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
481 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventSingleClick");
483 m_frame->document()->updateLayoutIgnorePendingStylesheets();
484 Node* innerNode = event.targetNode();
485 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
488 // Extend the selection if the Shift key is down, unless the click is in a link.
489 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
491 // Don't restart the selection when the mouse is pressed on an
492 // existing selection so we can allow for text dragging.
493 if (FrameView* view = m_frame->view()) {
494 LayoutPoint vPoint = view->windowToContents(event.event().position());
495 if (!extendSelection && m_frame->selection().contains(vPoint)) {
496 m_mouseDownWasSingleClickInSelection = true;
501 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
502 if (visiblePos.isNull())
503 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
504 Position pos = visiblePos.deepEquivalent();
506 VisibleSelection newSelection = m_frame->selection().selection();
507 TextGranularity granularity = CharacterGranularity;
509 if (extendSelection && newSelection.isCaretOrRange()) {
510 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
511 if (selectionInUserSelectAll.isRange()) {
512 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
513 pos = selectionInUserSelectAll.start();
514 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
515 pos = selectionInUserSelectAll.end();
518 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
519 if (pos.isNotNull()) {
520 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
521 // was created right-to-left
522 Position start = newSelection.start();
523 Position end = newSelection.end();
524 int distanceToStart = textDistance(start, pos);
525 int distanceToEnd = textDistance(pos, end);
526 if (distanceToStart <= distanceToEnd)
527 newSelection = VisibleSelection(end, pos);
529 newSelection = VisibleSelection(start, pos);
532 newSelection.setExtent(pos);
534 if (m_frame->selection().granularity() != CharacterGranularity) {
535 granularity = m_frame->selection().granularity();
536 newSelection.expandUsingGranularity(m_frame->selection().granularity());
539 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos));
542 bool handled = updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
546 static inline bool canMouseDownStartSelect(Node* node)
548 if (!node || !node->renderer())
551 if (!node->canStartSelection())
557 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
559 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
562 dragState().m_dragSrc = nullptr;
564 cancelFakeMouseMoveEvent();
566 m_frame->document()->updateLayoutIgnorePendingStylesheets();
568 if (ScrollView* scrollView = m_frame->view()) {
569 if (scrollView->isPointInScrollbarCorner(event.event().position()))
573 bool singleClick = event.event().clickCount() <= 1;
575 // If we got the event back, that must mean it wasn't prevented,
576 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
577 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
579 m_mouseDownMayStartDrag = singleClick;
581 m_mouseDownWasSingleClickInSelection = false;
583 m_mouseDown = event.event();
585 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
588 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGExtensions().zoomAndPanEnabled()) {
589 if (event.event().shiftKey() && singleClick) {
591 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()->windowToContents(event.event().position()));
596 // We don't do this at the start of mouse down handling,
597 // because we don't want to do it until we know we didn't hit a widget.
601 Node* innerNode = event.targetNode();
603 m_mousePressNode = innerNode;
604 m_dragStartPos = event.event().position();
606 bool swallowEvent = false;
607 m_mousePressed = true;
608 m_selectionInitiationState = HaveNotStartedSelection;
610 if (event.event().clickCount() == 2)
611 swallowEvent = handleMousePressEventDoubleClick(event);
612 else if (event.event().clickCount() >= 3)
613 swallowEvent = handleMousePressEventTripleClick(event);
615 swallowEvent = handleMousePressEventSingleClick(event);
617 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
618 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
623 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
625 TRACE_EVENT0("webkit", "EventHandler::handleMouseDraggedEvent");
630 if (handleDrag(event, ShouldCheckDragHysteresis))
633 Node* targetNode = event.targetNode();
634 if (event.event().button() != LeftButton || !targetNode)
637 RenderObject* renderer = targetNode->renderer();
639 Node* parent = NodeRenderingTraversal::parent(targetNode);
643 renderer = parent->renderer();
644 if (!renderer || !renderer->isListBox())
648 m_mouseDownMayStartDrag = false;
650 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
651 if (AutoscrollController* controller = autoscrollController()) {
652 controller->startAutoscrollForSelection(renderer);
653 m_mouseDownMayStartAutoscroll = false;
657 if (m_selectionInitiationState != ExtendedSelection) {
658 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
659 HitTestResult result(m_mouseDownPos);
660 m_frame->document()->renderView()->hitTest(request, result);
662 updateSelectionForMouseDrag(result);
664 updateSelectionForMouseDrag(event.hitTestResult());
668 void EventHandler::updateSelectionForMouseDrag()
670 FrameView* view = m_frame->view();
673 RenderView* renderer = m_frame->contentRenderer();
677 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
678 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
679 renderer->hitTest(request, result);
680 updateSelectionForMouseDrag(result);
683 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
685 if (!m_mouseDownMayStartSelect)
688 Node* target = hitTestResult.targetNode();
692 VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
693 // Don't modify the selection if we're not on a node.
694 if (targetPosition.isNull())
697 // Restart the selection if this is the first mouse move. This work is usually
698 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
699 VisibleSelection newSelection = m_frame->selection().selection();
701 // Special case to limit selection to the containing block for SVG text.
702 // FIXME: Isn't there a better non-SVG-specific way to do this?
703 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
704 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
705 if (selectionBaseRenderer->isSVGText())
706 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
709 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
712 if (m_selectionInitiationState != ExtendedSelection) {
713 // Always extend selection here because it's caused by a mouse drag
714 m_selectionInitiationState = ExtendedSelection;
715 newSelection = VisibleSelection(targetPosition);
718 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
719 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
720 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
721 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
722 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
724 // Reset base for user select all when base is inside user-select-all area and extent < base.
725 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
726 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
728 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
729 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
730 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
731 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
732 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
734 newSelection.setExtent(targetPosition);
737 newSelection.setExtent(targetPosition);
740 if (m_frame->selection().granularity() != CharacterGranularity)
741 newSelection.expandUsingGranularity(m_frame->selection().granularity());
743 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
744 FrameSelection::AdjustEndpointsAtBidiBoundary);
747 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
749 AutoscrollController* controller = autoscrollController();
750 if (controller && controller->autoscrollInProgress())
753 // Used to prevent mouseMoveEvent from initiating a drag before
754 // the mouse is pressed again.
755 m_mousePressed = false;
756 m_capturesDragging = false;
757 m_mouseDownMayStartDrag = false;
758 m_mouseDownMayStartSelect = false;
759 m_mouseDownMayStartAutoscroll = false;
760 m_mouseDownWasInSubframe = false;
762 bool handled = false;
764 // Clear the selection if the mouse didn't move after the last mouse
765 // press and it's not a context menu click. We do this so when clicking
766 // on the selection, the selection goes away. However, if we are
767 // editing, place the caret.
768 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
769 && m_dragStartPos == event.event().position()
770 && m_frame->selection().isRange()
771 && event.event().button() != RightButton) {
772 VisibleSelection newSelection;
773 Node* node = event.targetNode();
774 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
775 if (node && node->renderer() && (caretBrowsing || node->rendererIsEditable())) {
776 VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
777 newSelection = VisibleSelection(pos);
780 setSelectionIfNeeded(m_frame->selection(), newSelection);
785 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
787 m_frame->selection().selectFrameElementInParentIfFullySelected();
789 if (event.event().button() == MiddleButton && !event.isOverLink()) {
790 // Ignore handled, since we want to paste to where the caret was placed anyway.
791 handled = handlePasteGlobalSelection(event.event()) || handled;
799 void EventHandler::startPanScrolling(RenderObject* renderer)
801 if (!renderer->isBox())
803 AutoscrollController* controller = autoscrollController();
806 controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
812 AutoscrollController* EventHandler::autoscrollController() const
814 if (Page* page = m_frame->page())
815 return &page->autoscrollController();
819 bool EventHandler::panScrollInProgress() const
821 return autoscrollController() && autoscrollController()->panScrollInProgress();
824 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
826 TRACE_EVENT0("webkit", "EventHandler::hitTestResultAtPoint");
828 // We always send hitTestResultAtPoint to the main frame if we have one,
829 // otherwise we might hit areas that are obscured by higher frames.
830 if (Page* page = m_frame->page()) {
831 LocalFrame* mainFrame = page->mainFrame();
832 if (m_frame != mainFrame) {
833 FrameView* frameView = m_frame->view();
834 FrameView* mainView = mainFrame->view();
835 if (frameView && mainView) {
836 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
837 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
842 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
844 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
845 // layout because until then, there is nothing shown on the screen - the user can't
846 // have intentionally clicked on something belonging to this page. Furthermore,
847 // mousemove events before the first layout should not lead to a premature layout()
848 // happening, which could show a flash of white.
849 // See also the similar code in Document::prepareMouseEvent.
850 if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
853 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
854 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
855 m_frame->contentRenderer()->hitTest(request, result);
856 if (!request.readOnly())
857 m_frame->document()->updateHoverActiveState(request, result.innerElement());
859 if (request.disallowsShadowContent())
860 result.setToNodesInDocumentTreeScope();
865 void EventHandler::stopAutoscroll()
867 if (AutoscrollController* controller = autoscrollController())
868 controller->stopAutoscroll();
871 Node* EventHandler::mousePressNode() const
873 return m_mousePressNode.get();
876 bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoint absolutePoint)
881 Node* node = startNode;
884 node = m_frame->document()->focusedElement();
887 node = m_mousePressNode.get();
889 if (!node || !node->renderer())
892 RenderBox* curBox = node->renderer()->enclosingBox();
893 while (curBox && !curBox->isRenderView()) {
894 ScrollDirection physicalDirection = toPhysicalDirection(
895 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode());
897 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
898 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *stopNode;
899 bool didScroll = curBox->scroll(physicalDirection, granularity, delta);
901 if (didScroll && stopNode)
902 *stopNode = curBox->node();
904 if (didScroll || shouldStopBubbling) {
905 setFrameWasScrolledByUser();
909 curBox = curBox->containingBlock();
915 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
917 // The layout needs to be up to date to determine if we can scroll. We may be
918 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
919 m_frame->document()->updateLayoutIgnorePendingStylesheets();
920 if (scroll(direction, granularity, startingNode))
922 LocalFrame* frame = m_frame;
923 FrameView* view = frame->view();
924 if (view && view->scroll(direction, granularity))
926 frame = frame->tree().parent();
929 return frame->eventHandler().bubblingScroll(direction, granularity, m_frame->ownerElement());
932 IntPoint EventHandler::lastKnownMousePosition() const
934 return m_lastKnownMousePosition;
937 static LocalFrame* subframeForTargetNode(Node* node)
942 RenderObject* renderer = node->renderer();
943 if (!renderer || !renderer->isWidget())
946 // FIXME: This explicit check is needed only until RemoteFrames have RemoteFrameViews.
947 if (isHTMLFrameElementBase(node) && toHTMLFrameElementBase(node)->contentFrame() && toHTMLFrameElementBase(node)->contentFrame()->isRemoteFrameTemporary())
950 Widget* widget = toRenderWidget(renderer)->widget();
951 if (!widget || !widget->isFrameView())
954 return &toFrameView(widget)->frame();
957 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
959 if (!hitTestResult.isOverWidget())
961 return subframeForTargetNode(hitTestResult.targetNode());
964 static bool isSubmitImage(Node* node)
966 return isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
969 bool EventHandler::useHandCursor(Node* node, bool isOverLink)
974 return ((isOverLink || isSubmitImage(node)) && !node->rendererIsEditable());
977 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
980 ASSERT(m_frame->document());
985 void EventHandler::updateCursor()
987 if (m_mousePositionIsUnknown)
990 FrameView* view = m_frame->view();
991 if (!view || !view->shouldSetCursor())
994 RenderView* renderView = view->renderView();
998 m_frame->document()->updateLayout();
1000 HitTestRequest request(HitTestRequest::ReadOnly);
1001 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1002 renderView->hitTest(request, result);
1004 OptionalCursor optionalCursor = selectCursor(result);
1005 if (optionalCursor.isCursorChange()) {
1006 m_currentMouseCursor = optionalCursor.cursor();
1007 view->setCursor(m_currentMouseCursor);
1011 OptionalCursor EventHandler::selectCursor(const HitTestResult& result)
1013 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1014 return NoCursorChange;
1016 Page* page = m_frame->page();
1018 return NoCursorChange;
1020 if (panScrollInProgress())
1021 return NoCursorChange;
1024 Node* node = result.innerPossiblyPseudoNode();
1026 return selectAutoCursor(result, node, iBeamCursor());
1028 RenderObject* renderer = node->renderer();
1029 RenderStyle* style = renderer ? renderer->style() : 0;
1032 Cursor overrideCursor;
1033 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1034 case SetCursorBasedOnStyle:
1037 return overrideCursor;
1038 case DoNotSetCursor:
1039 return NoCursorChange;
1043 if (style && style->cursors()) {
1044 const CursorList* cursors = style->cursors();
1045 for (unsigned i = 0; i < cursors->size(); ++i) {
1046 StyleImage* styleImage = (*cursors)[i].image();
1049 ImageResource* cachedImage = styleImage->cachedImage();
1052 float scale = styleImage->imageScaleFactor();
1053 // Get hotspot and convert from logical pixels to physical pixels.
1054 IntPoint hotSpot = (*cursors)[i].hotSpot();
1055 hotSpot.scale(scale, scale);
1056 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1057 if (cachedImage->errorOccurred())
1059 // Limit the size of cursors (in UI pixels) so that they cannot be
1060 // used to cover UI elements in chrome.
1061 size.scale(1 / scale);
1062 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1065 Image* image = cachedImage->imageForRenderer(renderer);
1066 // Ensure no overflow possible in calculations above.
1067 if (scale < minimumCursorScale)
1069 return Cursor(image, hotSpot, scale);
1073 switch (style ? style->cursor() : CURSOR_AUTO) {
1075 bool horizontalText = !style || style->isHorizontalWritingMode();
1076 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1077 return selectAutoCursor(result, node, iBeam);
1080 return crossCursor();
1081 case CURSOR_POINTER:
1082 return handCursor();
1084 return moveCursor();
1085 case CURSOR_ALL_SCROLL:
1086 return moveCursor();
1087 case CURSOR_E_RESIZE:
1088 return eastResizeCursor();
1089 case CURSOR_W_RESIZE:
1090 return westResizeCursor();
1091 case CURSOR_N_RESIZE:
1092 return northResizeCursor();
1093 case CURSOR_S_RESIZE:
1094 return southResizeCursor();
1095 case CURSOR_NE_RESIZE:
1096 return northEastResizeCursor();
1097 case CURSOR_SW_RESIZE:
1098 return southWestResizeCursor();
1099 case CURSOR_NW_RESIZE:
1100 return northWestResizeCursor();
1101 case CURSOR_SE_RESIZE:
1102 return southEastResizeCursor();
1103 case CURSOR_NS_RESIZE:
1104 return northSouthResizeCursor();
1105 case CURSOR_EW_RESIZE:
1106 return eastWestResizeCursor();
1107 case CURSOR_NESW_RESIZE:
1108 return northEastSouthWestResizeCursor();
1109 case CURSOR_NWSE_RESIZE:
1110 return northWestSouthEastResizeCursor();
1111 case CURSOR_COL_RESIZE:
1112 return columnResizeCursor();
1113 case CURSOR_ROW_RESIZE:
1114 return rowResizeCursor();
1116 return iBeamCursor();
1118 return waitCursor();
1120 return helpCursor();
1121 case CURSOR_VERTICAL_TEXT:
1122 return verticalTextCursor();
1124 return cellCursor();
1125 case CURSOR_CONTEXT_MENU:
1126 return contextMenuCursor();
1127 case CURSOR_PROGRESS:
1128 return progressCursor();
1129 case CURSOR_NO_DROP:
1130 return noDropCursor();
1132 return aliasCursor();
1134 return copyCursor();
1136 return noneCursor();
1137 case CURSOR_NOT_ALLOWED:
1138 return notAllowedCursor();
1139 case CURSOR_DEFAULT:
1140 return pointerCursor();
1141 case CURSOR_WEBKIT_ZOOM_IN:
1142 return zoomInCursor();
1143 case CURSOR_WEBKIT_ZOOM_OUT:
1144 return zoomOutCursor();
1145 case CURSOR_WEBKIT_GRAB:
1146 return grabCursor();
1147 case CURSOR_WEBKIT_GRABBING:
1148 return grabbingCursor();
1150 return pointerCursor();
1153 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam)
1155 bool editable = (node && node->rendererIsEditable());
1157 if (useHandCursor(node, result.isOverLink()))
1158 return handCursor();
1160 bool inResizer = false;
1161 RenderObject* renderer = node ? node->renderer() : 0;
1162 if (renderer && m_frame->view()) {
1163 RenderLayer* layer = renderer->enclosingLayer();
1164 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1167 // During selection, use an I-beam no matter what we're over.
1168 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1169 if (m_mousePressed && m_mouseDownMayStartSelect
1170 && !m_mouseDownMayStartDrag
1171 && m_frame->selection().isCaretOrRange()
1172 && !m_capturingMouseEventsNode) {
1176 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1178 return pointerCursor();
1181 static LayoutPoint documentPointForWindowPoint(LocalFrame* frame, const IntPoint& windowPoint)
1183 FrameView* view = frame->view();
1184 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1185 // Historically the code would just crash; this is clearly no worse than that.
1186 return view ? view->windowToContents(windowPoint) : windowPoint;
1189 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1191 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
1193 RefPtr<FrameView> protector(m_frame->view());
1195 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1196 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1198 cancelFakeMouseMoveEvent();
1199 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1200 m_capturingMouseEventsNode = nullptr;
1201 m_mousePressed = true;
1202 m_capturesDragging = true;
1203 setLastKnownMousePosition(mouseEvent);
1204 m_mouseDownTimestamp = mouseEvent.timestamp();
1205 m_mouseDownMayStartDrag = false;
1206 m_mouseDownMayStartSelect = false;
1207 m_mouseDownMayStartAutoscroll = false;
1208 if (FrameView* view = m_frame->view())
1209 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1214 m_mouseDownWasInSubframe = false;
1216 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1217 if (mouseEvent.fromTouch())
1218 hitType |= HitTestRequest::ReadOnly;
1219 HitTestRequest request(hitType);
1220 // Save the document point we generate in case the window coordinate is invalidated by what happens
1221 // when we dispatch the event.
1222 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1223 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1225 if (!mev.targetNode()) {
1230 m_mousePressNode = mev.targetNode();
1232 RefPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1233 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1234 // Start capturing future events for this frame. We only do this if we didn't clear
1235 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1236 m_capturesDragging = subframe->eventHandler().capturesDragging();
1237 if (m_mousePressed && m_capturesDragging) {
1238 m_capturingMouseEventsNode = mev.targetNode();
1239 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1246 // We store whether pan scrolling is in progress before calling stopAutoscroll()
1247 // because it will set m_autoscrollType to NoAutoscroll on return.
1248 bool isPanScrollInProgress = panScrollInProgress();
1250 if (isPanScrollInProgress) {
1251 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1252 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1258 m_clickCount = mouseEvent.clickCount();
1259 m_clickNode = mev.targetNode()->isTextNode() ? mev.targetNode()->parentOrShadowHostNode() : mev.targetNode();
1261 if (FrameView* view = m_frame->view()) {
1262 RenderLayer* layer = mev.targetNode()->renderer() ? mev.targetNode()->renderer()->enclosingLayer() : 0;
1263 IntPoint p = view->windowToContents(mouseEvent.position());
1264 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1265 m_resizeScrollableArea = layer->scrollableArea();
1266 m_resizeScrollableArea->setInResizeMode(true);
1267 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1273 m_frame->selection().setCaretBlinkingSuspended(true);
1275 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.targetNode(), m_clickCount, mouseEvent, true);
1276 swallowEvent = swallowEvent || !handleMouseFocus(mouseEvent);
1277 m_capturesDragging = !swallowEvent || mev.scrollbar();
1279 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1280 // in case the scrollbar widget was destroyed when the mouse event was handled.
1281 if (mev.scrollbar()) {
1282 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1283 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1284 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1285 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1286 m_lastScrollbarUnderMouse = nullptr;
1290 // scrollbars should get events anyway, even disabled controls might be scrollable
1291 Scrollbar* scrollbar = mev.scrollbar();
1293 updateLastScrollbarUnderMouse(scrollbar, true);
1296 passMousePressEventToScrollbar(mev, scrollbar);
1298 if (shouldRefetchEventTarget(mev)) {
1299 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1300 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1303 FrameView* view = m_frame->view();
1304 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1306 scrollbar = mev.scrollbar();
1308 updateLastScrollbarUnderMouse(scrollbar, true);
1310 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1311 swallowEvent = true;
1313 swallowEvent = handleMousePressEvent(mev);
1316 return swallowEvent;
1319 static RenderLayer* layerForNode(Node* node)
1324 RenderObject* renderer = node->renderer();
1328 RenderLayer* layer = renderer->enclosingLayer();
1335 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1337 if (RenderLayerScrollableArea* scrollableArea = layer->scrollableArea()) {
1338 if (scrollableArea->scrollsOverflow())
1339 return scrollableArea;
1345 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1347 TRACE_EVENT0("webkit", "EventHandler::handleMouseMoveEvent");
1349 RefPtr<FrameView> protector(m_frame->view());
1350 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1352 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1353 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1355 Page* page = m_frame->page();
1359 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1360 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1361 layerScrollableArea->mouseMovedInContentArea();
1364 if (FrameView* frameView = m_frame->view())
1365 frameView->mouseMovedInContentArea();
1367 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1368 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1369 page->chrome().setToolTip(hoveredNode);
1374 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1376 TRACE_EVENT0("webkit", "EventHandler::handleMouseLeaveEvent");
1378 RefPtr<FrameView> protector(m_frame->view());
1379 handleMouseMoveOrLeaveEvent(event);
1382 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1385 ASSERT(m_frame->view());
1387 setLastKnownMousePosition(mouseEvent);
1389 if (m_hoverTimer.isActive())
1390 m_hoverTimer.stop();
1392 m_cursorUpdateTimer.stop();
1394 cancelFakeMouseMoveEvent();
1397 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1401 if (m_frameSetBeingResized)
1402 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), 0, mouseEvent, false);
1404 // Send events right to a scrollbar if the mouse is pressed.
1405 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1406 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1410 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1411 if (mouseEvent.fromTouch())
1412 hitType |= HitTestRequest::ReadOnly;
1415 hitType |= HitTestRequest::Active;
1416 else if (onlyUpdateScrollbars) {
1417 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1418 // means that :hover and :active freeze in the state they were in, rather than updating
1419 // for nodes the mouse moves while the window is not key (which will be the case if
1420 // onlyUpdateScrollbars is true).
1421 hitType |= HitTestRequest::ReadOnly;
1424 // Treat any mouse move events as readonly if the user is currently touching the screen.
1426 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1427 HitTestRequest request(hitType);
1428 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1430 *hoveredNode = mev.hitTestResult();
1432 Scrollbar* scrollbar = 0;
1434 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1435 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1437 if (FrameView* view = m_frame->view())
1438 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1441 scrollbar = mev.scrollbar();
1443 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1444 if (onlyUpdateScrollbars)
1448 bool swallowEvent = false;
1449 RefPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1451 // 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.
1452 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1453 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1456 // Update over/out state before passing the event to the subframe.
1457 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1459 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1460 // node to be detached from its FrameView, in which case the event should not be passed.
1461 if (newSubframe->view())
1462 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1464 if (scrollbar && !m_mousePressed)
1465 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1466 if (FrameView* view = m_frame->view()) {
1467 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult());
1468 if (optionalCursor.isCursorChange()) {
1469 m_currentMouseCursor = optionalCursor.cursor();
1470 view->setCursor(m_currentMouseCursor);
1475 m_lastMouseMoveEventSubframe = newSubframe;
1480 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.targetNode(), 0, mouseEvent, true);
1482 swallowEvent = handleMouseDraggedEvent(mev);
1484 return swallowEvent;
1487 void EventHandler::invalidateClick()
1490 m_clickNode = nullptr;
1493 static Node* parentForClickEvent(const Node& node)
1495 // IE doesn't dispatch click events for mousedown/mouseup events across form
1497 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1499 return node.parentOrShadowHostNode();
1502 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1504 TRACE_EVENT0("webkit", "EventHandler::handleMouseReleaseEvent");
1506 RefPtr<FrameView> protector(m_frame->view());
1508 m_frame->selection().setCaretBlinkingSuspended(false);
1510 OwnPtr<UserGestureIndicator> gestureIndicator;
1512 if (m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken)
1513 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1515 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1518 if (Page* page = m_frame->page())
1519 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1522 m_mousePressed = false;
1523 setLastKnownMousePosition(mouseEvent);
1527 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1531 if (m_frameSetBeingResized)
1532 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), m_clickCount, mouseEvent, false);
1534 if (m_lastScrollbarUnderMouse) {
1536 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1537 bool setUnder = false;
1538 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), m_clickCount, mouseEvent, setUnder);
1541 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1542 if (mouseEvent.fromTouch())
1543 hitType |= HitTestRequest::ReadOnly;
1544 HitTestRequest request(hitType);
1545 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1546 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1547 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1548 m_capturingMouseEventsNode = nullptr;
1549 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1552 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.targetNode(), m_clickCount, mouseEvent, false);
1554 bool contextMenuEvent = mouseEvent.button() == RightButton;
1556 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1557 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1558 contextMenuEvent = true;
1561 bool swallowClickEvent = false;
1562 if (m_clickCount > 0 && !contextMenuEvent && mev.targetNode() && m_clickNode) {
1563 if (Node* clickTargetNode = mev.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1564 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, m_clickCount, mouseEvent, true);
1567 if (m_resizeScrollableArea) {
1568 m_resizeScrollableArea->setInResizeMode(false);
1569 m_resizeScrollableArea = 0;
1572 bool swallowMouseReleaseEvent = false;
1573 if (!swallowMouseUpEvent)
1574 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1578 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1581 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1583 // If the event was a middle click, attempt to copy global selection in after
1584 // the newly set caret position.
1586 // This code is called from either the mouse up or mouse down handling. There
1587 // is some debate about when the global selection is pasted:
1588 // xterm: pastes on up.
1589 // GTK: pastes on down.
1590 // Qt: pastes on up.
1591 // Firefox: pastes on up.
1592 // Chromium: pastes on up.
1594 // There is something of a webcompat angle to this well, as highlighted by
1595 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1596 // down then the text is pasted just before the onclick handler runs and
1597 // clears the text box. So it's important this happens after the event
1598 // handlers have been fired.
1599 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1602 if (!m_frame->page())
1604 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1605 // Do not paste here if the focus was moved somewhere else.
1606 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1607 return m_frame->editor().command("PasteGlobalSelection").execute();
1613 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1615 FrameView* view = m_frame->view();
1617 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1621 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType,
1622 true, true, m_frame->document()->domWindow(),
1623 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1624 event.movementDelta().x(), event.movementDelta().y(),
1625 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1626 0, nullptr, clipboard);
1628 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1629 return me->defaultPrevented();
1632 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1634 if (!isHTMLFrameElementBase(target))
1637 // Cross-process drag and drop is not yet supported.
1638 if (toHTMLFrameElementBase(target)->contentFrame() && !toHTMLFrameElementBase(target)->contentFrame()->isLocalFrame())
1641 frame = toLocalFrame(toHTMLFrameElementBase(target)->contentFrame());
1645 static bool findDropZone(Node* target, Clipboard* clipboard)
1647 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1648 for (; element; element = element->parentElement()) {
1649 bool matched = false;
1650 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1652 if (dropZoneStr.isEmpty())
1655 dropZoneStr = dropZoneStr.lower();
1657 SpaceSplitString keywords(dropZoneStr, false);
1658 if (keywords.isNull())
1661 DragOperation dragOperation = DragOperationNone;
1662 for (unsigned i = 0; i < keywords.size(); i++) {
1663 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1664 if (op != DragOperationNone) {
1665 if (dragOperation == DragOperationNone)
1668 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1670 if (matched && dragOperation != DragOperationNone)
1674 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1681 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1683 bool accept = false;
1685 if (!m_frame->view())
1688 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1689 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1691 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1692 RefPtr<Node> newTarget = mev.targetNode();
1693 if (newTarget && newTarget->isTextNode())
1694 newTarget = NodeRenderingTraversal::parent(newTarget.get());
1696 if (AutoscrollController* controller = autoscrollController())
1697 controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1699 if (m_dragTarget != newTarget) {
1700 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1701 // it is sometimes incorrect when dragging within subframes, as seen with
1702 // LayoutTests/fast/events/drag-in-frames.html.
1704 // 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>.
1705 LocalFrame* targetFrame;
1706 if (targetIsFrame(newTarget.get(), targetFrame)) {
1708 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1709 } else if (newTarget) {
1710 // 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.
1711 if (dragState().m_dragSrc) {
1712 // for now we don't care if event handler cancels default behavior, since there is none
1713 dispatchDragSrcEvent(EventTypeNames::drag, event);
1715 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, clipboard);
1717 accept = findDropZone(newTarget.get(), clipboard);
1720 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1722 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1723 } else if (m_dragTarget)
1724 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1727 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1728 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1729 m_shouldOnlyFireDragOverEvent = true;
1732 LocalFrame* targetFrame;
1733 if (targetIsFrame(newTarget.get(), targetFrame)) {
1735 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1736 } else if (newTarget) {
1737 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1738 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1739 // for now we don't care if event handler cancels default behavior, since there is none
1740 dispatchDragSrcEvent(EventTypeNames::drag, event);
1742 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, clipboard);
1744 accept = findDropZone(newTarget.get(), clipboard);
1745 m_shouldOnlyFireDragOverEvent = false;
1748 m_dragTarget = newTarget;
1753 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1755 LocalFrame* targetFrame;
1756 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1758 targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
1759 } else if (m_dragTarget.get()) {
1760 if (dragState().m_dragSrc)
1761 dispatchDragSrcEvent(EventTypeNames::drag, event);
1762 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1767 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1769 LocalFrame* targetFrame;
1770 bool preventedDefault = false;
1771 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1773 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
1774 } else if (m_dragTarget.get())
1775 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, clipboard);
1777 return preventedDefault;
1780 void EventHandler::clearDragState()
1783 m_dragTarget = nullptr;
1784 m_capturingMouseEventsNode = nullptr;
1785 m_shouldOnlyFireDragOverEvent = false;
1788 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1790 m_capturingMouseEventsNode = n;
1791 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1794 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1797 ASSERT(m_frame->document());
1799 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1802 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1804 Node* result = targetNode;
1806 // If we're capturing, we always go right to that node.
1807 if (m_capturingMouseEventsNode)
1808 result = m_capturingMouseEventsNode.get();
1810 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1811 if (result && result->isTextNode())
1812 result = NodeRenderingTraversal::parent(result);
1814 m_nodeUnderMouse = result;
1816 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1817 if (fireMouseOverOut) {
1818 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1819 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1820 Page* page = m_frame->page();
1822 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1823 // The mouse has moved between frames.
1824 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1825 if (FrameView* frameView = frame->view())
1826 frameView->mouseExitedContentArea();
1828 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1829 // The mouse has moved between layers.
1830 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
1831 scrollableAreaForLastNode->mouseExitedContentArea();
1834 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1835 // The mouse has moved between frames.
1836 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
1837 if (FrameView* frameView = frame->view())
1838 frameView->mouseEnteredContentArea();
1840 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1841 // The mouse has moved between layers.
1842 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
1843 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1846 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1847 m_lastNodeUnderMouse = nullptr;
1848 m_lastScrollbarUnderMouse = nullptr;
1851 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1852 // send mouseout event to the old node
1853 if (m_lastNodeUnderMouse)
1854 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
1855 // send mouseover event to the new node
1856 if (m_nodeUnderMouse)
1857 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
1859 m_lastNodeUnderMouse = m_nodeUnderMouse;
1863 // The return value means 'continue default handling.'
1864 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1866 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1867 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1870 // The return value means 'continue default handling.'
1871 bool EventHandler::handleMouseFocus(const PlatformMouseEvent& mouseEvent)
1873 // If clicking on a frame scrollbar, do not mess up with content focus.
1874 if (FrameView* view = m_frame->view()) {
1875 if (view->scrollbarAtPoint(mouseEvent.position()))
1879 // The layout needs to be up to date to determine if an element is focusable.
1880 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1882 Element* element = 0;
1883 if (m_nodeUnderMouse)
1884 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
1885 for (; element; element = element->parentOrShadowHostElement()) {
1886 if (element->isFocusable() && element->focused())
1888 if (element->isMouseFocusable())
1891 ASSERT(!element || element->isMouseFocusable());
1893 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
1894 // a node on mouse down if it's selected and inside a focused node. It will
1895 // be focused if the user does a mouseup over it, however, because the
1896 // mouseup will set a selection inside it, which will call
1897 // FrameSelection::setFocusedNodeIfNeeded.
1899 && m_frame->selection().isRange()
1900 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
1901 && element->isDescendantOf(m_frame->document()->focusedElement()))
1904 // Only change the focus when clicking scrollbars if it can transfered to a
1905 // mouse focusable node.
1906 if (!element && isInsideScrollbar(mouseEvent.position()))
1909 if (Page* page = m_frame->page()) {
1910 // If focus shift is blocked, we eat the event. Note we should never
1911 // clear swallowEvent if the page already set it (e.g., by canceling
1912 // default behavior).
1914 if (!page->focusController().setFocusedElement(element, m_frame, FocusTypeMouse))
1917 // We call setFocusedElement even with !element in order to blur
1918 // current focus element when a link is clicked; this is expected by
1919 // some sites that rely on onChange handlers running from form
1920 // fields before the button click is processed.
1921 if (!page->focusController().setFocusedElement(0, m_frame))
1929 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
1931 if (RenderView* renderView = m_frame->contentRenderer()) {
1932 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1933 HitTestResult result(windowPoint);
1934 renderView->hitTest(request, result);
1935 return result.scrollbar();
1941 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
1943 #define RETURN_WHEEL_EVENT_HANDLED() \
1945 setFrameWasScrolledByUser(); \
1949 Document* doc = m_frame->document();
1951 if (!doc->renderer())
1954 RefPtr<FrameView> protector(m_frame->view());
1956 FrameView* view = m_frame->view();
1960 LayoutPoint vPoint = view->windowToContents(event.position());
1962 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1963 HitTestResult result(vPoint);
1964 doc->renderView()->hitTest(request, result);
1966 Node* node = result.innerNode();
1967 // Wheel events should not dispatch to text nodes.
1968 if (node && node->isTextNode())
1969 node = NodeRenderingTraversal::parent(node);
1972 if (event.useLatchedEventNode()) {
1973 if (!m_latchedWheelEventNode) {
1974 m_latchedWheelEventNode = node;
1975 m_widgetIsLatched = result.isOverWidget();
1977 node = m_latchedWheelEventNode.get();
1979 isOverWidget = m_widgetIsLatched;
1981 if (m_latchedWheelEventNode)
1982 m_latchedWheelEventNode = nullptr;
1983 if (m_previousWheelScrolledNode)
1984 m_previousWheelScrolledNode = nullptr;
1986 isOverWidget = result.isOverWidget();
1990 // Figure out which view to send the event to.
1991 RenderObject* target = node->renderer();
1993 if (isOverWidget && target && target->isWidget()) {
1994 Widget* widget = toRenderWidget(target)->widget();
1995 if (widget && passWheelEventToWidget(event, widget))
1996 RETURN_WHEEL_EVENT_HANDLED();
1999 if (node && !node->dispatchWheelEvent(event))
2000 RETURN_WHEEL_EVENT_HANDLED();
2003 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2004 view = m_frame->view();
2005 if (!view || !view->wheelEvent(event))
2008 RETURN_WHEEL_EVENT_HANDLED();
2010 #undef RETURN_WHEEL_EVENT_HANDLED
2013 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2015 if (!startNode || !wheelEvent)
2018 // Ctrl + scrollwheel is reserved for triggering zoom in/out actions in Chromium.
2019 if (wheelEvent->ctrlKey())
2022 Node* stopNode = m_previousWheelScrolledNode.get();
2023 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2025 // Break up into two scrolls if we need to. Diagonal movement on
2026 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2027 if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation())))
2028 wheelEvent->setDefaultHandled();
2030 if (scroll(ScrollDown, granularity, startNode, &stopNode, wheelEvent->deltaY(), roundedIntPoint(wheelEvent->absoluteLocation())))
2031 wheelEvent->setDefaultHandled();
2033 if (!m_latchedWheelEventNode)
2034 m_previousWheelScrolledNode = stopNode;
2037 bool EventHandler::handleGestureShowPress()
2039 m_lastShowPressTimestamp = WTF::currentTime();
2041 FrameView* view = m_frame->view();
2044 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2045 scrollAnimator->cancelAnimations();
2046 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2049 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2050 ScrollableArea* sa = *it;
2051 ScrollAnimator* animator = sa->scrollAnimator();
2053 animator->cancelAnimations();
2058 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2060 IntPoint adjustedPoint = gestureEvent.position();
2061 RefPtr<LocalFrame> subframe = nullptr;
2062 switch (gestureEvent.type()) {
2063 case PlatformEvent::GestureScrollBegin:
2064 case PlatformEvent::GestureScrollUpdate:
2065 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2066 case PlatformEvent::GestureScrollEnd:
2067 case PlatformEvent::GestureFlingStart:
2068 // Handle directly in main frame
2071 case PlatformEvent::GestureTap:
2072 case PlatformEvent::GestureTapUnconfirmed:
2073 case PlatformEvent::GestureTapDown:
2074 case PlatformEvent::GestureShowPress:
2075 case PlatformEvent::GestureTapDownCancel:
2076 case PlatformEvent::GestureTwoFingerTap:
2077 case PlatformEvent::GestureLongPress:
2078 case PlatformEvent::GestureLongTap:
2079 case PlatformEvent::GesturePinchBegin:
2080 case PlatformEvent::GesturePinchEnd:
2081 case PlatformEvent::GesturePinchUpdate:
2082 adjustGesturePosition(gestureEvent, adjustedPoint);
2083 subframe = getSubFrameForGestureEvent(adjustedPoint, gestureEvent);
2085 return subframe->eventHandler().handleGestureEvent(gestureEvent);
2089 ASSERT_NOT_REACHED();
2092 RefPtr<Node> eventTarget;
2093 RefPtr<Scrollbar> scrollbar;
2094 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2095 || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2096 || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation
2097 || gestureEvent.type() == PlatformEvent::GestureFlingStart) {
2098 scrollbar = m_scrollbarHandlingScrollGesture.get();
2099 eventTarget = m_scrollGestureHandlingNode.get();
2102 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2103 double activeInterval = 0;
2104 bool shouldKeepActiveForMinInterval = false;
2105 if (gestureEvent.type() == PlatformEvent::GestureShowPress
2106 || gestureEvent.type() == PlatformEvent::GestureTapUnconfirmed) {
2107 hitType |= HitTestRequest::Active;
2108 } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) {
2109 hitType |= HitTestRequest::Release;
2110 // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2111 if (!m_frame->document()->activeHoverElement())
2112 hitType |= HitTestRequest::ReadOnly;
2113 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2114 hitType |= HitTestRequest::Release;
2115 // If the Tap is received very shortly after ShowPress, we want to
2116 // delay clearing of the active state so that it's visible to the user
2117 // for at least a couple of frames.
2118 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2119 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2120 if (shouldKeepActiveForMinInterval)
2121 hitType |= HitTestRequest::ReadOnly;
2124 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2126 if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2127 IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2128 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2130 if (shouldKeepActiveForMinInterval) {
2131 m_lastDeferredTapElement = result.innerElement();
2132 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval, FROM_HERE);
2135 eventTarget = result.targetNode();
2137 FrameView* view = m_frame->view();
2138 scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2141 scrollbar = result.scrollbar();
2145 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2146 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed) {
2147 m_scrollbarHandlingScrollGesture = scrollbar;
2148 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2149 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2150 || !eventSwallowed) {
2151 m_scrollbarHandlingScrollGesture = nullptr;
2159 bool eventSwallowed = false;
2160 if (handleScrollGestureOnResizer(eventTarget.get(), gestureEvent))
2161 eventSwallowed = true;
2163 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2164 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2166 m_scrollGestureHandlingNode = eventTarget;
2173 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2174 // eliminate the need for this.
2175 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2177 switch (gestureEvent.type()) {
2178 case PlatformEvent::GestureScrollBegin:
2179 return handleGestureScrollBegin(gestureEvent);
2180 case PlatformEvent::GestureScrollUpdate:
2181 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2182 return handleGestureScrollUpdate(gestureEvent);
2183 case PlatformEvent::GestureScrollEnd:
2184 return handleGestureScrollEnd(gestureEvent);
2185 case PlatformEvent::GestureTap:
2186 return handleGestureTap(gestureEvent, adjustedPoint);
2187 case PlatformEvent::GestureShowPress:
2188 return handleGestureShowPress();
2189 case PlatformEvent::GestureLongPress:
2190 return handleGestureLongPress(gestureEvent, adjustedPoint);
2191 case PlatformEvent::GestureLongTap:
2192 return handleGestureLongTap(gestureEvent, adjustedPoint);
2193 case PlatformEvent::GestureTwoFingerTap:
2194 return handleGestureTwoFingerTap(gestureEvent, adjustedPoint);
2195 case PlatformEvent::GestureTapDown:
2196 case PlatformEvent::GesturePinchBegin:
2197 case PlatformEvent::GesturePinchEnd:
2198 case PlatformEvent::GesturePinchUpdate:
2199 case PlatformEvent::GestureTapDownCancel:
2200 case PlatformEvent::GestureTapUnconfirmed:
2201 case PlatformEvent::GestureFlingStart:
2204 ASSERT_NOT_REACHED();
2210 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2212 // 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.
2214 unsigned modifierFlags = 0;
2215 if (gestureEvent.altKey())
2216 modifierFlags |= PlatformEvent::AltKey;
2217 if (gestureEvent.ctrlKey())
2218 modifierFlags |= PlatformEvent::CtrlKey;
2219 if (gestureEvent.metaKey())
2220 modifierFlags |= PlatformEvent::MetaKey;
2221 if (gestureEvent.shiftKey())
2222 modifierFlags |= PlatformEvent::ShiftKey;
2223 PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2225 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2226 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2227 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2228 handleMouseMoveEvent(fakeMouseMove);
2230 bool defaultPrevented = false;
2231 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2232 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2233 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2234 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2236 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2237 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2238 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2239 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2241 return defaultPrevented;
2244 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2246 m_longTapShouldInvokeContextMenu = false;
2247 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2248 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2249 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2250 m_mouseDown = mouseDownEvent;
2252 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2253 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2254 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2255 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2256 m_didStartDrag = false;
2257 m_mouseDownMayStartDrag = true;
2258 dragState().m_dragSrc = nullptr;
2259 m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2260 RefPtr<FrameView> protector(m_frame->view());
2261 handleDrag(mev, DontCheckDragHysteresis);
2262 if (m_didStartDrag) {
2263 m_longTapShouldInvokeContextMenu = true;
2268 bool shouldLongPressSelectWord = true;
2270 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2272 if (shouldLongPressSelectWord) {
2273 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2274 HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2275 Node* innerNode = result.targetNode();
2276 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2277 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2278 if (m_frame->selection().isRange()) {
2279 focusDocumentView();
2284 return sendContextMenuEventForGesture(gestureEvent);
2287 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2290 if (m_longTapShouldInvokeContextMenu) {
2291 m_longTapShouldInvokeContextMenu = false;
2292 return sendContextMenuEventForGesture(gestureEvent);
2298 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2299 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2300 RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : 0;
2301 IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2302 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2303 m_resizeScrollableArea = layer->scrollableArea();
2304 m_resizeScrollableArea->setInResizeMode(true);
2305 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2308 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2309 gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2310 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2311 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2314 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2315 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2316 m_resizeScrollableArea->setInResizeMode(false);
2317 m_resizeScrollableArea = 0;
2325 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2327 return sendContextMenuEventForGesture(gestureEvent);
2330 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2335 if (!widget->isFrameView())
2338 return toFrameView(widget)->frame().eventHandler().handleGestureEvent(gestureEvent);
2341 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2343 if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2344 Widget* widget = toRenderWidget(renderer)->widget();
2345 return widget && passGestureEventToWidget(gestureEvent, widget);
2350 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2351 RefPtr<Node> node = m_scrollGestureHandlingNode;
2352 clearGestureScrollNodes();
2355 passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2360 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2362 Document* document = m_frame->document();
2363 if (!document->renderView())
2366 FrameView* view = m_frame->view();
2370 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2371 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2372 HitTestResult result(viewPoint);
2373 document->renderView()->hitTest(request, result);
2375 m_lastHitTestResultOverWidget = result.isOverWidget();
2376 m_scrollGestureHandlingNode = result.innerNode();
2377 m_previousGestureScrolledNode = nullptr;
2379 // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2380 // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2381 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2382 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2384 if (!m_scrollGestureHandlingNode)
2387 passGestureEventToWidgetIfPossible(gestureEvent, m_scrollGestureHandlingNode->renderer());
2392 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2394 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2398 const float scaleFactor = m_frame->pageZoomFactor();
2399 delta.scale(1 / scaleFactor, 1 / scaleFactor);
2401 Node* node = m_scrollGestureHandlingNode.get();
2403 return sendScrollEventToView(gestureEvent, delta);
2405 // Ignore this event if the targeted node does not have a valid renderer.
2406 RenderObject* renderer = node->renderer();
2410 RefPtr<FrameView> protector(m_frame->view());
2413 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2415 // Try to send the event to the correct view.
2416 if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) {
2417 if(scrollShouldNotPropagate)
2418 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2423 if (scrollShouldNotPropagate)
2424 stopNode = m_previousGestureScrolledNode.get();
2426 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2427 ScrollGranularity granularity = ScrollByPixel;
2428 bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width());
2429 bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height());
2431 if (scrollShouldNotPropagate)
2432 m_previousGestureScrolledNode = stopNode;
2434 if (horizontalScroll || verticalScroll) {
2435 setFrameWasScrolledByUser();
2439 // Otherwise try to scroll the view.
2440 return sendScrollEventToView(gestureEvent, delta);
2443 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2445 FrameView* view = m_frame->view();
2449 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2450 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2451 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2452 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2453 scaledDelta.width(), scaledDelta.height(),
2454 scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2455 ScrollByPixelWheelEvent,
2456 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2457 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2459 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2461 setFrameWasScrolledByUser();
2463 return scrolledFrame;
2466 LocalFrame* EventHandler::getSubFrameForGestureEvent(const IntPoint& touchAdjustedPoint, const PlatformGestureEvent& gestureEvent)
2468 PlatformMouseEvent mouseDown(touchAdjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2469 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2470 HitTestRequest request(HitTestRequest::ReadOnly);
2471 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDown);
2472 return subframeForHitTestResult(mev);
2475 void EventHandler::clearGestureScrollNodes()
2477 m_scrollGestureHandlingNode = nullptr;
2478 m_previousGestureScrolledNode = nullptr;
2481 bool EventHandler::isScrollbarHandlingGestures() const
2483 return m_scrollbarHandlingScrollGesture.get();
2486 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2488 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2490 return !event.area().isEmpty();
2493 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2495 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2496 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2498 // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2499 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2500 // scrollbars being untouchable.
2501 if (result.scrollbar())
2504 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2505 Vector<RefPtr<Node>, 11> nodes;
2506 copyToVector(result.rectBasedTestResult(), nodes);
2508 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2509 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2510 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2511 // handle targetNode being a shadow DOM node.
2513 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2514 // FIXME: targetNode and success are only used by Internals functions. We should
2515 // instead have dedicated test methods so we only do this work in tests.
2516 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> > (nodes));
2517 if (success && targetNode)
2518 targetNode = targetNode->deprecatedShadowAncestorNode();
2522 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2524 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2525 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2527 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2528 Vector<RefPtr<Node>, 11> nodes;
2529 copyToVector(result.rectBasedTestResult(), nodes);
2531 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2532 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2535 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2537 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2538 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, touchRadius);
2540 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2541 Vector<RefPtr<Node>, 11> nodes;
2542 copyToVector(result.rectBasedTestResult(), nodes);
2544 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2545 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2548 void EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2550 if (!shouldApplyTouchAdjustment(gestureEvent))
2553 Node* targetNode = 0;
2554 switch (gestureEvent.type()) {
2555 case PlatformEvent::GestureTap:
2556 case PlatformEvent::GestureTapUnconfirmed:
2557 case PlatformEvent::GestureTapDown:
2558 case PlatformEvent::GestureShowPress:
2559 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2561 case PlatformEvent::GestureLongPress:
2562 case PlatformEvent::GestureLongTap:
2563 case PlatformEvent::GestureTwoFingerTap:
2564 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2567 // FIXME: Implement handling for other types as needed.
2568 ASSERT_NOT_REACHED();
2572 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2574 Document* doc = m_frame->document();
2575 FrameView* v = m_frame->view();
2579 // Clear mouse press state to avoid initiating a drag while context menu is up.
2580 m_mousePressed = false;
2581 LayoutPoint viewportPos = v->windowToContents(event.position());
2582 HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2583 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2585 if (!m_frame->selection().contains(viewportPos)
2587 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2588 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2589 // available for text selections. But only if we're above text.
2590 && (m_frame->selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2591 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2593 if (mev.hitTestResult().isMisspelled())
2594 selectClosestMisspellingFromMouseEvent(mev);
2595 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2596 selectClosestWordOrLinkFromMouseEvent(mev);
2599 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.targetNode(), 0, event, false);
2602 bool EventHandler::sendContextMenuEventForKey()
2604 FrameView* view = m_frame->view();
2608 Document* doc = m_frame->document();
2612 // Clear mouse press state to avoid initiating a drag while context menu is up.
2613 m_mousePressed = false;
2615 static const int kContextMenuMargin = 1;
2618 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2620 int rightAligned = 0;
2624 Element* focusedElement = doc->focusedElement();
2625 FrameSelection& selection = m_frame->selection();
2626 Position start = selection.selection().start();
2627 bool shouldTranslateToRootView = true;
2629 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2630 RefPtrWillBeRawPtr<Range> selectionRange = selection.toNormalizedRange();
2631 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2633 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2634 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2635 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2636 location = IntPoint(x, y);
2637 } else if (focusedElement) {
2638 IntRect clippedRect = focusedElement->boundsInRootViewSpace();
2639 location = IntPoint(clippedRect.center());
2641 location = IntPoint(
2642 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2643 kContextMenuMargin);
2644 shouldTranslateToRootView = false;
2647 m_frame->view()->setCursor(pointerCursor());
2649 IntPoint position = shouldTranslateToRootView ? view->contentsToRootView(location) : location;
2650 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2652 Node* targetNode = doc->focusedElement();
2656 // Use the focused node as the target for hover and active.
2657 HitTestResult result(position);
2658 result.setInnerNode(targetNode);
2659 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, result.innerElement());
2661 // The contextmenu event is a mouse event even when invoked using the keyboard.
2662 // This is required for web compatibility.
2665 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2667 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2670 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2672 handleMousePressEvent(mouseEvent);
2673 return sendContextMenuEvent(mouseEvent);
2676 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2679 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2681 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2684 IntPoint adjustedPoint = event.position();
2685 adjustGesturePosition(event, adjustedPoint);
2686 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2687 // To simulate right-click behavior, we send a right mouse down and then
2688 // context menu event.
2689 handleMousePressEvent(mouseEvent);
2690 return sendContextMenuEvent(mouseEvent);
2691 // We do not need to send a corresponding mouse release because in case of
2692 // right-click, the context menu takes capture and consumes all events.
2695 void EventHandler::scheduleHoverStateUpdate()
2697 if (!m_hoverTimer.isActive())
2698 m_hoverTimer.startOneShot(0, FROM_HERE);
2701 void EventHandler::scheduleCursorUpdate()
2703 if (!m_cursorUpdateTimer.isActive())
2704 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
2707 void EventHandler::dispatchFakeMouseMoveEventSoon()
2712 if (m_mousePositionIsUnknown)
2715 Settings* settings = m_frame->settings();
2716 if (settings && !settings->deviceSupportsMouse())
2719 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2720 // reschedule the timer and use a longer time. This will cause the content
2721 // to receive these moves only after the user is done scrolling, reducing
2722 // pauses during the scroll.
2723 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2724 if (m_fakeMouseMoveEventTimer.isActive())
2725 m_fakeMouseMoveEventTimer.stop();
2726 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_HERE);
2728 if (!m_fakeMouseMoveEventTimer.isActive())
2729 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, FROM_HERE);
2733 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2735 FrameView* view = m_frame->view();
2739 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2742 dispatchFakeMouseMoveEventSoon();
2745 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2747 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2748 ASSERT(!m_mousePressed);
2750 Settings* settings = m_frame->settings();
2751 if (settings && !settings->deviceSupportsMouse())
2754 FrameView* view = m_frame->view();
2758 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2761 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2762 if (!isCursorVisible())
2769 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2770 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2771 handleMouseMoveEvent(fakeMouseMoveEvent);
2774 void EventHandler::cancelFakeMouseMoveEvent()
2776 m_fakeMouseMoveEventTimer.stop();
2779 bool EventHandler::isCursorVisible() const
2781 return m_frame->page()->isCursorVisible();
2784 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2786 m_frameSetBeingResized = frameSet;
2789 void EventHandler::resizeScrollableAreaDestroyed()
2791 ASSERT(m_resizeScrollableArea);
2792 m_resizeScrollableArea = 0;
2795 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2797 m_hoverTimer.stop();
2800 ASSERT(m_frame->document());
2802 if (RenderView* renderer = m_frame->contentRenderer()) {
2803 if (FrameView* view = m_frame->view()) {
2804 HitTestRequest request(HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2805 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2806 renderer->hitTest(request, result);
2807 m_frame->document()->updateHoverActiveState(request, result.innerElement());
2812 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
2814 m_activeIntervalTimer.stop();
2817 && m_frame->document()
2818 && m_lastDeferredTapElement) {
2819 // FIXME: Enable condition when http://crbug.com/226842 lands
2820 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2821 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
2822 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
2824 m_lastDeferredTapElement = nullptr;
2827 void EventHandler::notifyElementActivated()
2829 // Since another element has been set to active, stop current timer and clear reference.
2830 if (m_activeIntervalTimer.isActive())
2831 m_activeIntervalTimer.stop();
2832 m_lastDeferredTapElement = nullptr;
2835 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2837 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2838 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2839 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2840 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2841 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2842 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2844 String key = evt.unmodifiedText();
2845 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2848 elem->accessKeyAction(false);
2852 bool EventHandler::isKeyEventAllowedInFullScreen(FullscreenElementStack* fullscreen, const PlatformKeyboardEvent& keyEvent) const
2854 if (fullscreen->webkitFullScreenKeyboardInputAllowed())
2857 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2858 if (keyEvent.text().length() != 1)
2860 UChar character = keyEvent.text()[0];
2861 return character == ' ';
2864 int keyCode = keyEvent.windowsVirtualKeyCode();
2865 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2866 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2867 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2868 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2871 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2873 RefPtr<FrameView> protector(m_frame->view());
2875 ASSERT(m_frame->document());
2876 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(*m_frame->document())) {
2877 if (fullscreen->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent))
2881 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2882 capsLockStateMayHaveChanged();
2885 if (panScrollInProgress()) {
2886 // If a key is pressed while the panScroll is in progress then we want to stop
2887 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2890 // If we were in panscroll mode, we swallow the key event
2895 // Check for cases where we are too early for events -- possible unmatched key up
2896 // from pressing return in the location bar.
2897 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2901 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2903 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2904 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2905 // with access keys. Then we dispatch keydown, but suppress its default handling.
2906 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2907 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2908 bool matchedAnAccessKey = false;
2909 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2910 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2912 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2913 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2914 return !node->dispatchKeyEvent(initialKeyEvent);
2916 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2917 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2918 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
2919 RefPtrWillBeRawPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
2920 if (matchedAnAccessKey)
2921 keydown->setDefaultPrevented(true);
2922 keydown->setTarget(node);
2924 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2925 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2926 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2927 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2928 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2931 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2932 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2933 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2934 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2936 return keydownResult;
2938 // Focus may have changed during keydown handling, so refetch node.
2939 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2940 node = eventTargetNodeForDocument(m_frame->document());
2944 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2945 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
2946 if (keyPressEvent.text().isEmpty())
2947 return keydownResult;
2948 RefPtrWillBeRawPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
2949 keypress->setTarget(node);
2951 keypress->setDefaultPrevented(true);
2952 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
2954 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2957 static FocusType focusDirectionForKey(const AtomicString& keyIdentifier)
2959 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
2960 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
2961 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
2962 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
2964 FocusType retVal = FocusTypeNone;
2966 if (keyIdentifier == Down)
2967 retVal = FocusTypeDown;
2968 else if (keyIdentifier == Up)
2969 retVal = FocusTypeUp;
2970 else if (keyIdentifier == Left)
2971 retVal = FocusTypeLeft;
2972 else if (keyIdentifier == Right)
2973 retVal = FocusTypeRight;
2978 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2980 if (event->type() == EventTypeNames::keydown) {
2981 m_frame->editor().handleKeyboardEvent(event);
2982 if (event->defaultHandled())
2984 if (event->keyIdentifier() == "U+0009")
2985 defaultTabEventHandler(event);
2986 else if (event->keyIdentifier() == "U+0008")
2987 defaultBackspaceEventHandler(event);
2988 else if (event->keyIdentifier() == "U+001B")
2989 defaultEscapeEventHandler(event);
2991 FocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
2992 if (type != FocusTypeNone)
2993 defaultArrowEventHandler(type, event);
2996 if (event->type() == EventTypeNames::keypress) {
2997 m_frame->editor().handleKeyboardEvent(event);
2998 if (event->defaultHandled())
3000 if (event->charCode() == ' ')
3001 defaultSpaceEventHandler(event);
3005 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3007 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3008 return dragHysteresisExceeded(dragViewportLocation);
3011 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3013 FrameView* view = m_frame->view();
3016 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3017 IntSize delta = dragLocation - m_mouseDownPos;
3019 int threshold = GeneralDragHysteresis;
3020 switch (dragState().m_dragType) {
3021 case DragSourceActionSelection:
3022 threshold = TextDragHysteresis;
3024 case DragSourceActionImage:
3025 threshold = ImageDragHysteresis;
3027 case DragSourceActionLink:
3028 threshold = LinkDragHysteresis;
3030 case DragSourceActionDHTML:
3032 case DragSourceActionNone:
3033 ASSERT_NOT_REACHED();
3036 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3039 void EventHandler::freeClipboard()
3041 if (dragState().m_dragClipboard)
3042 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3045 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3047 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3048 HitTestRequest request(HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3049 prepareMouseEvent(request, event);
3051 if (dragState().m_dragSrc) {
3052 dragState().m_dragClipboard->setDestinationOperation(operation);
3053 // for now we don't care if event handler cancels default behavior, since there is none
3054 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3057 dragState().m_dragSrc = nullptr;
3058 // In case the drag was ended due to an escape key press we need to ensure
3059 // that consecutive mousemove events don't reinitiate the drag and drop.
3060 m_mouseDownMayStartDrag = false;
3063 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3065 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3066 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3067 dragState().m_dragSrc = rootEditableElement;
3070 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3071 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3073 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3076 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3078 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3079 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3080 // events, causing page/FrameView to go away.
3082 ASSERT(m_frame->view());
3083 if (!m_frame->page())
3086 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3087 // If we allowed the other side of the bridge to handle a drag
3088 // last time, then m_mousePressed might still be set. So we
3089 // clear it now to make sure the next move after a drag
3090 // doesn't look like a drag.
3091 m_mousePressed = false;
3095 if (m_mouseDownMayStartDrag) {
3096 HitTestRequest request(HitTestRequest::ReadOnly);
3097 HitTestResult result(m_mouseDownPos);
3098 m_frame->contentRenderer()->hitTest(request, result);
3099 Node* node = result.innerNode();
3101 DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3102 ? DragController::DelayedSelectionDragResolution
3103 : DragController::ImmediateSelectionDragResolution;
3104 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3106 dragState().m_dragSrc = nullptr;
3109 if (!dragState().m_dragSrc)
3110 m_mouseDownMayStartDrag = false; // no element is draggable
3113 if (!m_mouseDownMayStartDrag)
3114 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3116 // We are starting a text/image/url drag, so the cursor should be an arrow
3117 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3118 m_frame->view()->setCursor(pointerCursor());
3120 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3123 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3126 if (!tryStartDrag(event)) {
3127 // Something failed to start the drag, clean up.
3129 dragState().m_dragSrc = nullptr;
3132 m_mouseDownMayStartDrag = false;
3133 // Whether or not the drag actually started, no more default handling (like selection).
3137 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3139 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3140 // to make sure it gets numbified
3141 dragState().m_dragClipboard = createDraggingClipboard();
3143 // Check to see if this a DOM based drag, if it is get the DOM specified drag
3145 if (dragState().m_dragType == DragSourceActionDHTML) {
3146 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3147 // FIXME: This doesn't work correctly with transforms.
3148 FloatPoint absPos = renderer->localToAbsolute();
3149 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3150 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3152 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3153 // the element in some way. In this case we just kill the drag.
3158 DragController& dragController = m_frame->page()->dragController();
3159 if (!dragController.populateDragClipboard(m_frame, dragState(), m_mouseDownPos))
3161 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3162 && !m_frame->selection().isInPasswordField();
3164 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3165 // image can still be changed as we drag, but not the pasteboard data.
3166 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3168 if (m_mouseDownMayStartDrag) {
3169 // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3170 m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3171 // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3172 // whether or not the drag started, but perhaps it can simply use the return value from
3173 // handleDrag(), even though it doesn't mean exactly the same thing.
3176 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3177 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3183 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3185 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3186 // and avoid dispatching text input events from keydown default handlers.
3187 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3192 EventTarget* target;
3193 if (underlyingEvent)
3194 target = underlyingEvent->target();
3196 target = eventTargetNodeForDocument(m_frame->document());
3200 RefPtrWillBeRawPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3201 event->setUnderlyingEvent(underlyingEvent);
3203 target->dispatchEvent(event, IGNORE_EXCEPTION);
3204 return event->defaultHandled();
3207 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3209 if (m_frame->editor().handleTextEvent(event))
3210 event->setDefaultHandled();
3213 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3215 ASSERT(event->type() == EventTypeNames::keypress);
3217 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3220 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3221 if (scroll(direction, ScrollByPage)) {
3222 event->setDefaultHandled();
3226 FrameView* view = m_frame->view();
3230 if (view->scroll(direction, ScrollByPage))
3231 event->setDefaultHandled();
3234 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3236 ASSERT(event->type() == EventTypeNames::keydown);
3238 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3241 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3244 Page* page = m_frame->page();
3247 bool handledEvent = page->mainFrame()->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3249 event->setDefaultHandled();
3252 void EventHandler::defaultArrowEventHandler(FocusType focusType, KeyboardEvent* event)
3254 ASSERT(event->type() == EventTypeNames::keydown);
3256 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3259 Page* page = m_frame->page();
3263 if (!isSpatialNavigationEnabled(m_frame))
3266 // Arrows and other possible directional navigation keys can be used in design
3268 if (m_frame->document()->inDesignMode())
3271 if (page->focusController().advanceFocus(focusType))
3272 event->setDefaultHandled();
3275 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3277 ASSERT(event->type() == EventTypeNames::keydown);
3279 // We should only advance focus on tabs if no special modifier keys are held down.
3280 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3283 Page* page = m_frame->page();
3286 if (!page->tabKeyCyclesThroughElements())
3289 FocusType focusType = event->shiftKey() ? FocusTypeBackward : FocusTypeForward;
3291 // Tabs can be used in design mode editing.
3292 if (m_frame->document()->inDesignMode())
3295 if (page->focusController().advanceFocus(focusType))
3296 event->setDefaultHandled();
3299 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3301 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3302 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3305 void EventHandler::capsLockStateMayHaveChanged()
3307 if (Element* element = m_frame->document()->focusedElement()) {
3308 if (RenderObject* r = element->renderer()) {
3309 if (r->isTextField())
3310 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3315 void EventHandler::setFrameWasScrolledByUser()
3317 if (FrameView* view = m_frame->view())
3318 view->setWasScrolledByUser(true);
3321 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3323 if (!scrollbar || !scrollbar->enabled())
3325 setFrameWasScrolledByUser();
3326 scrollbar->mouseDown(mev.event());
3330 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3331 // last to scrollbar if setLast is true; else set last to 0.
3332 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3334 if (m_lastScrollbarUnderMouse != scrollbar) {
3335 // Send mouse exited to the old scrollbar.
3336 if (m_lastScrollbarUnderMouse)
3337 m_lastScrollbarUnderMouse->mouseExited();
3339 // Send mouse entered if we're setting a new scrollbar.
3340 if (scrollbar && setLast)
3341 scrollbar->mouseEntered();
3343 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3347 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3350 case PlatformTouchPoint::TouchReleased:
3351 return EventTypeNames::touchend;
3352 case PlatformTouchPoint::TouchCancelled:
3353 return EventTypeNames::touchcancel;
3354 case PlatformTouchPoint::TouchPressed:
3355 return EventTypeNames::touchstart;
3356 case PlatformTouchPoint::TouchMoved:
3357 return EventTypeNames::touchmove;
3358 case PlatformTouchPoint::TouchStationary:
3359 // TouchStationary state is not converted to touch events, so fall through to assert.
3361 ASSERT_NOT_REACHED();
3366 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3368 HitTestResult result(point);
3370 if (!frame || !frame->contentRenderer())
3372 if (frame->view()) {
3373 IntRect rect = frame->view()->visibleContentRect();
3374 if (!rect.contains(roundedIntPoint(point)))
3377 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3381 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3383 TRACE_EVENT0("webkit", "EventHandler::handleTouchEvent");
3385 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3387 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3390 bool freshTouchEvents = true;
3391 bool allTouchReleased = true;
3392 for (i = 0; i < points.size(); ++i) {
3393 const PlatformTouchPoint& point = points[i];
3394 if (point.state() != PlatformTouchPoint::TouchPressed)
3395 freshTouchEvents = false;
3396 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3397 allTouchReleased = false;
3399 if (freshTouchEvents) {
3400 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3401 // have cleared the active document when we saw the last release. But we
3402 // have some tests that violate this, ClusterFuzz could trigger it, and
3403 // there may be cases where the browser doesn't reliably release all
3404 // touches. http://crbug.com/345372 tracks this.
3405 m_touchSequenceDocument.clear();
3408 // First do hit tests for any new touch points.
3409 for (i = 0; i < points.size(); ++i) {
3410 const PlatformTouchPoint& point = points[i];
3411 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3413 // Touch events implicitly capture to the touched node, and don't change
3414 // active/hover states themselves (Gesture events do). So we only need
3415 // to hit-test on touchstart, and it can be read-only.
3416 if (point.state() == PlatformTouchPoint::TouchPressed) {
3417 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3418 HitTestResult result;
3419 if (!m_touchSequenceDocument) {
3420 result = hitTestResultAtPoint(pagePoint, hitType);
3421 } else if (m_touchSequenceDocument->frame()) {
3422 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(m_touchSequenceDocument->frame(), point.pos());
3423 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), pagePointInOriginatingDocument, hitType);
3427 Node* node = result.innerNode();
3431 // Touch events should not go to text nodes
3432 if (node->isTextNode())
3433 node = NodeRenderingTraversal::parent(node);
3435 if (!m_touchSequenceDocument) {
3436 // Keep track of which document should receive all touch events
3437 // in the active sequence. This must be a single document to
3438 // ensure we don't leak Nodes between documents.
3439 m_touchSequenceDocument = &(result.innerNode()->document());
3442 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3443 // since we shouldn't get a touchstart for a touch that's already
3444 // down. However EventSender allows this to be violated and there's
3445 // some tests that take advantage of it. There may also be edge
3446 // cases in the browser where this happens.
3447 // See http://crbug.com/345372.
3448 m_targetForTouchID.set(point.id(), node);
3450 TouchAction effectiveTouchAction = computeEffectiveTouchAction(pagePoint);
3451 if (effectiveTouchAction != TouchActionAuto)
3452 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3456 m_touchPressed = !allTouchReleased;
3458 // If there's no document receiving touch events, or no handlers on the
3459 // document set to receive the events, then we can skip all the rest of
3461 if (!m_touchSequenceDocument || !m_touchSequenceDocument->hasTouchEventHandlers() || !m_touchSequenceDocument->frame()) {
3462 if (allTouchReleased)
3463 m_touchSequenceDocument.clear();
3467 // Build up the lists to use for the 'touches', 'targetTouches' and
3468 // 'changedTouches' attributes in the JS event. See
3469 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3470 // lists fit together.
3472 // Holds the complete set of touches on the screen.
3473 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3475 // A different view on the 'touches' list above, filtered and grouped by
3476 // event target. Used for the 'targetTouches' list in the JS event.
3477 typedef WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList> > TargetTouchesHeapMap;
3478 TargetTouchesHeapMap touchesByTarget;
3480 // Array of touches per state, used to assemble the 'changedTouches' list.
3481 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3483 // The touches corresponding to the particular change state this struct
3484 // instance represents.
3485 RefPtrWillBeMember<TouchList> m_touches;
3486 // Set of targets involved in m_touches.
3487 EventTargetSet m_targets;
3488 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3490 for (i = 0; i < points.size(); ++i) {
3491 const PlatformTouchPoint& point = points[i];
3492 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3493 PlatformTouchPoint::State pointState = point.state();
3494 RefPtr<EventTarget> touchTarget;
3496 if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3497 // The target should be the original target for this touch, so get
3498 // it from the hashmap. As it's a release or cancel we also remove
3500 touchTarget = m_targetForTouchID.take(point.id());
3502 // No hittest is performed on move or stationary, since the target
3503 // is not allowed to change anyway.
3504 touchTarget = m_targetForTouchID.get(point.id());
3507 LocalFrame* targetFrame;
3510 Document& doc = touchTarget->toNode()->document();
3511 ASSERT(&doc == m_touchSequenceDocument.get());
3512 targetFrame = doc.frame();
3515 // If we don't have a target registered for the point it means we've
3516 // missed our opportunity to do a hit test for it (due to some
3517 // optimization that prevented blink from ever seeing the
3518 // touchstart), or that the touch started outside the active touch
3519 // sequence document. We should still include the touch in the
3520 // Touches list reported to the application (eg. so it can
3521 // differentiate between a one and two finger gesture), but we won't
3522 // actually dispatch any events for it. Set the target to the
3523 // Document so that there's some valid node here. Perhaps this
3524 // should really be DOMWindow, but in all other cases the target of
3525 // a Touch is a Node so using the window could be a breaking change.
3526 // Since we know there was no handler invoked, the specific target
3527 // should be completely irrelevant to the application.
3528 touchTarget = m_touchSequenceDocument;
3529 targetFrame = m_touchSequenceDocument->frame();
3530 knownTarget = false;
3532 ASSERT(targetFrame);
3534 if (m_frame != targetFrame) {
3535 // pagePoint should always be relative to the target elements
3536 // containing frame.
3537 pagePoint = documentPointForWindowPoint(targetFrame, point.pos());
3540 float scaleFactor = targetFrame->pageZoomFactor();
3542 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3543 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3544 int adjustedRadiusX = lroundf(point.radiusX() / scaleFactor);
3545 int adjustedRadiusY = lroundf(point.radiusY() / scaleFactor);
3547 RefPtrWillBeRawPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3548 point.screenPos().x(), point.screenPos().y(),
3549 adjustedPageX, adjustedPageY,
3550 adjustedRadiusX, adjustedRadiusY,
3551 point.rotationAngle(), point.force());
3553 // Ensure this target's touch list exists, even if it ends up empty, so
3554 // it can always be passed to TouchEvent::Create below.
3555 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3556 if (targetTouchesIterator == touchesByTarget.end()) {
3557 touchesByTarget.set(touchTarget.get(), TouchList::create());
3558 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3561 // touches and targetTouches should only contain information about
3562 // touches still on the screen, so if this point is released or
3563 // cancelled it will only appear in the changedTouches list.
3564 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3565 touches->append(touch);
3566 targetTouchesIterator->value->append(touch);
3569 // Now build up the correct list for changedTouches.
3570 // Note that any touches that are in the TouchStationary state (e.g. if
3571 // the user had several points touched but did not move them all) should
3572 // never be in the changedTouches list so we do not handle them
3573 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
3574 // for further discussion about the TouchStationary state.
3575 if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) {
3576 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3577 if (!changedTouches[pointState].m_touches)
3578 changedTouches[pointState].m_touches = TouchList::create();
3579 changedTouches[pointState].m_touches->append(touch);
3580 changedTouches[pointState].m_targets.add(touchTarget);
3583 if (allTouchReleased)
3584 m_touchSequenceDocument.clear();
3586 // Now iterate the changedTouches list and m_targets within it, sending
3587 // events to the targets as required.
3588 bool swallowedEvent = false;
3589 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3590 if (!changedTouches[state].m_touches)
3593 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3594 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3595 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3596 EventTarget* touchEventTarget = it->get();
3597 RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create(
3598 touches.get(), touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(),
3599 stateName, touchEventTarget->toNode()->document().domWindow(),
3600 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.cancelable());
3601 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3602 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3606 return swallowedEvent;
3609 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
3611 if (action1 == TouchActionNone || action2 == TouchActionNone)
3612 return TouchActionNone;
3613 if (action1 == TouchActionAuto)
3615 if (action2 == TouchActionAuto)
3617 if (!(action1 & action2))
3618 return TouchActionNone;
3619 return action1 & action2;
3622 TouchAction EventHandler::computeEffectiveTouchAction(const LayoutPoint& point)
3624 // Optimization to minimize risk of this new feature (behavior should be identical
3625 // since there's no way to get non-default touch-action values).
3626 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
3627 return TouchActionAuto;
3629 HitTestResult taResult = hitTestResultAtPoint(point, HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::TouchAction);
3630 Node* node = taResult.innerNode();
3632 return TouchActionAuto;
3634 // Start by permitting all actions, then walk the elements supporting
3635 // touch-action from the target node up to the nearest scrollable ancestor
3636 // and exclude any prohibited actions.
3637 TouchAction effectiveTouchAction = TouchActionAuto;
3638 for (const Node* curNode = node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3639 if (RenderObject* renderer = curNode->renderer()) {
3640 if (renderer->visibleForTouchAction()) {
3641 TouchAction action = renderer->style()->touchAction();
3642 effectiveTouchAction = intersectTouchAction(action, effectiveTouchAction);
3643 if (effectiveTouchAction == TouchActionNone)
3647 // If we've reached an ancestor that supports a touch action, search no further.
3648 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3652 return effectiveTouchAction;
3655 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3657 m_mousePositionIsUnknown = false;
3658 m_lastKnownMousePosition = event.position();
3659 m_lastKnownMouseGlobalPosition = event.globalPosition();
3662 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3664 // If we're clicking into a frame that is selected, the frame will appear
3665 // greyed out even though we're clicking on the selection. This looks
3666 // really strange (having the whole frame be greyed out), so we deselect the
3668 IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3669 if (m_frame->selection().contains(p)) {
3670 VisiblePosition visiblePos(
3671 mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
3672 VisibleSelection newSelection(visiblePos);
3673 m_frame->selection().setSelection(newSelection);
3676 subframe->eventHandler().handleMousePressEvent(mev.event());
3680 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe, HitTestResult* hoveredNode)
3682 if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
3684 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3688 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3690 subframe->eventHandler().handleMouseReleaseEvent(mev.event());
3694 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
3696 // We can sometimes get a null widget! EventHandlerMac handles a null
3697 // widget by returning false, so we do the same.
3701 // If not a FrameView, then probably a plugin widget. Those will receive
3702 // the event via an EventTargetNode dispatch when this returns false.
3703 if (!widget->isFrameView())
3706 return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
3709 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
3711 // Figure out which view to send the event to.
3712 if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
3717 PassRefPtrWillBeRawPtr<Clipboard> EventHandler::createDraggingClipboard() const
3719 return Clipboard::create(Clipboard::DragAndDrop, ClipboardWritable, DataObject::create());
3722 void EventHandler::focusDocumentView()
3724 Page* page = m_frame->page();
3727 page->focusController().focusDocumentView(m_frame);
3730 unsigned EventHandler::accessKeyModifiers()
3733 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
3735 return PlatformEvent::AltKey;
3739 } // namespace WebCore