2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014 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 "EventHandler.h"
31 #include "AXObjectCache.h"
32 #include "AutoscrollController.h"
33 #include "BackForwardController.h"
34 #include "CachedImage.h"
36 #include "ChromeClient.h"
38 #include "CursorList.h"
40 #include "DocumentEventQueue.h"
41 #include "DragController.h"
42 #include "DragState.h"
44 #include "EditorClient.h"
45 #include "EventNames.h"
46 #include "ExceptionCodePlaceholder.h"
48 #include "FloatPoint.h"
49 #include "FloatRect.h"
50 #include "FocusController.h"
51 #include "FrameLoader.h"
52 #include "FrameSelection.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "htmlediting.h"
56 #include "HTMLFrameElementBase.h"
57 #include "HTMLFrameSetElement.h"
58 #include "HTMLInputElement.h"
59 #include "HTMLNames.h"
60 #include "HitTestRequest.h"
61 #include "HitTestResult.h"
63 #include "InspectorInstrumentation.h"
64 #include "KeyboardEvent.h"
65 #include "MainFrame.h"
66 #include "MouseEvent.h"
67 #include "MouseEventWithHitTestResults.h"
69 #include "PlatformEvent.h"
70 #include "PlatformKeyboardEvent.h"
71 #include "PlatformWheelEvent.h"
72 #include "PluginDocument.h"
73 #include "RenderFrameSet.h"
74 #include "RenderLayer.h"
75 #include "RenderTextControlSingleLine.h"
76 #include "RenderView.h"
77 #include "RenderWidget.h"
78 #include "RuntimeApplicationChecks.h"
79 #include "SVGDocument.h"
80 #include "SVGElementInstance.h"
82 #include "SVGUseElement.h"
83 #include "ScrollAnimator.h"
84 #include "Scrollbar.h"
86 #include "ShadowRoot.h"
87 #include "SpatialNavigation.h"
88 #include "StyleCachedImage.h"
89 #include "TextEvent.h"
90 #include "TextIterator.h"
91 #include "UserGestureIndicator.h"
92 #include "UserTypingGestureIndicator.h"
93 #include "WheelEvent.h"
94 #include "WindowsKeyboardCodes.h"
95 #include <wtf/Assertions.h>
96 #include <wtf/CurrentTime.h>
97 #include <wtf/StdLibExtras.h>
98 #include <wtf/TemporaryChange.h>
100 #if ENABLE(TOUCH_EVENTS)
101 #if ENABLE(IOS_TOUCH_EVENTS)
102 #include "PlatformTouchEventIOS.h"
104 #include "PlatformTouchEvent.h"
106 #include "TouchEvent.h"
107 #include "TouchList.h"
110 #if ENABLE(CSS_IMAGE_SET)
111 #include "StyleCachedImageSet.h"
116 using namespace HTMLNames;
118 #if ENABLE(DRAG_SUPPORT)
119 // The link drag hysteresis is much larger than the others because there
120 // needs to be enough space to cancel the link press without starting a link drag,
121 // and because dragging links is rare.
122 const int LinkDragHysteresis = 40;
123 const int ImageDragHysteresis = 5;
124 const int TextDragHysteresis = 3;
125 const int GeneralDragHysteresis = 3;
126 #endif // ENABLE(DRAG_SUPPORT)
128 #if ENABLE(IOS_GESTURE_EVENTS)
129 const float GestureUnknown = 0;
132 #if ENABLE(IOS_TOUCH_EVENTS)
133 // FIXME: Share this constant with EventHandler and SliderThumbElement.
134 const unsigned InvalidTouchIdentifier = 0;
137 // Match key code of composition keydown event on windows.
138 // IE sends VK_PROCESSKEY which has value 229;
139 const int CompositionEventKeyCode = 229;
141 using namespace SVGNames;
143 // The amount of time to wait before sending a fake mouse event, triggered
144 // during a scroll. The short interval is used if the content responds to the mouse events
145 // in fakeMouseMoveDurationThreshold or less, otherwise the long interval is used.
146 const double fakeMouseMoveDurationThreshold = 0.01;
147 const double fakeMouseMoveShortInterval = 0.1;
148 const double fakeMouseMoveLongInterval = 0.25;
150 #if ENABLE(CURSOR_SUPPORT)
151 // The amount of time to wait for a cursor update on style and layout changes
152 // Set to 50Hz, no need to be faster than common screen refresh rate
153 const double cursorUpdateInterval = 0.02;
155 const int maximumCursorSize = 128;
158 #if ENABLE(MOUSE_CURSOR_SCALE)
159 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
160 // need to ensure here is that the scale isn't so small that integer overflow can occur when
161 // dividing cursor sizes (limited above) by the scale.
162 const double minimumCursorScale = 0.001;
165 enum NoCursorChangeType { NoCursorChange };
167 class OptionalCursor {
169 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
170 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
172 bool isCursorChange() const { return m_isCursorChange; }
173 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
176 bool m_isCursorChange;
180 class MaximumDurationTracker {
182 explicit MaximumDurationTracker(double *maxDuration)
183 : m_maxDuration(maxDuration)
184 , m_start(monotonicallyIncreasingTime())
188 ~MaximumDurationTracker()
190 *m_maxDuration = std::max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
194 double* m_maxDuration;
198 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
199 class SyntheticTouchPoint : public PlatformTouchPoint {
202 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
203 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
205 const static int idDefaultValue = 0;
206 const static int radiusYDefaultValue = 1;
207 const static int radiusXDefaultValue = 1;
208 const static float rotationAngleDefaultValue = 0.0f;
209 const static float forceDefaultValue = 1.0f;
211 m_id = idDefaultValue; // There is only one active TouchPoint.
212 m_screenPos = event.globalPosition();
213 m_pos = event.position();
214 m_radiusY = radiusYDefaultValue;
215 m_radiusX = radiusXDefaultValue;
216 m_rotationAngle = rotationAngleDefaultValue;
217 m_force = forceDefaultValue;
219 PlatformEvent::Type type = event.type();
220 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
223 case PlatformEvent::MouseMoved:
224 m_state = TouchMoved;
226 case PlatformEvent::MousePressed:
227 m_state = TouchPressed;
229 case PlatformEvent::MouseReleased:
230 m_state = TouchReleased;
233 ASSERT_NOT_REACHED();
239 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
241 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
243 switch (event.type()) {
244 case PlatformEvent::MouseMoved:
247 case PlatformEvent::MousePressed:
250 case PlatformEvent::MouseReleased:
254 ASSERT_NOT_REACHED();
258 m_timestamp = event.timestamp();
259 m_modifiers = event.modifiers();
260 m_touchPoints.append(SyntheticTouchPoint(event));
263 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
265 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
268 case WheelEvent::DOM_DELTA_PAGE:
270 case WheelEvent::DOM_DELTA_LINE:
272 case WheelEvent::DOM_DELTA_PIXEL:
273 return ScrollByPixel;
275 return ScrollByPixel;
279 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Element** stopElement, const IntPoint& wheelEventAbsolutePoint)
283 if (!node->renderer())
285 RenderBox* enclosingBox = node->renderer()->enclosingBox();
286 float absDelta = delta > 0 ? delta : -delta;
288 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopElement, enclosingBox, wheelEventAbsolutePoint);
291 #if (ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS))
292 static inline bool shouldGesturesTriggerActive()
294 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
295 // rely on them to set the active state. Unfortunately there's no generic way to
296 // know in advance what event types are supported.
303 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
308 #if ENABLE(DRAG_SUPPORT)
309 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
317 EventHandler::EventHandler(Frame& frame)
319 , m_mousePressed(false)
320 , m_capturesDragging(false)
321 , m_mouseDownMayStartSelect(false)
322 #if ENABLE(DRAG_SUPPORT)
323 , m_mouseDownMayStartDrag(false)
324 , m_dragMayStartSelectionInstead(false)
326 , m_mouseDownWasSingleClickInSelection(false)
327 , m_selectionInitiationState(HaveNotStartedSelection)
328 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
329 #if ENABLE(CURSOR_SUPPORT)
330 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
332 , m_autoscrollController(adoptPtr(new AutoscrollController))
333 , m_mouseDownMayStartAutoscroll(false)
334 , m_mouseDownWasInSubframe(false)
335 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
338 , m_eventHandlerWillResetCapturingMouseEventsElement(nullptr)
340 #if ENABLE(IOS_GESTURE_EVENTS)
341 , m_gestureInitialDiameter(GestureUnknown)
342 , m_gestureLastDiameter(GestureUnknown)
343 , m_gestureInitialRotation(GestureUnknown)
344 , m_gestureLastRotation(GestureUnknown)
346 #if ENABLE(IOS_TOUCH_EVENTS)
347 , m_firstTouchID(InvalidTouchIdentifier)
349 , m_mousePositionIsUnknown(true)
350 , m_mouseDownTimestamp(0)
351 , m_recentWheelEventDeltaTracker(adoptPtr(new WheelEventDeltaTracker))
352 , m_widgetIsLatched(false)
354 , m_mouseDownView(nil)
355 , m_sendingEventToSubview(false)
357 , m_activationEventNumber(-1)
358 #endif // !PLATFORM(IOS)
360 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
361 , m_originatingTouchPointTargetKey(0)
362 , m_touchPressed(false)
364 , m_maxMouseMovedDuration(0)
365 , m_baseEventType(PlatformEvent::NoType)
366 , m_didStartDrag(false)
367 , m_didLongPressInvokeContextMenu(false)
368 , m_isHandlingWheelEvent(false)
369 #if ENABLE(CURSOR_VISIBILITY)
370 , m_autoHideCursorTimer(this, &EventHandler::autoHideCursorTimerFired)
375 EventHandler::~EventHandler()
377 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
378 #if ENABLE(CURSOR_VISIBILITY)
379 ASSERT(!m_autoHideCursorTimer.isActive());
383 #if ENABLE(DRAG_SUPPORT)
384 DragState& EventHandler::dragState()
386 DEFINE_STATIC_LOCAL(DragState, state, ());
389 #endif // ENABLE(DRAG_SUPPORT)
391 void EventHandler::clear()
394 #if ENABLE(CURSOR_SUPPORT)
395 m_cursorUpdateTimer.stop();
397 m_fakeMouseMoveEventTimer.stop();
398 #if ENABLE(CURSOR_VISIBILITY)
399 cancelAutoHideCursorTimer();
402 m_elementUnderMouse = nullptr;
403 m_lastElementUnderMouse = nullptr;
404 m_instanceUnderMouse = 0;
405 m_lastInstanceUnderMouse = 0;
406 m_lastMouseMoveEventSubframe = 0;
407 m_lastScrollbarUnderMouse = 0;
410 #if ENABLE(IOS_GESTURE_EVENTS)
411 m_gestureInitialDiameter = GestureUnknown;
412 m_gestureLastDiameter = GestureUnknown;
413 m_gestureInitialRotation = GestureUnknown;
414 m_gestureLastRotation = GestureUnknown;
415 m_gestureTargets.clear();
417 #if ENABLE(IOS_TOUCH_EVENTS)
419 m_firstTouchID = InvalidTouchIdentifier;
420 m_touchEventTargetSubframe = 0;
422 m_frameSetBeingResized = 0;
423 #if ENABLE(DRAG_SUPPORT)
425 m_shouldOnlyFireDragOverEvent = false;
427 m_mousePositionIsUnknown = true;
428 m_lastKnownMousePosition = IntPoint();
429 m_lastKnownMouseGlobalPosition = IntPoint();
430 m_mousePressNode = 0;
431 m_mousePressed = false;
432 m_capturesDragging = false;
433 m_capturingMouseEventsElement = nullptr;
434 m_latchedWheelEventElement = nullptr;
435 m_previousWheelScrolledElement = nullptr;
436 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
437 m_originatingTouchPointTargets.clear();
438 m_originatingTouchPointDocument.clear();
439 m_originatingTouchPointTargetKey = 0;
441 m_maxMouseMovedDuration = 0;
442 m_baseEventType = PlatformEvent::NoType;
443 m_didStartDrag = false;
444 m_didLongPressInvokeContextMenu = false;
447 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
449 if (nodeToBeRemoved->contains(m_clickNode.get()))
453 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
455 if (selection.selection() != newSelection && selection.shouldChangeSelection(newSelection))
456 selection.setSelection(newSelection);
459 static inline bool dispatchSelectStart(Node* node)
461 if (!node || !node->renderer())
464 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
467 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
469 #if ENABLE(USERSELECT_ALL)
470 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
471 if (!rootUserSelectAll)
474 VisibleSelection newSelection(selection);
475 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
476 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
480 UNUSED_PARAM(targetNode);
485 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
487 if (Position::nodeIsUserSelectNone(targetNode))
490 if (!dispatchSelectStart(targetNode))
493 if (selection.isRange())
494 m_selectionInitiationState = ExtendedSelection;
496 granularity = CharacterGranularity;
497 m_selectionInitiationState = PlacedCaret;
500 m_frame.selection().setSelectionByMouseIfDifferent(selection, granularity);
505 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
507 Node* targetNode = result.targetNode();
508 VisibleSelection newSelection;
510 if (targetNode && targetNode->renderer()) {
511 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint()));
512 if (pos.isNotNull()) {
513 newSelection = VisibleSelection(pos);
514 newSelection.expandUsingGranularity(WordGranularity);
517 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
518 newSelection.appendTrailingWhitespace();
520 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), WordGranularity);
524 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
526 if (m_mouseDownMayStartSelect) {
527 selectClosestWordFromHitTestResult(result.hitTestResult(),
528 (result.event().clickCount() == 2 && m_frame.editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
532 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
534 if (!result.hitTestResult().isLiveLink())
535 return selectClosestWordFromMouseEvent(result);
537 Node* targetNode = result.targetNode();
539 if (targetNode && targetNode->renderer() && m_mouseDownMayStartSelect) {
540 VisibleSelection newSelection;
541 Element* URLElement = result.hitTestResult().URLElement();
542 VisiblePosition pos(targetNode->renderer()->positionForPoint(result.localPoint()));
543 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
544 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
546 updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), WordGranularity);
550 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
552 if (event.event().button() != LeftButton)
555 if (m_frame.selection().isRange())
556 // A double-click when range is already selected
557 // should not change the selection. So, do not call
558 // selectClosestWordFromMouseEvent, but do set
559 // m_beganSelectingText to prevent handleMouseReleaseEvent
560 // from setting caret selection.
561 m_selectionInitiationState = ExtendedSelection;
563 selectClosestWordFromMouseEvent(event);
568 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
570 if (event.event().button() != LeftButton)
573 Node* targetNode = event.targetNode();
574 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
577 VisibleSelection newSelection;
578 VisiblePosition pos(targetNode->renderer()->positionForPoint(event.localPoint()));
579 if (pos.isNotNull()) {
580 newSelection = VisibleSelection(pos);
581 newSelection.expandUsingGranularity(ParagraphGranularity);
584 return updateSelectionForMouseDownDispatchingSelectStart(targetNode, expandSelectionToRespectUserSelectAll(targetNode, newSelection), ParagraphGranularity);
587 static int textDistance(const Position& start, const Position& end)
589 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
590 return TextIterator::rangeLength(range.get(), true);
593 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
595 m_frame.document()->updateLayoutIgnorePendingStylesheets();
596 Node* targetNode = event.targetNode();
597 if (!(targetNode && targetNode->renderer() && m_mouseDownMayStartSelect))
600 // Extend the selection if the Shift key is down, unless the click is in a link.
601 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
603 // Don't restart the selection when the mouse is pressed on an
604 // existing selection so we can allow for text dragging.
605 if (FrameView* view = m_frame.view()) {
606 LayoutPoint vPoint = view->windowToContents(event.event().position());
607 if (!extendSelection && m_frame.selection().contains(vPoint)) {
608 m_mouseDownWasSingleClickInSelection = true;
613 VisiblePosition visiblePos(targetNode->renderer()->positionForPoint(event.localPoint()));
614 if (visiblePos.isNull())
615 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(targetNode), DOWNSTREAM);
616 Position pos = visiblePos.deepEquivalent();
618 VisibleSelection newSelection = m_frame.selection().selection();
619 TextGranularity granularity = CharacterGranularity;
621 if (extendSelection && newSelection.isCaretOrRange()) {
622 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectUserSelectAll(targetNode, VisibleSelection(pos));
623 if (selectionInUserSelectAll.isRange()) {
624 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
625 pos = selectionInUserSelectAll.start();
626 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
627 pos = selectionInUserSelectAll.end();
630 if (!m_frame.editor().behavior().shouldConsiderSelectionAsDirectional() && pos.isNotNull()) {
631 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
632 // was created right-to-left
633 Position start = newSelection.start();
634 Position end = newSelection.end();
635 int distanceToStart = textDistance(start, pos);
636 int distanceToEnd = textDistance(pos, end);
637 if (distanceToStart <= distanceToEnd)
638 newSelection = VisibleSelection(end, pos);
640 newSelection = VisibleSelection(start, pos);
642 newSelection.setExtent(pos);
644 if (m_frame.selection().granularity() != CharacterGranularity) {
645 granularity = m_frame.selection().granularity();
646 newSelection.expandUsingGranularity(m_frame.selection().granularity());
649 newSelection = expandSelectionToRespectUserSelectAll(targetNode, visiblePos);
651 bool handled = updateSelectionForMouseDownDispatchingSelectStart(targetNode, newSelection, granularity);
653 if (event.event().button() == MiddleButton) {
654 // Ignore handled, since we want to paste to where the caret was placed anyway.
655 handled = handlePasteGlobalSelection(event.event()) || handled;
660 static inline bool canMouseDownStartSelect(Node* node)
662 if (!node || !node->renderer())
665 return node->canStartSelection() || Position::nodeIsUserSelectAll(node);
668 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
670 #if ENABLE(DRAG_SUPPORT)
672 dragState().source = 0;
675 cancelFakeMouseMoveEvent();
677 m_frame.document()->updateLayoutIgnorePendingStylesheets();
679 if (ScrollView* scrollView = m_frame.view()) {
680 if (scrollView->isPointInScrollbarCorner(event.event().position()))
684 bool singleClick = event.event().clickCount() <= 1;
686 // If we got the event back, that must mean it wasn't prevented,
687 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
688 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
690 #if ENABLE(DRAG_SUPPORT)
691 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
692 m_mouseDownMayStartDrag = singleClick;
695 m_mouseDownWasSingleClickInSelection = false;
697 m_mouseDown = event.event();
699 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
702 if (m_frame.document()->isSVGDocument()
703 && toSVGDocument(m_frame.document())->zoomAndPanEnabled()) {
704 if (event.event().shiftKey() && singleClick) {
706 toSVGDocument(m_frame.document())->startPan(m_frame.view()->windowToContents(event.event().position()));
711 // We don't do this at the start of mouse down handling,
712 // because we don't want to do it until we know we didn't hit a widget.
716 m_mousePressNode = event.targetNode();
717 #if ENABLE(DRAG_SUPPORT)
718 m_dragStartPos = event.event().position();
721 bool swallowEvent = false;
722 m_mousePressed = true;
723 m_selectionInitiationState = HaveNotStartedSelection;
725 if (event.event().clickCount() == 2)
726 swallowEvent = handleMousePressEventDoubleClick(event);
727 else if (event.event().clickCount() >= 3)
728 swallowEvent = handleMousePressEventTripleClick(event);
730 swallowEvent = handleMousePressEventSingleClick(event);
732 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
733 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
738 #if ENABLE(DRAG_SUPPORT)
739 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
744 if (handleDrag(event, ShouldCheckDragHysteresis))
747 Node* targetNode = event.targetNode();
748 if (event.event().button() != LeftButton || !targetNode)
751 RenderObject* renderer = targetNode->renderer();
753 Element* parent = targetNode->parentOrShadowHostElement();
757 renderer = parent->renderer();
758 if (!renderer || !renderer->isListBox())
762 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
763 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
766 m_mouseDownMayStartDrag = false;
768 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
769 m_autoscrollController->startAutoscrollForSelection(renderer);
770 m_mouseDownMayStartAutoscroll = false;
773 if (m_selectionInitiationState != ExtendedSelection) {
774 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
775 HitTestResult result(m_mouseDownPos);
776 m_frame.document()->renderView()->hitTest(request, result);
778 updateSelectionForMouseDrag(result);
780 updateSelectionForMouseDrag(event.hitTestResult());
784 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
786 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
787 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
788 // in handleMousePressEvent
790 if (!m_frame.contentRenderer() || !m_frame.contentRenderer()->hasLayer())
793 if (event.button() != LeftButton || event.clickCount() != 1)
796 FrameView* view = m_frame.view();
800 Page* page = m_frame.page();
804 updateDragSourceActionsAllowed();
805 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
806 HitTestResult result(view->windowToContents(event.position()));
807 m_frame.contentRenderer()->hitTest(request, result);
809 return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
812 void EventHandler::updateSelectionForMouseDrag()
814 FrameView* view = m_frame.view();
817 RenderView* renderer = m_frame.contentRenderer();
821 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
822 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
823 renderer->hitTest(request, result);
824 updateSelectionForMouseDrag(result);
827 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
829 LayoutPoint selectionEndPoint = localPoint;
830 Element* editableElement = selection.rootEditableElement();
832 if (!targetNode->renderer())
833 return VisiblePosition();
835 if (editableElement && !editableElement->contains(targetNode)) {
836 if (!editableElement->renderer())
837 return VisiblePosition();
839 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
840 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
841 targetNode = editableElement;
844 return targetNode->renderer()->positionForPoint(selectionEndPoint);
847 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
849 if (!m_mouseDownMayStartSelect)
852 Node* target = hitTestResult.targetNode();
856 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame.selection().selection(), hitTestResult.localPoint(), target);
858 // Don't modify the selection if we're not on a node.
859 if (targetPosition.isNull())
862 // Restart the selection if this is the first mouse move. This work is usually
863 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
864 VisibleSelection newSelection = m_frame.selection().selection();
866 // Special case to limit selection to the containing block for SVG text.
867 // FIXME: Isn't there a better non-SVG-specific way to do this?
868 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
869 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
870 if (selectionBaseRenderer->isSVGText())
871 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
874 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
877 if (m_selectionInitiationState != ExtendedSelection) {
878 // Always extend selection here because it's caused by a mouse drag
879 m_selectionInitiationState = ExtendedSelection;
880 newSelection = VisibleSelection(targetPosition);
883 #if ENABLE(USERSELECT_ALL)
884 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
885 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
886 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
887 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
889 // Reset base for user select all when base is inside user-select-all area and extent < base.
890 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
891 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
893 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
894 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
895 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
896 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
897 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
899 newSelection.setExtent(targetPosition);
902 newSelection.setExtent(targetPosition);
905 if (m_frame.selection().granularity() != CharacterGranularity)
906 newSelection.expandUsingGranularity(m_frame.selection().granularity());
908 m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
909 FrameSelection::AdjustEndpointsAtBidiBoundary);
911 #endif // ENABLE(DRAG_SUPPORT)
913 void EventHandler::lostMouseCapture()
915 m_frame.selection().setCaretBlinkingSuspended(false);
918 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
920 if (eventLoopHandleMouseUp(event))
923 // If this was the first click in the window, we don't even want to clear the selection.
924 // This case occurs when the user clicks on a draggable element, since we have to process
925 // the mouse down and drag events to see if we might start a drag. For other first clicks
926 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
927 // ignored upstream of this layer.
928 return eventActivatedView(event.event());
931 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
933 if (autoscrollInProgress())
934 stopAutoscrollTimer();
936 if (handleMouseUp(event))
939 // Used to prevent mouseMoveEvent from initiating a drag before
940 // the mouse is pressed again.
941 m_mousePressed = false;
942 m_capturesDragging = false;
943 #if ENABLE(DRAG_SUPPORT)
944 m_mouseDownMayStartDrag = false;
946 m_mouseDownMayStartSelect = false;
947 m_mouseDownMayStartAutoscroll = false;
948 m_mouseDownWasInSubframe = false;
950 bool handled = false;
952 // Clear the selection if the mouse didn't move after the last mouse
953 // press and it's not a context menu click. We do this so when clicking
954 // on the selection, the selection goes away. However, if we are
955 // editing, place the caret.
956 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
957 #if ENABLE(DRAG_SUPPORT)
958 && m_dragStartPos == event.event().position()
960 && m_frame.selection().isRange()
961 && event.event().button() != RightButton) {
962 VisibleSelection newSelection;
963 Node* node = event.targetNode();
964 bool caretBrowsing = m_frame.settings().caretBrowsingEnabled();
965 if (node && node->renderer() && (caretBrowsing || node->hasEditableStyle())) {
966 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
967 newSelection = VisibleSelection(pos);
970 setSelectionIfNeeded(m_frame.selection(), newSelection);
975 if (event.event().button() == MiddleButton) {
976 // Ignore handled, since we want to paste to where the caret was placed anyway.
977 handled = handlePasteGlobalSelection(event.event()) || handled;
983 #if ENABLE(PAN_SCROLLING)
985 void EventHandler::didPanScrollStart()
987 m_autoscrollController->didPanScrollStart();
990 void EventHandler::didPanScrollStop()
992 m_autoscrollController->didPanScrollStop();
995 void EventHandler::startPanScrolling(RenderElement* renderer)
998 if (!renderer->isBox())
1000 m_autoscrollController->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
1005 #endif // ENABLE(PAN_SCROLLING)
1007 RenderBox* EventHandler::autoscrollRenderer() const
1009 return m_autoscrollController->autoscrollRenderer();
1012 void EventHandler::updateAutoscrollRenderer()
1014 m_autoscrollController->updateAutoscrollRenderer();
1017 bool EventHandler::autoscrollInProgress() const
1019 return m_autoscrollController->autoscrollInProgress();
1022 bool EventHandler::panScrollInProgress() const
1024 return m_autoscrollController->panScrollInProgress();
1027 #if ENABLE(DRAG_SUPPORT)
1028 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1030 Page* page = m_frame.page();
1032 return DragSourceActionNone;
1034 FrameView* view = m_frame.view();
1036 return DragSourceActionNone;
1038 return page->dragController().delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1040 #endif // ENABLE(DRAG_SUPPORT)
1042 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1044 // We always send hitTestResultAtPoint to the main frame if we have one,
1045 // otherwise we might hit areas that are obscured by higher frames.
1046 if (!m_frame.isMainFrame()) {
1047 Frame& mainFrame = m_frame.mainFrame();
1048 FrameView* frameView = m_frame.view();
1049 FrameView* mainView = mainFrame.view();
1050 if (frameView && mainView) {
1051 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
1052 return mainFrame.eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
1056 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
1058 if (!m_frame.contentRenderer())
1061 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
1062 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
1063 m_frame.contentRenderer()->hitTest(request, result);
1064 if (!request.readOnly())
1065 m_frame.document()->updateHoverActiveState(request, result.innerElement());
1067 if (request.disallowsShadowContent())
1068 result.setToNonShadowAncestor();
1073 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1075 m_autoscrollController->stopAutoscrollTimer(rendererIsBeingDestroyed);
1078 Node* EventHandler::mousePressNode() const
1080 return m_mousePressNode.get();
1083 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1085 m_mousePressNode = node;
1088 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1090 Node* node = startingNode;
1093 node = m_frame.document()->focusedElement();
1096 node = m_mousePressNode.get();
1099 auto r = node->renderer();
1100 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1101 setFrameWasScrolledByUser();
1109 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1111 Node* node = startingNode;
1114 node = m_frame.document()->focusedElement();
1117 node = m_mousePressNode.get();
1120 auto r = node->renderer();
1121 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1122 setFrameWasScrolledByUser();
1130 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1132 // The layout needs to be up to date to determine if we can scroll. We may be
1133 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1134 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1135 if (scrollOverflow(direction, granularity, startingNode))
1137 Frame* frame = &m_frame;
1138 FrameView* view = frame->view();
1139 if (view && view->scroll(direction, granularity))
1141 frame = frame->tree().parent();
1144 return frame->eventHandler().scrollRecursively(direction, granularity, m_frame.ownerElement());
1147 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1149 // The layout needs to be up to date to determine if we can scroll. We may be
1150 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1151 m_frame.document()->updateLayoutIgnorePendingStylesheets();
1152 if (logicalScrollOverflow(direction, granularity, startingNode))
1154 Frame* frame = &m_frame;
1155 FrameView* view = frame->view();
1157 bool scrolled = false;
1159 // Mac also resets the scroll position in the inline direction.
1160 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1163 if (view && view->logicalScroll(direction, granularity))
1169 frame = frame->tree().parent();
1173 return frame->eventHandler().logicalScrollRecursively(direction, granularity, m_frame.ownerElement());
1176 IntPoint EventHandler::lastKnownMousePosition() const
1178 return m_lastKnownMousePosition;
1181 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1183 if (!hitTestResult.isOverWidget())
1185 return subframeForTargetNode(hitTestResult.targetNode());
1188 Frame* EventHandler::subframeForTargetNode(Node* node)
1193 auto renderer = node->renderer();
1194 if (!renderer || !renderer->isWidget())
1197 Widget* widget = toRenderWidget(renderer)->widget();
1198 if (!widget || !widget->isFrameView())
1201 return &toFrameView(widget)->frame();
1204 #if ENABLE(CURSOR_SUPPORT)
1205 static bool isSubmitImage(Node* node)
1207 return node && isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
1210 // Returns true if the node's editable block is not current focused for editing
1211 static bool nodeIsNotBeingEdited(const Node& node, const Frame& frame)
1213 return frame.selection().selection().rootEditableElement() != node.rootEditableElement();
1216 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1221 bool editable = node->hasEditableStyle();
1222 bool editableLinkEnabled = false;
1224 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1226 switch (m_frame.settings().editableLinkBehavior()) {
1228 case EditableLinkDefaultBehavior:
1229 case EditableLinkAlwaysLive:
1230 editableLinkEnabled = true;
1233 case EditableLinkNeverLive:
1234 editableLinkEnabled = false;
1237 case EditableLinkLiveWhenNotFocused:
1238 editableLinkEnabled = nodeIsNotBeingEdited(*node, m_frame) || shiftKey;
1241 case EditableLinkOnlyLiveWithShiftKey:
1242 editableLinkEnabled = shiftKey;
1247 return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1250 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>&)
1252 ASSERT(m_frame.document());
1256 void EventHandler::updateCursor()
1258 if (m_mousePositionIsUnknown)
1261 FrameView* view = m_frame.view();
1265 RenderView* renderView = view->renderView();
1269 if (!view->shouldSetCursor())
1276 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1278 m_frame.document()->updateLayout();
1280 HitTestRequest request(HitTestRequest::ReadOnly);
1281 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1282 renderView->hitTest(request, result);
1284 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1285 if (optionalCursor.isCursorChange()) {
1286 m_currentMouseCursor = optionalCursor.cursor();
1287 view->setCursor(m_currentMouseCursor);
1291 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1293 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1294 return NoCursorChange;
1296 if (!m_frame.page())
1297 return NoCursorChange;
1299 #if ENABLE(PAN_SCROLLING)
1300 if (m_frame.mainFrame().eventHandler().panScrollInProgress())
1301 return NoCursorChange;
1304 Node* node = result.targetNode();
1306 return NoCursorChange;
1308 auto renderer = node->renderer();
1309 RenderStyle* style = renderer ? &renderer->style() : nullptr;
1310 bool horizontalText = !style || style->isHorizontalWritingMode();
1311 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1313 #if ENABLE(CURSOR_VISIBILITY)
1314 if (style && style->cursorVisibility() == CursorVisibilityAutoHide) {
1315 FeatureObserver::observe(m_frame.document(), FeatureObserver::CursorVisibility);
1316 startAutoHideCursorTimer();
1318 cancelAutoHideCursorTimer();
1322 Cursor overrideCursor;
1323 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1324 case SetCursorBasedOnStyle:
1327 return overrideCursor;
1328 case DoNotSetCursor:
1329 return NoCursorChange;
1333 if (style && style->cursors()) {
1334 const CursorList* cursors = style->cursors();
1335 for (unsigned i = 0; i < cursors->size(); ++i) {
1336 StyleImage* styleImage = (*cursors)[i].image();
1339 CachedImage* cachedImage = styleImage->cachedImage();
1342 float scale = styleImage->imageScaleFactor();
1343 // Get hotspot and convert from logical pixels to physical pixels.
1344 IntPoint hotSpot = (*cursors)[i].hotSpot();
1345 hotSpot.scale(scale, scale);
1346 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1347 if (cachedImage->errorOccurred())
1349 // Limit the size of cursors (in UI pixels) so that they cannot be
1350 // used to cover UI elements in chrome.
1351 size.scale(1 / scale);
1352 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1355 Image* image = cachedImage->imageForRenderer(renderer);
1356 #if ENABLE(MOUSE_CURSOR_SCALE)
1357 // Ensure no overflow possible in calculations above.
1358 if (scale < minimumCursorScale)
1360 return Cursor(image, hotSpot, scale);
1363 return Cursor(image, hotSpot);
1364 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1368 switch (style ? style->cursor() : CURSOR_AUTO) {
1370 bool editable = node->hasEditableStyle();
1372 if (useHandCursor(node, result.isOverLink(), shiftKey))
1373 return handCursor();
1375 bool inResizer = false;
1377 if (RenderLayer* layer = renderer->enclosingLayer()) {
1378 if (FrameView* view = m_frame.view())
1379 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1383 // During selection, use an I-beam regardless of the content beneath the cursor when cursor style is not explicitly specified.
1384 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1385 if (m_mousePressed && m_mouseDownMayStartSelect
1386 #if ENABLE(DRAG_SUPPORT)
1387 && !m_mouseDownMayStartDrag
1389 && m_frame.selection().isCaretOrRange()
1390 && !m_capturingMouseEventsElement) {
1394 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1396 return pointerCursor();
1399 return crossCursor();
1400 case CURSOR_POINTER:
1401 return handCursor();
1403 return moveCursor();
1404 case CURSOR_ALL_SCROLL:
1405 return moveCursor();
1406 case CURSOR_E_RESIZE:
1407 return eastResizeCursor();
1408 case CURSOR_W_RESIZE:
1409 return westResizeCursor();
1410 case CURSOR_N_RESIZE:
1411 return northResizeCursor();
1412 case CURSOR_S_RESIZE:
1413 return southResizeCursor();
1414 case CURSOR_NE_RESIZE:
1415 return northEastResizeCursor();
1416 case CURSOR_SW_RESIZE:
1417 return southWestResizeCursor();
1418 case CURSOR_NW_RESIZE:
1419 return northWestResizeCursor();
1420 case CURSOR_SE_RESIZE:
1421 return southEastResizeCursor();
1422 case CURSOR_NS_RESIZE:
1423 return northSouthResizeCursor();
1424 case CURSOR_EW_RESIZE:
1425 return eastWestResizeCursor();
1426 case CURSOR_NESW_RESIZE:
1427 return northEastSouthWestResizeCursor();
1428 case CURSOR_NWSE_RESIZE:
1429 return northWestSouthEastResizeCursor();
1430 case CURSOR_COL_RESIZE:
1431 return columnResizeCursor();
1432 case CURSOR_ROW_RESIZE:
1433 return rowResizeCursor();
1435 return iBeamCursor();
1437 return waitCursor();
1439 return helpCursor();
1440 case CURSOR_VERTICAL_TEXT:
1441 return verticalTextCursor();
1443 return cellCursor();
1444 case CURSOR_CONTEXT_MENU:
1445 return contextMenuCursor();
1446 case CURSOR_PROGRESS:
1447 return progressCursor();
1448 case CURSOR_NO_DROP:
1449 return noDropCursor();
1451 return aliasCursor();
1453 return copyCursor();
1455 return noneCursor();
1456 case CURSOR_NOT_ALLOWED:
1457 return notAllowedCursor();
1458 case CURSOR_DEFAULT:
1459 return pointerCursor();
1460 case CURSOR_WEBKIT_ZOOM_IN:
1461 return zoomInCursor();
1462 case CURSOR_WEBKIT_ZOOM_OUT:
1463 return zoomOutCursor();
1464 case CURSOR_WEBKIT_GRAB:
1465 return grabCursor();
1466 case CURSOR_WEBKIT_GRABBING:
1467 return grabbingCursor();
1469 return pointerCursor();
1471 #endif // ENABLE(CURSOR_SUPPORT)
1473 #if ENABLE(CURSOR_VISIBILITY)
1474 void EventHandler::startAutoHideCursorTimer()
1476 Page* page = m_frame.page();
1480 m_autoHideCursorTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
1482 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1483 // so cancel any pending fake mouse moves.
1484 if (m_fakeMouseMoveEventTimer.isActive())
1485 m_fakeMouseMoveEventTimer.stop();
1488 void EventHandler::cancelAutoHideCursorTimer()
1490 if (m_autoHideCursorTimer.isActive())
1491 m_autoHideCursorTimer.stop();
1494 void EventHandler::autoHideCursorTimerFired(Timer<EventHandler>& timer)
1496 ASSERT_UNUSED(timer, &timer == &m_autoHideCursorTimer);
1497 m_currentMouseCursor = noneCursor();
1498 FrameView* view = m_frame.view();
1499 if (view && view->isActive())
1500 view->setCursor(m_currentMouseCursor);
1504 static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
1506 FrameView* view = frame.view();
1507 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1508 // Historically the code would just crash; this is clearly no worse than that.
1509 return view ? view->windowToContents(windowPoint) : windowPoint;
1512 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1514 RefPtr<FrameView> protector(m_frame.view());
1516 if (InspectorInstrumentation::handleMousePress(m_frame.page())) {
1521 #if ENABLE(TOUCH_EVENTS)
1522 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1523 if (defaultPrevented)
1527 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1529 // FIXME (bug 68185): this call should be made at another abstraction layer
1530 m_frame.loader().resetMultipleFormSubmissionProtection();
1532 cancelFakeMouseMoveEvent();
1533 m_mousePressed = true;
1534 m_capturesDragging = true;
1535 setLastKnownMousePosition(mouseEvent);
1536 m_mouseDownTimestamp = mouseEvent.timestamp();
1537 #if ENABLE(DRAG_SUPPORT)
1538 m_mouseDownMayStartDrag = false;
1540 m_mouseDownMayStartSelect = false;
1541 m_mouseDownMayStartAutoscroll = false;
1542 if (FrameView* view = m_frame.view())
1543 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1548 m_mouseDownWasInSubframe = false;
1550 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1551 // Save the document point we generate in case the window coordinate is invalidated by what happens
1552 // when we dispatch the event.
1553 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1554 MouseEventWithHitTestResults mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1556 if (!mev.targetNode()) {
1561 m_mousePressNode = mev.targetNode();
1563 RefPtr<Frame> subframe = subframeForHitTestResult(mev);
1564 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1565 // Start capturing future events for this frame. We only do this if we didn't clear
1566 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1567 m_capturesDragging = subframe->eventHandler().capturesDragging();
1568 if (m_mousePressed && m_capturesDragging) {
1569 m_capturingMouseEventsElement = subframe->ownerElement();
1570 m_eventHandlerWillResetCapturingMouseEventsElement = true;
1576 #if ENABLE(PAN_SCROLLING)
1577 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1578 // because it will set m_autoscrollType to NoAutoscroll on return.
1579 bool isPanScrollInProgress = m_frame.mainFrame().eventHandler().panScrollInProgress();
1580 stopAutoscrollTimer();
1581 if (isPanScrollInProgress) {
1582 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1583 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1589 m_clickCount = mouseEvent.clickCount();
1590 m_clickNode = mev.targetNode();
1597 if (FrameView* view = m_frame.view()) {
1598 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1599 IntPoint p = view->windowToContents(mouseEvent.position());
1600 if (layer && layer->isPointInResizeControl(p)) {
1601 layer->setInResizeMode(true);
1602 m_resizeLayer = layer;
1603 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1609 m_frame.selection().setCaretBlinkingSuspended(true);
1611 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1612 m_capturesDragging = !swallowEvent || mev.scrollbar();
1614 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1615 // in case the scrollbar widget was destroyed when the mouse event was handled.
1616 if (mev.scrollbar()) {
1617 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1618 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1619 mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1620 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1621 m_lastScrollbarUnderMouse = 0;
1625 // scrollbars should get events anyway, even disabled controls might be scrollable
1626 Scrollbar* scrollbar = mev.scrollbar();
1628 updateLastScrollbarUnderMouse(scrollbar, true);
1631 passMousePressEventToScrollbar(mev, scrollbar);
1633 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1634 // If a mouse event handler changes the input element type to one that has a widget associated,
1635 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1636 // event target node can't still be the shadow node.
1637 if (mev.targetNode()->isShadowRoot() && isHTMLInputElement(toShadowRoot(mev.targetNode())->hostElement())) {
1638 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1639 mev = m_frame.document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1642 FrameView* view = m_frame.view();
1643 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1645 scrollbar = mev.scrollbar();
1647 updateLastScrollbarUnderMouse(scrollbar, true);
1649 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1650 swallowEvent = true;
1652 swallowEvent = handleMousePressEvent(mev);
1655 return swallowEvent;
1658 // This method only exists for platforms that don't know how to deliver
1659 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1661 RefPtr<FrameView> protector(m_frame.view());
1663 m_frame.selection().setCaretBlinkingSuspended(false);
1665 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1667 // We get this instead of a second mouse-up
1668 m_mousePressed = false;
1669 setLastKnownMousePosition(mouseEvent);
1671 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1672 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1673 Frame* subframe = subframeForHitTestResult(mev);
1674 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1675 m_capturingMouseEventsElement = nullptr;
1676 if (subframe && passMousePressEventToSubframe(mev, subframe))
1679 m_clickCount = mouseEvent.clickCount();
1680 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1682 bool swallowClickEvent = mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1684 if (m_lastScrollbarUnderMouse)
1685 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1687 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1691 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1694 static RenderLayer* layerForNode(Node* node)
1699 auto renderer = node->renderer();
1703 RenderLayer* layer = renderer->enclosingLayer();
1710 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1712 RefPtr<FrameView> protector(m_frame.view());
1713 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1715 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1716 bool result = handleMouseMoveEvent(event, &hoveredNode);
1718 Page* page = m_frame.page();
1722 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1723 if (FrameView* frameView = m_frame.view()) {
1724 if (frameView->containsScrollableArea(layer))
1725 layer->mouseMovedInContentArea();
1729 if (FrameView* frameView = m_frame.view())
1730 frameView->mouseMovedInContentArea();
1732 hoveredNode.setToNonShadowAncestor();
1733 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1734 page->chrome().setToolTip(hoveredNode);
1738 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1740 HitTestResult hoveredNode;
1741 return handleMouseMoveEvent(event, &hoveredNode, true);
1744 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1746 #if ENABLE(TOUCH_EVENTS)
1747 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1748 if (defaultPrevented)
1752 RefPtr<FrameView> protector(m_frame.view());
1754 setLastKnownMousePosition(mouseEvent);
1756 if (m_hoverTimer.isActive())
1757 m_hoverTimer.stop();
1759 #if ENABLE(CURSOR_SUPPORT)
1760 m_cursorUpdateTimer.stop();
1763 cancelFakeMouseMoveEvent();
1766 toSVGDocument(m_frame.document())->updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1770 if (m_frameSetBeingResized)
1771 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1773 // On iOS, our scrollbars are managed by UIKit.
1775 // Send events right to a scrollbar if the mouse is pressed.
1776 if (m_lastScrollbarUnderMouse && m_mousePressed)
1777 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1780 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars;
1782 hitType |= HitTestRequest::Active;
1783 else if (onlyUpdateScrollbars) {
1784 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1785 // means that :hover and :active freeze in the state they were in, rather than updating
1786 // for nodes the mouse moves while the window is not key (which will be the case if
1787 // onlyUpdateScrollbars is true).
1788 hitType |= HitTestRequest::ReadOnly;
1791 #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
1792 // Treat any mouse move events as readonly if the user is currently touching the screen.
1794 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1796 HitTestRequest request(hitType);
1797 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1799 *hoveredNode = mev.hitTestResult();
1801 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1802 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1804 Scrollbar* scrollbar = mev.scrollbar();
1805 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1807 // On iOS, our scrollbars are managed by UIKit.
1809 if (!m_mousePressed && scrollbar)
1810 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1812 if (onlyUpdateScrollbars)
1816 bool swallowEvent = false;
1817 RefPtr<Frame> newSubframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mev);
1819 // 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.
1820 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(&m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1821 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1824 // Update over/out state before passing the event to the subframe.
1825 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1827 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1828 // node to be detached from its FrameView, in which case the event should not be passed.
1829 if (newSubframe->view())
1830 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1831 #if ENABLE(CURSOR_SUPPORT)
1833 if (FrameView* view = m_frame.view()) {
1834 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey());
1835 if (optionalCursor.isCursorChange()) {
1836 m_currentMouseCursor = optionalCursor.cursor();
1837 view->setCursor(m_currentMouseCursor);
1843 m_lastMouseMoveEventSubframe = newSubframe;
1848 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
1849 #if ENABLE(DRAG_SUPPORT)
1851 swallowEvent = handleMouseDraggedEvent(mev);
1852 #endif // ENABLE(DRAG_SUPPORT)
1854 return swallowEvent;
1857 void EventHandler::invalidateClick()
1863 inline static bool mouseIsReleasedOnPressedElement(Node* targetNode, Node* clickNode)
1865 if (targetNode == clickNode)
1871 ShadowRoot* containingShadowRoot = targetNode->containingShadowRoot();
1872 if (!containingShadowRoot)
1875 // FIXME: When an element in UA ShadowDOM (e.g. inner element in <input>) is clicked,
1876 // we assume that the host element is clicked. This is necessary for implementing <input type="range"> etc.
1877 // However, we should not check ShadowRoot type basically.
1878 // https://bugs.webkit.org/show_bug.cgi?id=108047
1879 if (containingShadowRoot->type() != ShadowRoot::UserAgentShadowRoot)
1882 Node* adjustedTargetNode = targetNode->shadowHost();
1883 Node* adjustedClickNode = clickNode ? clickNode->shadowHost() : 0;
1884 return adjustedTargetNode == adjustedClickNode;
1887 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1889 RefPtr<FrameView> protector(m_frame.view());
1891 m_frame.selection().setCaretBlinkingSuspended(false);
1893 #if ENABLE(TOUCH_EVENTS)
1894 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1895 if (defaultPrevented)
1899 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1901 #if ENABLE(PAN_SCROLLING)
1902 m_autoscrollController->handleMouseReleaseEvent(mouseEvent);
1905 m_mousePressed = false;
1906 setLastKnownMousePosition(mouseEvent);
1910 toSVGDocument(m_frame.document())->updatePan(m_frame.view()->windowToContents(m_lastKnownMousePosition));
1914 if (m_frameSetBeingResized)
1915 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1917 if (m_lastScrollbarUnderMouse) {
1919 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1920 bool cancelable = true;
1921 bool setUnder = false;
1922 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder);
1925 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
1926 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1927 Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mev);
1928 if (m_eventHandlerWillResetCapturingMouseEventsElement)
1929 m_capturingMouseEventsElement = nullptr;
1930 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1933 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1935 bool contextMenuEvent = mouseEvent.button() == RightButton;
1937 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && mouseIsReleasedOnPressedElement(mev.targetNode(), m_clickNode.get()) && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1939 if (m_resizeLayer) {
1940 m_resizeLayer->setInResizeMode(false);
1944 bool swallowMouseReleaseEvent = false;
1945 if (!swallowMouseUpEvent)
1946 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1950 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1953 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1955 // If the event was a middle click, attempt to copy global selection in after
1956 // the newly set caret position.
1958 // This code is called from either the mouse up or mouse down handling. There
1959 // is some debate about when the global selection is pasted:
1960 // xterm: pastes on up.
1961 // GTK: pastes on down.
1962 // Qt: pastes on up.
1963 // Firefox: pastes on up.
1964 // Chromium: pastes on up.
1966 // There is something of a webcompat angle to this well, as highlighted by
1967 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1968 // down then the text is pasted just before the onclick handler runs and
1969 // clears the text box. So it's important this happens after the event
1970 // handlers have been fired.
1972 if (mouseEvent.type() != PlatformEvent::MousePressed)
1975 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1979 if (!m_frame.page())
1981 Frame& focusFrame = m_frame.page()->focusController().focusedOrMainFrame();
1982 // Do not paste here if the focus was moved somewhere else.
1983 if (&m_frame == &focusFrame && m_frame.editor().client()->supportsGlobalSelection())
1984 return m_frame.editor().command(ASCIILiteral("PasteGlobalSelection")).execute();
1989 #if ENABLE(DRAG_SUPPORT)
1991 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Element& dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1993 FrameView* view = m_frame.view();
1995 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1999 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2000 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2001 true, true, event.timestamp(), m_frame.document()->defaultView(),
2002 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2003 #if ENABLE(POINTER_LOCK)
2004 event.movementDelta().x(), event.movementDelta().y(),
2006 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2009 dragTarget.dispatchEvent(me.get(), IGNORE_EXCEPTION);
2010 return me->defaultPrevented();
2013 static bool targetIsFrame(Node* target, Frame*& frame)
2018 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
2021 frame = toHTMLFrameElementBase(target)->contentFrame();
2026 static DragOperation convertDropZoneOperationToDragOperation(const String& dragOperation)
2028 if (dragOperation == "copy")
2029 return DragOperationCopy;
2030 if (dragOperation == "move")
2031 return DragOperationMove;
2032 if (dragOperation == "link")
2033 return DragOperationLink;
2034 return DragOperationNone;
2037 static String convertDragOperationToDropZoneOperation(DragOperation operation)
2039 switch (operation) {
2040 case DragOperationCopy:
2041 return ASCIILiteral("copy");
2042 case DragOperationMove:
2043 return ASCIILiteral("move");
2044 case DragOperationLink:
2045 return ASCIILiteral("link");
2047 return ASCIILiteral("copy");
2051 static inline bool hasFileOfType(Clipboard& clipboard, const String& type)
2053 RefPtr<FileList> fileList = clipboard.files();
2054 for (unsigned i = 0; i < fileList->length(); i++) {
2055 if (equalIgnoringCase(fileList->item(i)->type(), type))
2061 static inline bool hasStringOfType(Clipboard& clipboard, const String& type)
2063 return !type.isNull() && clipboard.types().contains(type);
2066 static bool hasDropZoneType(Clipboard& clipboard, const String& keyword)
2068 if (keyword.startsWith("file:"))
2069 return hasFileOfType(clipboard, keyword.substring(5));
2071 if (keyword.startsWith("string:"))
2072 return hasStringOfType(clipboard, keyword.substring(7));
2077 static bool findDropZone(Node* target, Clipboard* clipboard)
2079 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
2080 for (; element; element = element->parentElement()) {
2081 bool matched = false;
2082 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2084 if (dropZoneStr.isEmpty())
2087 dropZoneStr = dropZoneStr.lower();
2089 SpaceSplitString keywords(dropZoneStr, false);
2090 if (keywords.isEmpty())
2093 DragOperation dragOperation = DragOperationNone;
2094 for (unsigned int i = 0; i < keywords.size(); i++) {
2095 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2096 if (op != DragOperationNone) {
2097 if (dragOperation == DragOperationNone)
2100 matched = matched || hasDropZoneType(*clipboard, keywords[i].string());
2102 if (matched && dragOperation != DragOperationNone)
2106 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2113 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2115 bool accept = false;
2117 if (!m_frame.view())
2120 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2121 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
2123 RefPtr<Element> newTarget;
2124 if (Node* targetNode = mev.targetNode()) {
2125 // Drag events should never go to non-element nodes (following IE, and proper mouseover/out dispatch)
2126 if (!targetNode->isElementNode())
2127 newTarget = targetNode->parentOrShadowHostElement();
2129 newTarget = toElement(targetNode);
2132 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2134 if (m_dragTarget != newTarget) {
2135 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2136 // it is sometimes incorrect when dragging within subframes, as seen with
2137 // LayoutTests/fast/events/drag-in-frames.html.
2139 // 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>.
2141 if (targetIsFrame(newTarget.get(), targetFrame)) {
2143 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
2144 } else if (newTarget) {
2145 // 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.
2146 if (dragState().source && dragState().shouldDispatchEvents) {
2147 // for now we don't care if event handler cancels default behavior, since there is none
2148 dispatchDragSrcEvent(eventNames().dragEvent, event);
2150 accept = dispatchDragEvent(eventNames().dragenterEvent, *newTarget, event, clipboard);
2152 accept = findDropZone(newTarget.get(), clipboard);
2155 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2157 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
2158 } else if (m_dragTarget)
2159 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, clipboard);
2162 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2163 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2164 m_shouldOnlyFireDragOverEvent = true;
2168 if (targetIsFrame(newTarget.get(), targetFrame)) {
2170 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
2171 } else if (newTarget) {
2172 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2173 if (!m_shouldOnlyFireDragOverEvent && dragState().source && dragState().shouldDispatchEvents) {
2174 // for now we don't care if event handler cancels default behavior, since there is none
2175 dispatchDragSrcEvent(eventNames().dragEvent, event);
2177 accept = dispatchDragEvent(eventNames().dragoverEvent, *newTarget, event, clipboard);
2179 accept = findDropZone(newTarget.get(), clipboard);
2180 m_shouldOnlyFireDragOverEvent = false;
2183 m_dragTarget = newTarget.release();
2187 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2190 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2192 targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
2193 } else if (m_dragTarget) {
2194 if (dragState().source && dragState().shouldDispatchEvents)
2195 dispatchDragSrcEvent(eventNames().dragEvent, event);
2196 dispatchDragEvent(eventNames().dragleaveEvent, *m_dragTarget, event, clipboard);
2201 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2204 bool preventedDefault = false;
2205 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2207 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
2208 } else if (m_dragTarget)
2209 preventedDefault = dispatchDragEvent(eventNames().dropEvent, *m_dragTarget, event, clipboard);
2211 return preventedDefault;
2214 void EventHandler::clearDragState()
2216 stopAutoscrollTimer();
2217 m_dragTarget = nullptr;
2218 m_capturingMouseEventsElement = nullptr;
2219 m_shouldOnlyFireDragOverEvent = false;
2221 m_sendingEventToSubview = false;
2224 #endif // ENABLE(DRAG_SUPPORT)
2226 void EventHandler::setCapturingMouseEventsElement(PassRefPtr<Element> element)
2228 m_capturingMouseEventsElement = element;
2229 m_eventHandlerWillResetCapturingMouseEventsElement = false;
2232 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
2234 ASSERT(m_frame.document());
2235 return m_frame.document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
2238 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
2240 if (!referenceNode || !referenceNode->isSVGElement())
2243 ShadowRoot* shadowRoot = referenceNode->containingShadowRoot();
2247 Element* shadowTreeParentElement = shadowRoot->hostElement();
2248 if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag))
2251 return toSVGUseElement(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
2254 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
2256 Element* targetElement = nullptr;
2258 // If we're capturing, we always go right to that element.
2259 if (m_capturingMouseEventsElement)
2260 targetElement = m_capturingMouseEventsElement.get();
2261 else if (targetNode) {
2262 // If the target node is a non-element, dispatch on the parent. <rdar://problem/4196646>
2263 if (!targetNode->isElementNode())
2264 targetElement = targetNode->parentOrShadowHostElement();
2266 targetElement = toElement(targetNode);
2269 m_elementUnderMouse = targetElement;
2270 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(targetElement);
2272 // <use> shadow tree elements may have been recloned, update node under mouse in any case
2273 if (m_lastInstanceUnderMouse) {
2274 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
2275 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
2277 if (lastCorrespondingElement && lastCorrespondingUseElement) {
2278 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
2280 // Locate the recloned shadow tree element for our corresponding instance
2281 HashSet<SVGElementInstance*>::iterator end = instances.end();
2282 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
2283 SVGElementInstance* instance = (*it);
2284 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
2286 if (instance == m_lastInstanceUnderMouse)
2289 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
2292 SVGElement* shadowTreeElement = instance->shadowTreeElement();
2293 if (!shadowTreeElement->inDocument() || m_lastElementUnderMouse == shadowTreeElement)
2296 m_lastElementUnderMouse = shadowTreeElement;
2297 m_lastInstanceUnderMouse = instance;
2303 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2304 if (fireMouseOverOut) {
2305 RenderLayer* layerForLastNode = layerForNode(m_lastElementUnderMouse.get());
2306 RenderLayer* layerForNodeUnderMouse = layerForNode(m_elementUnderMouse.get());
2307 Page* page = m_frame.page();
2309 if (m_lastElementUnderMouse && (!m_elementUnderMouse || &m_elementUnderMouse->document() != m_frame.document())) {
2310 // The mouse has moved between frames.
2311 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2312 if (FrameView* frameView = frame->view())
2313 frameView->mouseExitedContentArea();
2315 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2316 // The mouse has moved between layers.
2317 if (Frame* frame = m_lastElementUnderMouse->document().frame()) {
2318 if (FrameView* frameView = frame->view()) {
2319 if (frameView->containsScrollableArea(layerForLastNode))
2320 layerForLastNode->mouseExitedContentArea();
2325 if (m_elementUnderMouse && (!m_lastElementUnderMouse || &m_lastElementUnderMouse->document() != m_frame.document())) {
2326 // The mouse has moved between frames.
2327 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2328 if (FrameView* frameView = frame->view())
2329 frameView->mouseEnteredContentArea();
2331 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2332 // The mouse has moved between layers.
2333 if (Frame* frame = m_elementUnderMouse->document().frame()) {
2334 if (FrameView* frameView = frame->view()) {
2335 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2336 layerForNodeUnderMouse->mouseEnteredContentArea();
2341 if (m_lastElementUnderMouse && &m_lastElementUnderMouse->document() != m_frame.document()) {
2342 m_lastElementUnderMouse = nullptr;
2343 m_lastScrollbarUnderMouse = 0;
2344 m_lastInstanceUnderMouse = 0;
2347 if (m_lastElementUnderMouse != m_elementUnderMouse) {
2348 // send mouseout event to the old node
2349 if (m_lastElementUnderMouse)
2350 m_lastElementUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
2351 // send mouseover event to the new node
2352 if (m_elementUnderMouse)
2353 m_elementUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
2355 m_lastElementUnderMouse = m_elementUnderMouse;
2356 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_elementUnderMouse.get());
2360 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2362 if (FrameView* view = m_frame.view())
2363 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2365 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2367 bool swallowEvent = false;
2369 if (m_elementUnderMouse)
2370 swallowEvent = !(m_elementUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount));
2372 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2374 // If clicking on a frame scrollbar, do not mess up with content focus.
2375 if (FrameView* view = m_frame.view()) {
2376 if (view->scrollbarAtPoint(mouseEvent.position()))
2380 // The layout needs to be up to date to determine if an element is focusable.
2381 m_frame.document()->updateLayoutIgnorePendingStylesheets();
2383 // Blur current focus node when a link/button is clicked; this
2384 // is expected by some sites that rely on onChange handlers running
2385 // from form fields before the button click is processed.
2387 Element* element = m_elementUnderMouse.get();
2389 // Walk up the DOM tree to search for an element to focus.
2391 if (element->isMouseFocusable()) {
2392 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2393 // node on mouse down if it's selected and inside a focused node. It will be
2394 // focused if the user does a mouseup over it, however, because the mouseup
2395 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2396 if (m_frame.selection().isRange()
2397 && m_frame.selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2398 && element->isDescendantOf(m_frame.document()->focusedElement()))
2403 element = element->parentOrShadowHostElement();
2406 // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node.
2407 if ((!element || !element->isMouseFocusable()) && isInsideScrollbar(mouseEvent.position()))
2410 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2411 // if the page already set it (e.g., by canceling default behavior).
2412 if (Page* page = m_frame.page()) {
2413 if (element && element->isMouseFocusable()) {
2414 if (!page->focusController().setFocusedElement(element, &m_frame))
2415 swallowEvent = true;
2416 } else if (!element || !element->focused()) {
2417 if (!page->focusController().setFocusedElement(0, &m_frame))
2418 swallowEvent = true;
2423 return !swallowEvent;
2426 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2428 if (RenderView* renderView = m_frame.contentRenderer()) {
2429 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2430 HitTestResult result(windowPoint);
2431 renderView->hitTest(request, result);
2432 return result.scrollbar();
2439 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2445 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2447 Document* document = m_frame.document();
2449 if (!document->renderView())
2452 RefPtr<FrameView> protector(m_frame.view());
2454 FrameView* view = m_frame.view();
2458 m_isHandlingWheelEvent = true;
2459 setFrameWasScrolledByUser();
2460 LayoutPoint vPoint = view->windowToContents(e.position());
2462 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2463 HitTestResult result(vPoint);
2464 document->renderView()->hitTest(request, result);
2466 bool useLatchedWheelEventElement = e.useLatchedEventElement();
2468 Element* element = result.innerElement();
2471 if (useLatchedWheelEventElement) {
2472 if (!m_latchedWheelEventElement) {
2473 m_latchedWheelEventElement = element;
2474 m_widgetIsLatched = result.isOverWidget();
2476 element = m_latchedWheelEventElement.get();
2478 isOverWidget = m_widgetIsLatched;
2480 if (m_latchedWheelEventElement)
2481 m_latchedWheelEventElement = nullptr;
2482 if (m_previousWheelScrolledElement)
2483 m_previousWheelScrolledElement = nullptr;
2485 isOverWidget = result.isOverWidget();
2488 // FIXME: It should not be necessary to do this mutation here.
2489 // Instead, the handlers should know convert vertical scrolls
2491 PlatformWheelEvent event = e;
2492 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2493 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2496 switch (event.phase()) {
2497 case PlatformWheelEventPhaseBegan:
2498 m_recentWheelEventDeltaTracker->beginTrackingDeltas();
2500 case PlatformWheelEventPhaseEnded:
2501 m_recentWheelEventDeltaTracker->endTrackingDeltas();
2508 m_recentWheelEventDeltaTracker->recordWheelEventDelta(event);
2511 // Figure out which view to send the event to.
2512 RenderElement* target = element->renderer();
2514 if (isOverWidget && target && target->isWidget()) {
2515 Widget* widget = toRenderWidget(target)->widget();
2516 if (widget && passWheelEventToWidget(e, widget)) {
2517 m_isHandlingWheelEvent = false;
2522 if (!element->dispatchWheelEvent(event)) {
2523 m_isHandlingWheelEvent = false;
2529 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2530 view = m_frame.view();
2533 if (useLatchedWheelEventElement && m_latchedWheelEventElement == element) {
2534 bool enclosingFrameIsMainFrame = view ? view->frame().isMainFrame() : false;
2536 // If we are latched, and have nowhere to scroll, treat the scroll event as ended so that we don't
2537 // cause the scroll to break free of the current scrolling widget.
2538 if (!enclosingFrameIsMainFrame) {
2539 bool didHandleWheelEvent = view ? view->wheelEvent(event) : false;
2540 if (!didHandleWheelEvent) {
2541 // If we are just starting a scroll event, and have nowhere left to scroll, allow
2542 // the enclosing frame to handle the scroll.
2543 didHandleWheelEvent = !m_recentWheelEventDeltaTracker->isFirstWheelEvent();
2546 m_isHandlingWheelEvent = false;
2547 return didHandleWheelEvent;
2550 if (!m_recentWheelEventDeltaTracker->isFirstWheelEvent()) {
2551 // When the main frame is our parent, and we have been scrolling within this region, we do not
2552 // want to have the main frame consume any remaining scroll events. Keep them latched to this
2554 m_isHandlingWheelEvent = false;
2560 bool didHandleEvent = view ? view->wheelEvent(event) : false;
2561 m_isHandlingWheelEvent = false;
2562 return didHandleEvent;
2565 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2567 if (!startNode || !wheelEvent)
2570 Element* stopElement = m_previousWheelScrolledElement.get();
2571 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2572 DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None;
2574 // Workaround for scrolling issues <rdar://problem/14758615>.
2576 if (m_recentWheelEventDeltaTracker->isTrackingDeltas())
2577 dominantDirection = m_recentWheelEventDeltaTracker->dominantScrollGestureDirection();
2580 // Break up into two scrolls if we need to. Diagonal movement on
2581 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2582 if (dominantDirection != DominantScrollGestureDirection::Vertical && scrollNode(wheelEvent->deltaX(), granularity, ScrollRight, ScrollLeft, startNode, &stopElement, roundedIntPoint(wheelEvent->absoluteLocation())))
2583 wheelEvent->setDefaultHandled();
2585 if (dominantDirection != DominantScrollGestureDirection::Horizontal && scrollNode(wheelEvent->deltaY(), granularity, ScrollDown, ScrollUp, startNode, &stopElement, roundedIntPoint(wheelEvent->absoluteLocation())))
2586 wheelEvent->setDefaultHandled();
2588 if (!m_latchedWheelEventElement)
2589 m_previousWheelScrolledElement = stopElement;
2592 #if ENABLE(CONTEXT_MENUS)
2593 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2595 Document* doc = m_frame.document();
2596 FrameView* v = m_frame.view();
2600 // Clear mouse press state to avoid initiating a drag while context menu is up.
2601 m_mousePressed = false;
2603 LayoutPoint viewportPos = v->windowToContents(event.position());
2604 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
2605 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2607 if (m_frame.editor().behavior().shouldSelectOnContextualMenuClick()
2608 && !m_frame.selection().contains(viewportPos)
2610 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2611 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2612 // available for text selections. But only if we're above text.
2613 && (m_frame.selection().selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2614 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2615 selectClosestWordOrLinkFromMouseEvent(mev);
2618 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, false);
2620 return swallowEvent;
2623 bool EventHandler::sendContextMenuEventForKey()
2625 FrameView* view = m_frame.view();
2629 Document* doc = m_frame.document();
2633 // Clear mouse press state to avoid initiating a drag while context menu is up.
2634 m_mousePressed = false;
2636 static const int kContextMenuMargin = 1;
2638 #if OS(WINDOWS) && !OS(WINCE)
2639 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2641 int rightAligned = 0;
2645 Element* focusedElement = doc->focusedElement();
2646 const VisibleSelection& selection = m_frame.selection().selection();
2647 Position start = selection.start();
2649 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2650 RefPtr<Range> selectionRange = selection.toNormalizedRange();
2651 IntRect firstRect = m_frame.editor().firstRectForRange(selectionRange.get());
2653 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2654 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2655 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2656 location = IntPoint(x, y);
2657 } else if (focusedElement) {
2658 RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2661 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2662 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2664 location = IntPoint(
2665 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2666 kContextMenuMargin);
2669 m_frame.view()->setCursor(pointerCursor());
2671 IntPoint position = view->contentsToRootView(location);
2672 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2674 Node* targetNode = doc->focusedElement();
2678 // Use the focused node as the target for hover and active.
2679 HitTestResult result(position);
2680 result.setInnerNode(targetNode);
2681 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement());
2683 // The contextmenu event is a mouse event even when invoked using the keyboard.
2684 // This is required for web compatibility.
2687 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2689 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2692 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2694 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2696 #endif // ENABLE(CONTEXT_MENUS)
2698 void EventHandler::scheduleHoverStateUpdate()
2700 if (!m_hoverTimer.isActive())
2701 m_hoverTimer.startOneShot(0);
2704 #if ENABLE(CURSOR_SUPPORT)
2705 void EventHandler::scheduleCursorUpdate()
2707 if (!m_cursorUpdateTimer.isActive())
2708 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2712 void EventHandler::dispatchFakeMouseMoveEventSoon()
2717 if (m_mousePositionIsUnknown)
2720 if (!m_frame.settings().deviceSupportsMouse())
2723 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2724 // reschedule the timer and use a longer time. This will cause the content
2725 // to receive these moves only after the user is done scrolling, reducing
2726 // pauses during the scroll.
2727 if (m_maxMouseMovedDuration > fakeMouseMoveDurationThreshold) {
2728 if (m_fakeMouseMoveEventTimer.isActive())
2729 m_fakeMouseMoveEventTimer.stop();
2730 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2732 if (!m_fakeMouseMoveEventTimer.isActive())
2733 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2737 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2739 FrameView* view = m_frame.view();
2743 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2746 dispatchFakeMouseMoveEventSoon();
2749 void EventHandler::cancelFakeMouseMoveEvent()
2751 m_fakeMouseMoveEventTimer.stop();
2754 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>& timer)
2756 ASSERT_UNUSED(timer, &timer == &m_fakeMouseMoveEventTimer);
2757 ASSERT(!m_mousePressed);
2759 if (!m_frame.settings().deviceSupportsMouse())
2762 FrameView* view = m_frame.view();
2766 if (!m_frame.page() || !m_frame.page()->isVisible() || !m_frame.page()->focusController().isActive())
2773 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2774 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2775 mouseMoved(fakeMouseMoveEvent);
2778 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2780 m_frameSetBeingResized = frameSet;
2783 void EventHandler::resizeLayerDestroyed()
2785 ASSERT(m_resizeLayer);
2789 void EventHandler::hoverTimerFired(Timer<EventHandler>&)
2791 m_hoverTimer.stop();
2793 ASSERT(m_frame.document());
2795 if (RenderView* renderer = m_frame.contentRenderer()) {
2796 if (FrameView* view = m_frame.view()) {
2797 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
2798 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2799 renderer->hitTest(request, result);
2800 m_frame.document()->updateHoverActiveState(request, result.innerElement());
2805 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2807 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2808 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2809 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2810 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2811 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2812 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2814 String key = evt.unmodifiedText();
2815 Element* elem = m_frame.document()->getElementByAccessKey(key.lower());
2818 elem->accessKeyAction(false);
2822 #if !PLATFORM(MAC) || PLATFORM(IOS)
2823 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2829 #if ENABLE(FULLSCREEN_API)
2830 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2832 Document* document = m_frame.document();
2833 if (document->webkitFullScreenKeyboardInputAllowed())
2836 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2837 if (keyEvent.text().length() != 1)
2839 UChar character = keyEvent.text()[0];
2840 return character == ' ';
2843 int keyCode = keyEvent.windowsVirtualKeyCode();
2844 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2845 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2846 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2847 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2851 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2853 RefPtr<FrameView> protector(m_frame.view());
2855 #if ENABLE(FULLSCREEN_API)
2856 if (m_frame.document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
2860 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2861 capsLockStateMayHaveChanged();
2863 #if ENABLE(PAN_SCROLLING)
2864 if (m_frame.mainFrame().eventHandler().panScrollInProgress()) {
2865 // If a key is pressed while the panScroll is in progress then we want to stop
2866 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2867 stopAutoscrollTimer();
2869 // If we were in panscroll mode, we swallow the key event
2874 // Check for cases where we are too early for events -- possible unmatched key up
2875 // from pressing return in the location bar.
2876 RefPtr<Element> element = eventTargetElementForDocument(m_frame.document());
2880 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2881 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2883 if (FrameView* view = m_frame.view())
2884 view->disableLayerFlushThrottlingTemporarilyForInteraction();
2886 // FIXME (bug 68185): this call should be made at another abstraction layer
2887 m_frame.loader().resetMultipleFormSubmissionProtection();
2889 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2890 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2891 // with access keys. Then we dispatch keydown, but suppress its default handling.
2892 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2893 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2894 bool matchedAnAccessKey = false;
2895 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2896 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2898 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2899 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2900 return !element->dispatchKeyEvent(initialKeyEvent);
2902 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2904 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2905 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2906 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
2907 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
2908 if (matchedAnAccessKey)
2909 keydown->setDefaultPrevented(true);
2910 keydown->setTarget(element);
2912 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2913 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
2914 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2915 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
2916 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2919 // Run input method in advance of DOM event handling. This may result in the IM
2920 // modifying the page prior the keydown event, but this behaviour is necessary
2921 // in order to match IE:
2922 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2923 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2924 m_frame.editor().handleInputMethodKeydown(keydown.get());
2926 bool handledByInputMethod = keydown->defaultHandled();
2928 if (handledByInputMethod) {
2929 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2930 keydown = KeyboardEvent::create(keyDownEvent, m_frame.document()->defaultView());
2931 keydown->setTarget(element);
2932 keydown->setDefaultHandled();
2935 element->dispatchEvent(keydown, IGNORE_EXCEPTION);
2936 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2937 bool changedFocusedFrame = m_frame.page() && &m_frame != &m_frame.page()->focusController().focusedOrMainFrame();
2938 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2939 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2940 return keydownResult;
2942 // Focus may have changed during keydown handling, so refetch element.
2943 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original element.
2944 if (!keydownResult) {
2945 element = eventTargetElementForDocument(m_frame.document());
2950 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2951 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
2952 if (keyPressEvent.text().isEmpty())
2953 return keydownResult;
2954 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame.document()->defaultView());
2955 keypress->setTarget(element);
2957 keypress->setDefaultPrevented(true);
2959 keypress->keypressCommands() = keydown->keypressCommands();
2961 element->dispatchEvent(keypress, IGNORE_EXCEPTION);
2963 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2966 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
2968 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
2969 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
2970 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
2971 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
2973 FocusDirection retVal = FocusDirectionNone;
2975 if (keyIdentifier == Down)
2976 retVal = FocusDirectionDown;
2977 else if (keyIdentifier == Up)
2978 retVal = FocusDirectionUp;
2979 else if (keyIdentifier == Left)
2980 retVal = FocusDirectionLeft;
2981 else if (keyIdentifier == Right)
2982 retVal = FocusDirectionRight;
2987 static void handleKeyboardSelectionMovement(FrameSelection& selection, KeyboardEvent* event)
2992 bool isOptioned = event->getModifierState("Alt");
2993 bool isCommanded = event->getModifierState("Meta");
2995 SelectionDirection direction = DirectionForward;
2996 TextGranularity granularity = CharacterGranularity;
2998 switch (focusDirectionForKey(event->keyIdentifier())) {
2999 case FocusDirectionNone:
3001 case FocusDirectionForward:
3002 case FocusDirectionBackward:
3003 ASSERT_NOT_REACHED();
3005 case FocusDirectionUp:
3006 direction = DirectionBackward;
3007 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3009 case FocusDirectionDown:
3010 direction = DirectionForward;
3011 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3013 case FocusDirectionLeft:
3014 direction = DirectionLeft;
3015 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3017 case FocusDirectionRight:
3018 direction = DirectionRight;
3019 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3023 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3024 selection.modify(alternation, direction, granularity, UserTriggered);
3025 event->setDefaultHandled();
3028 void EventHandler::handleKeyboardSelectionMovementForAccessibility(KeyboardEvent* event)
3030 if (event->type() == eventNames().keydownEvent) {
3031 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3032 handleKeyboardSelectionMovement(m_frame.selection(), event);
3036 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3038 if (event->type() == eventNames().keydownEvent) {
3039 m_frame.editor().handleKeyboardEvent(event);
3040 if (event->defaultHandled())
3042 if (event->keyIdentifier() == "U+0009")
3043 defaultTabEventHandler(event);
3044 else if (event->keyIdentifier() == "U+0008")
3045 defaultBackspaceEventHandler(event);
3047 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3048 if (direction != FocusDirectionNone)
3049 defaultArrowEventHandler(direction, event);
3052 handleKeyboardSelectionMovementForAccessibility(event);
3054 if (event->type() == eventNames().keypressEvent) {
3055 m_frame.editor().handleKeyboardEvent(event);
3056 if (event->defaultHandled())
3058 if (event->charCode() == ' ')
3059 defaultSpaceEventHandler(event);
3063 #if ENABLE(DRAG_SUPPORT)
3064 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3066 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3067 return dragHysteresisExceeded(dragViewportLocation);
3070 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3072 FrameView* view = m_frame.view();
3075 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3076 IntSize delta = dragLocation - m_mouseDownPos;
3078 int threshold = GeneralDragHysteresis;
3079 switch (dragState().type) {
3080 case DragSourceActionSelection:
3081 threshold = TextDragHysteresis;
3083 case DragSourceActionImage:
3084 threshold = ImageDragHysteresis;
3086 case DragSourceActionLink:
3087 threshold = LinkDragHysteresis;
3089 case DragSourceActionDHTML:
3091 case DragSourceActionNone:
3092 case DragSourceActionAny:
3093 ASSERT_NOT_REACHED();
3096 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3099 void EventHandler::freeClipboard()
3101 if (!dragState().clipboard)
3103 dragState().clipboard->setAccessPolicy(ClipboardNumb);
3104 dragState().clipboard = 0;
3107 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3109 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3110 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
3111 prepareMouseEvent(request, event);
3113 if (dragState().source && dragState().shouldDispatchEvents) {
3114 dragState().clipboard->setDestinationOperation(operation);
3115 // For now we don't care if event handler cancels default behavior, since there is no default behavior.
3116 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3119 dragState().source = 0;
3120 // In case the drag was ended due to an escape key press we need to ensure
3121 // that consecutive mousemove events don't reinitiate the drag and drop.
3122 m_mouseDownMayStartDrag = false;
3125 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3127 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editable element.
3128 if (dragState().source && !dragState().source->inDocument())
3129 dragState().source = rootEditableElement;
3132 // Return value indicates if we should continue "default processing", i.e., whether event handler canceled.
3133 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3135 return !dispatchDragEvent(eventType, *dragState().source, event, dragState().clipboard.get());
3138 static bool ExactlyOneBitSet(DragSourceAction n)
3140 return n && !(n & (n - 1));
3143 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3145 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3146 // If we allowed the other side of the bridge to handle a drag
3147 // last time, then m_mousePressed might still be set. So we
3148 // clear it now to make sure the next move after a drag
3149 // doesn't look like a drag.
3150 m_mousePressed = false;
3154 if (eventLoopHandleMouseDragged(event))
3157 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3159 if (m_mouseDownMayStartDrag && !dragState().source) {
3160 dragState().shouldDispatchEvents = (updateDragSourceActionsAllowed() & DragSourceActionDHTML);
3162 // try to find an element that wants to be dragged
3163 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
3164 HitTestResult result(m_mouseDownPos);
3165 m_frame.contentRenderer()->hitTest(request, result);
3167 dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
3169 if (!dragState().source)
3170 m_mouseDownMayStartDrag = false; // no element is draggable
3172 m_dragMayStartSelectionInstead = (dragState().type & DragSourceActionSelection);
3175 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3176 // or else we bail on the dragging stuff and allow selection to occur
3177 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().type & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3178 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3179 if ((dragState().type & DragSourceActionImage)) {
3180 // ... unless the mouse is over an image, then we start dragging just the image
3181 dragState().type = DragSourceActionImage;
3182 } else if (!(dragState().type & (DragSourceActionDHTML | DragSourceActionLink))) {
3183 // ... but only bail if we're not over an unselectable element.
3184 m_mouseDownMayStartDrag = false;
3185 dragState().source = 0;
3186 // ... but if this was the first click in the window, we don't even want to start selection
3187 if (eventActivatedView(event.event()))
3188 m_mouseDownMayStartSelect = false;
3190 // Prevent the following case from occuring:
3191 // 1. User starts a drag immediately after mouse down over an unselectable element.
3192 // 2. We enter this block and decided that since we're over an unselectable element, don't cancel the drag.
3193 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't exceeded the drag hysteresis yet.
3194 // 4. We enter this block again, and since it's now marked as a selection drag, we cancel the drag.
3195 m_dragMayStartSelectionInstead = false;
3199 if (!m_mouseDownMayStartDrag)
3200 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3202 if (!ExactlyOneBitSet(dragState().type)) {
3203 ASSERT((dragState().type & DragSourceActionSelection));
3204 ASSERT((dragState().type & ~DragSourceActionSelection) == DragSourceActionDHTML
3205 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionImage
3206 || (dragState().type & ~DragSourceActionSelection) == DragSourceActionLink);
3207 dragState().type = DragSourceActionSelection;
3210 // We are starting a text/image/url drag, so the cursor should be an arrow
3211 if (FrameView* view = m_frame.view()) {
3212 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3213 view->setCursor(pointerCursor());
3216 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3219 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3222 DragOperation srcOp = DragOperationNone;
3224 // This does work only if we missed a dragEnd. Do it anyway, just to make sure the old clipboard gets numbed.
3227 dragState().clipboard = createDraggingClipboard();
3229 if (dragState().shouldDispatchEvents) {
3230 // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset.
3231 if (dragState().type == DragSourceActionDHTML) {
3232 if (RenderObject* renderer = dragState().source->renderer()) {
3233 // FIXME: This doesn't work correctly with transforms.
3234 FloatPoint absPos = renderer->localToAbsolute();
3235 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3236 dragState().clipboard->setDragImage(dragState().source.get(), delta.width(), delta.height());
3238 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3239 // the element in some way. In this case we just kill the drag.
3240 m_mouseDownMayStartDrag = false;
3245 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3246 && !m_frame.selection().selection().isInPasswordField();
3248 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3249 // image can still be changed as we drag, but not the pasteboard data.
3250 dragState().clipboard->setAccessPolicy(ClipboardImageWritable);
3252 if (m_mouseDownMayStartDrag) {
3253 // Gather values from DHTML element, if it set any.
3254 srcOp = dragState().clipboard->sourceOperation();
3256 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3257 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3258 // started the drag when that happens. So we have to assume it's started before we kick it off.
3259 dragState().clipboard->setDragHasStarted();
3263 if (m_mouseDownMayStartDrag) {
3264 Page* page = m_frame.page();
3265 m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3266 // In WebKit2 we could re-enter this code and start another drag.
3267 // On OS X this causes problems with the ownership of the pasteboard and the promised types.
3268 if (m_didStartDrag) {
3269 m_mouseDownMayStartDrag = false;
3272 if (dragState().source && dragState().shouldDispatchEvents) {
3273 // Drag was canned at the last minute. We owe dragSource a dragend event.
3274 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3275 m_mouseDownMayStartDrag = false;
3280 if (!m_mouseDownMayStartDrag) {
3281 // Something failed to start the drag, clean up.
3283 dragState().source = 0;
3286 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3289 #endif // ENABLE(DRAG_SUPPORT)
3291 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3293 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3294 // and avoid dispatching text input events from keydown default handlers.
3295 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
3297 EventTarget* target;
3298 if (underlyingEvent)
3299 target = underlyingEvent->target();
3301 target = eventTargetElementForDocument(m_frame.document());
3305 if (FrameView* view = m_frame.view())
3306 view->disableLayerFlushThrottlingTemporarilyForInteraction();
3308 RefPtr<TextEvent> event = TextEvent::create(m_frame.document()->domWindow(), text, inputType);
3309 event->setUnderlyingEvent(underlyingEvent);
3311 target->dispatchEvent(event, IGNORE_EXCEPTION);
3312 return event->defaultHandled();
3315 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3318 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3320 && event->keyIdentifier() == "U+0009";
3323 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3325 #if PLATFORM(MAC) || PLATFORM(EFL)
3326 return EventHandler::isKeyboardOptionTab(event);
3328 UNUSED_PARAM(event);
3333 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3335 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3337 Page* page = m_frame.page();
3341 bool tabsToLinksClientCallResult = page->chrome().client().keyboardUIMode() & KeyboardAccessTabsToLinks;
3342 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3345 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3347 if (m_frame.editor().handleTextEvent(event))
3348 event->setDefaultHandled();
3352 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3354 ASSERT(event->type() == eventNames().keypressEvent);
3356 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3359 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3360 if (logicalScrollOverflow(direction, ScrollByPage)) {
3361 event->setDefaultHandled();
3365 FrameView* view = m_frame.view();
3369 if (view->logicalScroll(direction, ScrollByPage))
3370 event->setDefaultHandled();
3373 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3375 ASSERT(event->type() == eventNames().keydownEvent);
3377 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3380 if (!m_frame.editor().behavior().shouldNavigateBackOnBackspace())
3383 Page* page = m_frame.page();
3387 if (!m_frame.settings().backspaceKeyNavigationEnabled())
3390 bool handledEvent = false;
3392 if (event->shiftKey())
3393 handledEvent = page->backForward().goForward();
3395 handledEvent = page->backForward().goBack();
3398 event->setDefaultHandled();
3402 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3404 ASSERT(event->type() == eventNames().keydownEvent);
3406 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3409 Page* page = m_frame.page();
3413 if (!isSpatialNavigationEnabled(&m_frame))
3416 // Arrows and other possible directional navigation keys can be used in design
3418 if (m_frame.document()->inDesignMode())
3421 if (page->focusController().advanceFocus(focusDirection, event))
3422 event->setDefaultHandled();
3425 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3427 ASSERT(event->type() == eventNames().keydownEvent);
3429 // We should only advance focus on tabs if no special modifier keys are held down.
3430 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3433 Page* page = m_frame.page();
3436 if (!page->tabKeyCyclesThroughElements())
3439 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3441 // Tabs can be used in design mode editing.
3442 if (m_frame.document()->inDesignMode())
3445 if (page->focusController().advanceFocus(focusDirection, event))
3446 event->setDefaultHandled();
3449 void EventHandler::capsLockStateMayHaveChanged()
3451 Document* d = m_frame.document();
3452 if (Element* element = d->focusedElement()) {
3453 if (RenderObject* r = element->renderer()) {
3454 if (r->isTextField())
3455 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3460 void EventHandler::sendScrollEvent()
3462 setFrameWasScrolledByUser();
3463 if (m_frame.view() && m_frame.document())
3464 m_frame.document()->eventQueue().enqueueOrDispatchScrollEvent(*m_frame.document());
3467 void EventHandler::setFrameWasScrolledByUser()
3469 FrameView* v = m_frame.view();
3471 v->setWasScrolledByUser(true);
3474 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3476 if (!scrollbar || !scrollbar->enabled())
3478 setFrameWasScrolledByUser();
3479 return scrollbar->mouseDown(mev.event());
3482 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3483 // last to scrollbar if setLast is true; else set last to 0.
3484 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3486 if (m_lastScrollbarUnderMouse != scrollbar) {
3487 // Send mouse exited to the old scrollbar.
3488 if (m_lastScrollbarUnderMouse)
3489 m_lastScrollbarUnderMouse->mouseExited();