2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "EventHandler.h"
31 #include "AXObjectCache.h"
32 #include "AutoscrollController.h"
33 #include "CachedImage.h"
35 #include "ChromeClient.h"
37 #include "CursorList.h"
39 #include "DocumentEventQueue.h"
40 #include "DragController.h"
41 #include "DragState.h"
43 #include "EditorClient.h"
44 #include "EventNames.h"
45 #include "EventPathWalker.h"
46 #include "ExceptionCodePlaceholder.h"
47 #include "FloatPoint.h"
48 #include "FloatRect.h"
49 #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 "MouseEvent.h"
66 #include "MouseEventWithHitTestResults.h"
68 #include "PlatformEvent.h"
69 #include "PlatformKeyboardEvent.h"
70 #include "PlatformWheelEvent.h"
71 #include "PluginDocument.h"
72 #include "RenderFrameSet.h"
73 #include "RenderLayer.h"
74 #include "RenderTextControlSingleLine.h"
75 #include "RenderView.h"
76 #include "RenderWidget.h"
77 #include "ScrollAnimator.h"
78 #include "Scrollbar.h"
80 #include "ShadowRoot.h"
81 #include "SpatialNavigation.h"
82 #include "StaticHashSetNodeList.h"
83 #include "StyleCachedImage.h"
84 #include "TextEvent.h"
85 #include "TextIterator.h"
86 #include "UserTypingGestureIndicator.h"
87 #include "WheelEvent.h"
88 #include "WindowsKeyboardCodes.h"
89 #include <wtf/Assertions.h>
90 #include <wtf/CurrentTime.h>
91 #include <wtf/StdLibExtras.h>
92 #include <wtf/TemporaryChange.h>
94 #if ENABLE(GESTURE_EVENTS)
95 #include "PlatformGestureEvent.h"
98 #if ENABLE(TOUCH_ADJUSTMENT)
99 #include "TouchAdjustment.h"
103 #include "SVGDocument.h"
104 #include "SVGElementInstance.h"
105 #include "SVGNames.h"
106 #include "SVGUseElement.h"
109 #if ENABLE(TOUCH_EVENTS)
110 #include "PlatformTouchEvent.h"
111 #include "TouchEvent.h"
112 #include "TouchList.h"
115 #if ENABLE(CSS_IMAGE_SET)
116 #include "StyleCachedImageSet.h"
121 using namespace HTMLNames;
123 #if ENABLE(DRAG_SUPPORT)
124 // The link drag hysteresis is much larger than the others because there
125 // needs to be enough space to cancel the link press without starting a link drag,
126 // and because dragging links is rare.
127 const int LinkDragHysteresis = 40;
128 const int ImageDragHysteresis = 5;
129 const int TextDragHysteresis = 3;
130 const int GeneralDragHysteresis = 3;
131 #endif // ENABLE(DRAG_SUPPORT)
133 // Match key code of composition keydown event on windows.
134 // IE sends VK_PROCESSKEY which has value 229;
135 const int CompositionEventKeyCode = 229;
138 using namespace SVGNames;
141 // The amount of time to wait before sending a fake mouse event, triggered
142 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
143 // otherwise the long interval is used.
144 const double fakeMouseMoveShortInterval = 0.1;
145 const double fakeMouseMoveLongInterval = 0.250;
147 // The amount of time to wait for a cursor update on style and layout changes
148 // Set to 50Hz, no need to be faster than common screen refresh rate
149 const double cursorUpdateInterval = 0.02;
151 const int maximumCursorSize = 128;
152 #if ENABLE(MOUSE_CURSOR_SCALE)
153 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
154 // need to ensure here is that the scale isn't so small that integer overflow can occur when
155 // dividing cursor sizes (limited above) by the scale.
156 const double minimumCursorScale = 0.001;
159 enum NoCursorChangeType { NoCursorChange };
161 class OptionalCursor {
163 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
164 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
166 bool isCursorChange() const { return m_isCursorChange; }
167 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
170 bool m_isCursorChange;
174 class MaximumDurationTracker {
176 explicit MaximumDurationTracker(double *maxDuration)
177 : m_maxDuration(maxDuration)
178 , m_start(monotonicallyIncreasingTime())
182 ~MaximumDurationTracker()
184 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
188 double* m_maxDuration;
192 #if ENABLE(TOUCH_EVENTS)
193 class SyntheticTouchPoint : public PlatformTouchPoint {
196 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
197 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
199 const static int idDefaultValue = 0;
200 const static int radiusYDefaultValue = 1;
201 const static int radiusXDefaultValue = 1;
202 const static float rotationAngleDefaultValue = 0.0f;
203 const static float forceDefaultValue = 1.0f;
205 m_id = idDefaultValue; // There is only one active TouchPoint.
206 m_screenPos = event.globalPosition();
207 m_pos = event.position();
208 m_radiusY = radiusYDefaultValue;
209 m_radiusX = radiusXDefaultValue;
210 m_rotationAngle = rotationAngleDefaultValue;
211 m_force = forceDefaultValue;
213 PlatformEvent::Type type = event.type();
214 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
217 case PlatformEvent::MouseMoved:
218 m_state = TouchMoved;
220 case PlatformEvent::MousePressed:
221 m_state = TouchPressed;
223 case PlatformEvent::MouseReleased:
224 m_state = TouchReleased;
227 ASSERT_NOT_REACHED();
233 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
235 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
237 switch (event.type()) {
238 case PlatformEvent::MouseMoved:
241 case PlatformEvent::MousePressed:
244 case PlatformEvent::MouseReleased:
248 ASSERT_NOT_REACHED();
252 m_timestamp = event.timestamp();
253 m_modifiers = event.modifiers();
254 m_touchPoints.append(SyntheticTouchPoint(event));
259 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
262 case WheelEvent::DOM_DELTA_PAGE:
264 case WheelEvent::DOM_DELTA_LINE:
266 case WheelEvent::DOM_DELTA_PIXEL:
267 return ScrollByPixel;
269 return ScrollByPixel;
273 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
277 if (!node->renderer())
279 RenderBox* enclosingBox = node->renderer()->enclosingBox();
280 float absDelta = delta > 0 ? delta : -delta;
281 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode);
284 #if ENABLE(GESTURE_EVENTS)
285 static inline bool shouldGesturesTriggerActive()
287 // If the platform we're on supports GestureTapDown and GestureTapCancel then we'll
288 // rely on them to set the active state. Unfortunately there's no generic way to
289 // know in advance what event types are supported.
290 #if PLATFORM(CHROMIUM)
300 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
305 #if ENABLE(DRAG_SUPPORT)
306 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
314 EventHandler::EventHandler(Frame* frame)
316 , m_mousePressed(false)
317 , m_capturesDragging(false)
318 , m_mouseDownMayStartSelect(false)
319 #if ENABLE(DRAG_SUPPORT)
320 , m_mouseDownMayStartDrag(false)
321 , m_dragMayStartSelectionInstead(false)
323 , m_mouseDownWasSingleClickInSelection(false)
324 , m_selectionInitiationState(HaveNotStartedSelection)
325 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
326 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
327 , m_autoscrollController(adoptPtr(new AutoscrollController))
328 , m_mouseDownMayStartAutoscroll(false)
329 , m_mouseDownWasInSubframe(false)
330 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
335 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
337 , m_mousePositionIsUnknown(true)
338 , m_mouseDownTimestamp(0)
339 , m_widgetIsLatched(false)
341 , m_mouseDownView(nil)
342 , m_sendingEventToSubview(false)
343 , m_activationEventNumber(-1)
345 #if ENABLE(TOUCH_EVENTS)
346 , m_originatingTouchPointTargetKey(0)
347 , m_touchPressed(false)
349 #if ENABLE(GESTURE_EVENTS)
350 , m_scrollGestureHandlingNode(0)
351 , m_lastHitTestResultOverWidget(false)
353 , m_maxMouseMovedDuration(0)
354 , m_baseEventType(PlatformEvent::NoType)
355 , m_didStartDrag(false)
356 , m_didLongPressInvokeContextMenu(false)
357 #if ENABLE(CURSOR_VISIBILITY)
358 , m_autoHideCursorTimer(this, &EventHandler::autoHideCursorTimerFired)
363 EventHandler::~EventHandler()
365 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
366 #if ENABLE(CURSOR_VISIBILITY)
367 ASSERT(!m_autoHideCursorTimer.isActive());
371 #if ENABLE(DRAG_SUPPORT)
372 DragState& EventHandler::dragState()
374 DEFINE_STATIC_LOCAL(DragState, state, ());
377 #endif // ENABLE(DRAG_SUPPORT)
379 void EventHandler::clear()
382 m_cursorUpdateTimer.stop();
383 m_fakeMouseMoveEventTimer.stop();
384 #if ENABLE(CURSOR_VISIBILITY)
385 cancelAutoHideCursorTimer();
388 m_nodeUnderMouse = 0;
389 m_lastNodeUnderMouse = 0;
391 m_instanceUnderMouse = 0;
392 m_lastInstanceUnderMouse = 0;
394 m_lastMouseMoveEventSubframe = 0;
395 m_lastScrollbarUnderMouse = 0;
398 m_frameSetBeingResized = 0;
399 #if ENABLE(DRAG_SUPPORT)
401 m_shouldOnlyFireDragOverEvent = false;
403 m_mousePositionIsUnknown = true;
404 m_lastKnownMousePosition = IntPoint();
405 m_lastKnownMouseGlobalPosition = IntPoint();
406 m_lastMouseDownUserGestureToken.clear();
407 m_mousePressNode = 0;
408 m_mousePressed = false;
409 m_capturesDragging = false;
410 m_capturingMouseEventsNode = 0;
411 m_latchedWheelEventNode = 0;
412 m_previousWheelScrolledNode = 0;
413 #if ENABLE(TOUCH_EVENTS)
414 m_originatingTouchPointTargets.clear();
415 m_originatingTouchPointDocument.clear();
416 m_originatingTouchPointTargetKey = 0;
418 #if ENABLE(GESTURE_EVENTS)
419 m_scrollGestureHandlingNode = 0;
420 m_lastHitTestResultOverWidget = false;
421 m_previousGestureScrolledNode = 0;
422 m_scrollbarHandlingScrollGesture = 0;
424 m_maxMouseMovedDuration = 0;
425 m_baseEventType = PlatformEvent::NoType;
426 m_didStartDrag = false;
427 m_didLongPressInvokeContextMenu = false;
430 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
432 if (nodeToBeRemoved->contains(m_clickNode.get()))
436 static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
439 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
440 selection->setSelection(newSelection);
443 static inline bool dispatchSelectStart(Node* node)
445 if (!node || !node->renderer())
448 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
451 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
453 #if ENABLE(USERSELECT_ALL)
454 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
455 if (!rootUserSelectAll)
458 VisibleSelection newSelection(selection);
459 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
460 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
464 UNUSED_PARAM(targetNode);
469 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
471 if (Position::nodeIsUserSelectNone(targetNode))
474 if (!dispatchSelectStart(targetNode))
477 if (selection.isRange())
478 m_selectionInitiationState = ExtendedSelection;
480 granularity = CharacterGranularity;
481 m_selectionInitiationState = PlacedCaret;
484 m_frame->selection()->setNonDirectionalSelectionIfNeeded(selection, granularity);
489 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
491 Node* innerNode = result.targetNode();
492 VisibleSelection newSelection;
494 if (innerNode && innerNode->renderer()) {
495 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
496 if (pos.isNotNull()) {
497 newSelection = VisibleSelection(pos);
498 newSelection.expandUsingGranularity(WordGranularity);
501 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
502 newSelection.appendTrailingWhitespace();
504 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
508 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
510 if (m_mouseDownMayStartSelect) {
511 selectClosestWordFromHitTestResult(result.hitTestResult(),
512 (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
516 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
518 if (!result.hitTestResult().isLiveLink())
519 return selectClosestWordFromMouseEvent(result);
521 Node* innerNode = result.targetNode();
523 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
524 VisibleSelection newSelection;
525 Element* URLElement = result.hitTestResult().URLElement();
526 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
527 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
528 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
530 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
534 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
536 if (event.event().button() != LeftButton)
539 if (m_frame->selection()->isRange())
540 // A double-click when range is already selected
541 // should not change the selection. So, do not call
542 // selectClosestWordFromMouseEvent, but do set
543 // m_beganSelectingText to prevent handleMouseReleaseEvent
544 // from setting caret selection.
545 m_selectionInitiationState = ExtendedSelection;
547 selectClosestWordFromMouseEvent(event);
552 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
554 if (event.event().button() != LeftButton)
557 Node* innerNode = event.targetNode();
558 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
561 VisibleSelection newSelection;
562 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
563 if (pos.isNotNull()) {
564 newSelection = VisibleSelection(pos);
565 newSelection.expandUsingGranularity(ParagraphGranularity);
568 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
571 static int textDistance(const Position& start, const Position& end)
573 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
574 return TextIterator::rangeLength(range.get(), true);
577 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
579 m_frame->document()->updateLayoutIgnorePendingStylesheets();
580 Node* innerNode = event.targetNode();
581 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
584 // Extend the selection if the Shift key is down, unless the click is in a link.
585 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
587 // Don't restart the selection when the mouse is pressed on an
588 // existing selection so we can allow for text dragging.
589 if (FrameView* view = m_frame->view()) {
590 LayoutPoint vPoint = view->windowToContents(event.event().position());
591 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
592 m_mouseDownWasSingleClickInSelection = true;
597 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
598 if (visiblePos.isNull())
599 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
600 Position pos = visiblePos.deepEquivalent();
602 VisibleSelection newSelection = m_frame->selection()->selection();
603 TextGranularity granularity = CharacterGranularity;
605 if (extendSelection && newSelection.isCaretOrRange()) {
606 VisibleSelection selectionInUserSelectAll = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(pos));
607 if (selectionInUserSelectAll.isRange()) {
608 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
609 pos = selectionInUserSelectAll.start();
610 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
611 pos = selectionInUserSelectAll.end();
614 if (!m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional()) {
615 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
616 // was created right-to-left
617 Position start = newSelection.start();
618 Position end = newSelection.end();
619 int distanceToStart = textDistance(start, pos);
620 int distanceToEnd = textDistance(pos, end);
621 if (distanceToStart <= distanceToEnd)
622 newSelection = VisibleSelection(end, pos);
624 newSelection = VisibleSelection(start, pos);
626 newSelection.setExtent(pos);
628 if (m_frame->selection()->granularity() != CharacterGranularity) {
629 granularity = m_frame->selection()->granularity();
630 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
633 newSelection = expandSelectionToRespectUserSelectAll(innerNode, visiblePos);
635 bool handled = updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
637 if (event.event().button() == MiddleButton) {
638 // Ignore handled, since we want to paste to where the caret was placed anyway.
639 handled = handlePasteGlobalSelection(event.event()) || handled;
644 static inline bool canMouseDownStartSelect(Node* node)
646 if (!node || !node->renderer())
649 if (!node->canStartSelection())
655 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
657 #if ENABLE(DRAG_SUPPORT)
659 dragState().m_dragSrc = 0;
662 cancelFakeMouseMoveEvent();
664 m_frame->document()->updateLayoutIgnorePendingStylesheets();
666 if (ScrollView* scrollView = m_frame->view()) {
667 if (scrollView->isPointInScrollbarCorner(event.event().position()))
671 bool singleClick = event.event().clickCount() <= 1;
673 // If we got the event back, that must mean it wasn't prevented,
674 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
675 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
677 #if ENABLE(DRAG_SUPPORT)
678 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
679 m_mouseDownMayStartDrag = singleClick;
682 m_mouseDownWasSingleClickInSelection = false;
684 m_mouseDown = event.event();
686 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
690 if (m_frame->document()->isSVGDocument()
691 && toSVGDocument(m_frame->document())->zoomAndPanEnabled()) {
692 if (event.event().shiftKey() && singleClick) {
694 toSVGDocument(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
700 // We don't do this at the start of mouse down handling,
701 // because we don't want to do it until we know we didn't hit a widget.
705 Node* innerNode = event.targetNode();
707 m_mousePressNode = innerNode;
708 #if ENABLE(DRAG_SUPPORT)
709 m_dragStartPos = event.event().position();
712 bool swallowEvent = false;
713 m_mousePressed = true;
714 m_selectionInitiationState = HaveNotStartedSelection;
716 if (event.event().clickCount() == 2)
717 swallowEvent = handleMousePressEventDoubleClick(event);
718 else if (event.event().clickCount() >= 3)
719 swallowEvent = handleMousePressEventTripleClick(event);
721 swallowEvent = handleMousePressEventSingleClick(event);
723 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
724 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
729 #if ENABLE(DRAG_SUPPORT)
730 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
735 if (handleDrag(event, ShouldCheckDragHysteresis))
738 Node* targetNode = event.targetNode();
739 if (event.event().button() != LeftButton || !targetNode)
742 RenderObject* renderer = targetNode->renderer();
744 Node* parent = EventPathWalker::parent(targetNode);
748 renderer = parent->renderer();
749 if (!renderer || !renderer->isListBox())
753 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
754 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
757 m_mouseDownMayStartDrag = false;
759 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
760 m_autoscrollController->startAutoscrollForSelection(renderer);
761 m_mouseDownMayStartAutoscroll = false;
764 if (m_selectionInitiationState != ExtendedSelection) {
765 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
766 HitTestResult result(m_mouseDownPos);
767 m_frame->document()->renderView()->hitTest(request, result);
769 updateSelectionForMouseDrag(result);
771 updateSelectionForMouseDrag(event.hitTestResult());
775 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
777 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
778 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
779 // in handleMousePressEvent
781 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
784 if (event.button() != LeftButton || event.clickCount() != 1)
787 FrameView* view = m_frame->view();
791 Page* page = m_frame->page();
795 updateDragSourceActionsAllowed();
796 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
797 HitTestResult result(view->windowToContents(event.position()));
798 m_frame->contentRenderer()->hitTest(request, result);
800 return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.roundedPointInInnerNodeFrame(), state);
803 void EventHandler::updateSelectionForMouseDrag()
805 FrameView* view = m_frame->view();
808 RenderView* renderer = m_frame->contentRenderer();
812 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
813 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
814 renderer->hitTest(request, result);
815 updateSelectionForMouseDrag(result);
818 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
820 LayoutPoint selectionEndPoint = localPoint;
821 Element* editableElement = selection.rootEditableElement();
823 if (!targetNode->renderer())
824 return VisiblePosition();
826 if (editableElement && !editableElement->contains(targetNode)) {
827 if (!editableElement->renderer())
828 return VisiblePosition();
830 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
831 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
832 targetNode = editableElement;
835 return targetNode->renderer()->positionForPoint(selectionEndPoint);
838 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
840 if (!m_mouseDownMayStartSelect)
843 Node* target = hitTestResult.targetNode();
847 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
849 // Don't modify the selection if we're not on a node.
850 if (targetPosition.isNull())
853 // Restart the selection if this is the first mouse move. This work is usually
854 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
855 VisibleSelection newSelection = m_frame->selection()->selection();
858 // Special case to limit selection to the containing block for SVG text.
859 // FIXME: Isn't there a better non-SVG-specific way to do this?
860 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
861 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
862 if (selectionBaseRenderer->isSVGText())
863 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
867 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
870 if (m_selectionInitiationState != ExtendedSelection) {
871 // Always extend selection here because it's caused by a mouse drag
872 m_selectionInitiationState = ExtendedSelection;
873 newSelection = VisibleSelection(targetPosition);
876 #if ENABLE(USERSELECT_ALL)
877 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
878 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
879 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
880 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
882 // Reset base for user select all when base is inside user-select-all area and extent < base.
883 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
884 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
886 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
887 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
888 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
889 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
890 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
892 newSelection.setExtent(targetPosition);
895 newSelection.setExtent(targetPosition);
898 if (m_frame->selection()->granularity() != CharacterGranularity)
899 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
901 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection()->granularity(),
902 FrameSelection::AdjustEndpointsAtBidiBoundary);
904 #endif // ENABLE(DRAG_SUPPORT)
906 void EventHandler::lostMouseCapture()
908 m_frame->selection()->setCaretBlinkingSuspended(false);
911 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
913 if (eventLoopHandleMouseUp(event))
916 // If this was the first click in the window, we don't even want to clear the selection.
917 // This case occurs when the user clicks on a draggable element, since we have to process
918 // the mouse down and drag events to see if we might start a drag. For other first clicks
919 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
920 // ignored upstream of this layer.
921 return eventActivatedView(event.event());
924 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
926 if (autoscrollInProgress())
927 stopAutoscrollTimer();
929 if (handleMouseUp(event))
932 // Used to prevent mouseMoveEvent from initiating a drag before
933 // the mouse is pressed again.
934 m_mousePressed = false;
935 m_capturesDragging = false;
936 #if ENABLE(DRAG_SUPPORT)
937 m_mouseDownMayStartDrag = false;
939 m_mouseDownMayStartSelect = false;
940 m_mouseDownMayStartAutoscroll = false;
941 m_mouseDownWasInSubframe = false;
943 bool handled = false;
945 // Clear the selection if the mouse didn't move after the last mouse
946 // press and it's not a context menu click. We do this so when clicking
947 // on the selection, the selection goes away. However, if we are
948 // editing, place the caret.
949 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
950 #if ENABLE(DRAG_SUPPORT)
951 && m_dragStartPos == event.event().position()
953 && m_frame->selection()->isRange()
954 && event.event().button() != RightButton) {
955 VisibleSelection newSelection;
956 Node* node = event.targetNode();
957 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
958 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
959 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
960 newSelection = VisibleSelection(pos);
963 setSelectionIfNeeded(m_frame->selection(), newSelection);
968 m_frame->selection()->notifyRendererOfSelectionChange(UserTriggered);
970 m_frame->selection()->selectFrameElementInParentIfFullySelected();
972 if (event.event().button() == MiddleButton) {
973 // Ignore handled, since we want to paste to where the caret was placed anyway.
974 handled = handlePasteGlobalSelection(event.event()) || handled;
980 #if ENABLE(PAN_SCROLLING)
982 void EventHandler::didPanScrollStart()
984 m_autoscrollController->didPanScrollStart();
987 void EventHandler::didPanScrollStop()
989 m_autoscrollController->didPanScrollStop();
992 void EventHandler::startPanScrolling(RenderObject* renderer)
994 if (!renderer->isBox())
996 m_autoscrollController->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
1000 #endif // ENABLE(PAN_SCROLLING)
1002 RenderObject* EventHandler::autoscrollRenderer() const
1004 return m_autoscrollController->autoscrollRenderer();
1007 void EventHandler::updateAutoscrollRenderer()
1009 m_autoscrollController->updateAutoscrollRenderer();
1012 bool EventHandler::autoscrollInProgress() const
1014 return m_autoscrollController->autoscrollInProgress();
1017 bool EventHandler::panScrollInProgress() const
1019 return m_autoscrollController->panScrollInProgress();
1022 #if ENABLE(DRAG_SUPPORT)
1023 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1026 return DragSourceActionNone;
1028 Page* page = m_frame->page();
1030 return DragSourceActionNone;
1032 FrameView* view = m_frame->view();
1034 return DragSourceActionNone;
1036 return page->dragController()->delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1038 #endif // ENABLE(DRAG_SUPPORT)
1040 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1042 // We always send hitTestResultAtPoint to the main frame if we have one,
1043 // otherwise we might hit areas that are obscured by higher frames.
1044 if (Page* page = m_frame->page()) {
1045 Frame* mainFrame = page->mainFrame();
1046 if (m_frame != mainFrame) {
1047 FrameView* frameView = m_frame->view();
1048 FrameView* mainView = mainFrame->view();
1049 if (frameView && mainView) {
1050 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
1051 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()->focusedNode();
1096 node = m_mousePressNode.get();
1099 RenderObject* 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()->focusedNode();
1117 node = m_mousePressNode.get();
1120 RenderObject* 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 RenderObject* 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 static bool isSubmitImage(Node* node)
1206 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1209 // Returns true if the node's editable block is not current focused for editing
1210 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1212 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1215 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1220 bool editable = node->rendererIsEditable();
1221 bool editableLinkEnabled = false;
1223 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1225 ASSERT(m_frame->settings());
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>*)
1253 ASSERT(m_frame->document());
1258 void EventHandler::updateCursor()
1260 if (m_mousePositionIsUnknown)
1263 FrameView* view = m_frame->view();
1267 RenderView* renderView = view->renderView();
1271 if (!view->shouldSetCursor())
1278 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1280 m_frame->document()->updateLayout();
1282 HitTestRequest request(HitTestRequest::ReadOnly);
1283 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1284 renderView->hitTest(request, result);
1286 OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1287 if (optionalCursor.isCursorChange()) {
1288 m_currentMouseCursor = optionalCursor.cursor();
1289 view->setCursor(m_currentMouseCursor);
1293 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1295 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1296 return NoCursorChange;
1298 Page* page = m_frame->page();
1300 return NoCursorChange;
1301 #if ENABLE(PAN_SCROLLING)
1302 if (page->mainFrame()->eventHandler()->panScrollInProgress())
1303 return NoCursorChange;
1306 Node* node = result.targetNode();
1308 return NoCursorChange;
1310 RenderObject* renderer = node->renderer();
1311 RenderStyle* style = renderer ? renderer->style() : 0;
1312 bool horizontalText = !style || style->isHorizontalWritingMode();
1313 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1315 #if ENABLE(CURSOR_VISIBILITY)
1316 if (style && style->cursorVisibility() == CursorVisibilityAutoHide) {
1317 FeatureObserver::observe(m_frame->document(), FeatureObserver::CursorVisibility);
1318 startAutoHideCursorTimer();
1320 cancelAutoHideCursorTimer();
1323 // During selection, use an I-beam no matter what we're over.
1324 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1325 if (m_mousePressed && m_mouseDownMayStartSelect
1326 #if ENABLE(DRAG_SUPPORT)
1327 && !m_mouseDownMayStartDrag
1329 && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1333 Cursor overrideCursor;
1334 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1335 case SetCursorBasedOnStyle:
1338 return overrideCursor;
1339 case DoNotSetCursor:
1340 return NoCursorChange;
1344 if (style && style->cursors()) {
1345 const CursorList* cursors = style->cursors();
1346 for (unsigned i = 0; i < cursors->size(); ++i) {
1347 StyleImage* styleImage = (*cursors)[i].image();
1350 CachedImage* cachedImage = styleImage->cachedImage();
1353 float scale = styleImage->imageScaleFactor();
1354 // Get hotspot and convert from logical pixels to physical pixels.
1355 IntPoint hotSpot = (*cursors)[i].hotSpot();
1356 hotSpot.scale(scale, scale);
1357 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1358 if (cachedImage->errorOccurred())
1360 // Limit the size of cursors (in UI pixels) so that they cannot be
1361 // used to cover UI elements in chrome.
1362 size.scale(1 / scale);
1363 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1366 Image* image = cachedImage->imageForRenderer(renderer);
1367 #if ENABLE(MOUSE_CURSOR_SCALE)
1368 // Ensure no overflow possible in calculations above.
1369 if (scale < minimumCursorScale)
1371 return Cursor(image, hotSpot, scale);
1374 return Cursor(image, hotSpot);
1375 #endif // ENABLE(MOUSE_CURSOR_SCALE)
1379 switch (style ? style->cursor() : CURSOR_AUTO) {
1381 bool editable = node->rendererIsEditable();
1383 if (useHandCursor(node, result.isOverLink(), shiftKey))
1384 return handCursor();
1386 bool inResizer = false;
1388 if (RenderLayer* layer = renderer->enclosingLayer()) {
1389 if (FrameView* view = m_frame->view())
1390 inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
1393 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1395 return pointerCursor();
1398 return crossCursor();
1399 case CURSOR_POINTER:
1400 return handCursor();
1402 return moveCursor();
1403 case CURSOR_ALL_SCROLL:
1404 return moveCursor();
1405 case CURSOR_E_RESIZE:
1406 return eastResizeCursor();
1407 case CURSOR_W_RESIZE:
1408 return westResizeCursor();
1409 case CURSOR_N_RESIZE:
1410 return northResizeCursor();
1411 case CURSOR_S_RESIZE:
1412 return southResizeCursor();
1413 case CURSOR_NE_RESIZE:
1414 return northEastResizeCursor();
1415 case CURSOR_SW_RESIZE:
1416 return southWestResizeCursor();
1417 case CURSOR_NW_RESIZE:
1418 return northWestResizeCursor();
1419 case CURSOR_SE_RESIZE:
1420 return southEastResizeCursor();
1421 case CURSOR_NS_RESIZE:
1422 return northSouthResizeCursor();
1423 case CURSOR_EW_RESIZE:
1424 return eastWestResizeCursor();
1425 case CURSOR_NESW_RESIZE:
1426 return northEastSouthWestResizeCursor();
1427 case CURSOR_NWSE_RESIZE:
1428 return northWestSouthEastResizeCursor();
1429 case CURSOR_COL_RESIZE:
1430 return columnResizeCursor();
1431 case CURSOR_ROW_RESIZE:
1432 return rowResizeCursor();
1434 return iBeamCursor();
1436 return waitCursor();
1438 return helpCursor();
1439 case CURSOR_VERTICAL_TEXT:
1440 return verticalTextCursor();
1442 return cellCursor();
1443 case CURSOR_CONTEXT_MENU:
1444 return contextMenuCursor();
1445 case CURSOR_PROGRESS:
1446 return progressCursor();
1447 case CURSOR_NO_DROP:
1448 return noDropCursor();
1450 return aliasCursor();
1452 return copyCursor();
1454 return noneCursor();
1455 case CURSOR_NOT_ALLOWED:
1456 return notAllowedCursor();
1457 case CURSOR_DEFAULT:
1458 return pointerCursor();
1459 case CURSOR_WEBKIT_ZOOM_IN:
1460 return zoomInCursor();
1461 case CURSOR_WEBKIT_ZOOM_OUT:
1462 return zoomOutCursor();
1463 case CURSOR_WEBKIT_GRAB:
1464 return grabCursor();
1465 case CURSOR_WEBKIT_GRABBING:
1466 return grabbingCursor();
1468 return pointerCursor();
1471 #if ENABLE(CURSOR_VISIBILITY)
1472 void EventHandler::startAutoHideCursorTimer()
1474 Page* page = m_frame->page();
1478 m_autoHideCursorTimer.startOneShot(page->settings()->timeWithoutMouseMovementBeforeHidingControls());
1480 // The fake mouse move event screws up the auto-hide feature (by resetting the auto-hide timer)
1481 // so cancel any pending fake mouse moves.
1482 if (m_fakeMouseMoveEventTimer.isActive())
1483 m_fakeMouseMoveEventTimer.stop();
1486 void EventHandler::cancelAutoHideCursorTimer()
1488 if (m_autoHideCursorTimer.isActive())
1489 m_autoHideCursorTimer.stop();
1492 void EventHandler::autoHideCursorTimerFired(Timer<EventHandler>* timer)
1494 ASSERT_UNUSED(timer, timer == &m_autoHideCursorTimer);
1495 m_currentMouseCursor = noneCursor();
1496 FrameView* view = m_frame->view();
1497 if (view && view->isActive())
1498 view->setCursor(m_currentMouseCursor);
1502 static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1504 FrameView* view = frame->view();
1505 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1506 // Historically the code would just crash; this is clearly no worse than that.
1507 return view ? view->windowToContents(windowPoint) : windowPoint;
1510 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1512 RefPtr<FrameView> protector(m_frame->view());
1514 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1519 #if ENABLE(TOUCH_EVENTS)
1520 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1521 if (defaultPrevented)
1525 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1526 m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1528 // FIXME (bug 68185): this call should be made at another abstraction layer
1529 m_frame->loader()->resetMultipleFormSubmissionProtection();
1531 cancelFakeMouseMoveEvent();
1532 m_mousePressed = true;
1533 m_capturesDragging = true;
1534 setLastKnownMousePosition(mouseEvent);
1535 m_mouseDownTimestamp = mouseEvent.timestamp();
1536 #if ENABLE(DRAG_SUPPORT)
1537 m_mouseDownMayStartDrag = false;
1539 m_mouseDownMayStartSelect = false;
1540 m_mouseDownMayStartAutoscroll = false;
1541 if (FrameView* view = m_frame->view())
1542 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1547 m_mouseDownWasInSubframe = false;
1549 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1550 // Save the document point we generate in case the window coordinate is invalidated by what happens
1551 // when we dispatch the event.
1552 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1553 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1555 if (!mev.targetNode()) {
1560 m_mousePressNode = mev.targetNode();
1562 RefPtr<Frame> subframe = subframeForHitTestResult(mev);
1563 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1564 // Start capturing future events for this frame. We only do this if we didn't clear
1565 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1566 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1567 if (m_mousePressed && m_capturesDragging) {
1568 m_capturingMouseEventsNode = mev.targetNode();
1569 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1575 #if ENABLE(PAN_SCROLLING)
1576 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1577 // because it will set m_autoscrollType to NoAutoscroll on return.
1578 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress();
1579 stopAutoscrollTimer();
1580 if (isPanScrollInProgress) {
1581 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1582 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1588 m_clickCount = mouseEvent.clickCount();
1589 m_clickNode = mev.targetNode();
1591 if (FrameView* view = m_frame->view()) {
1592 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1593 IntPoint p = view->windowToContents(mouseEvent.position());
1594 if (layer && layer->isPointInResizeControl(p)) {
1595 layer->setInResizeMode(true);
1596 m_resizeLayer = layer;
1597 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1603 m_frame->selection()->setCaretBlinkingSuspended(true);
1605 bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1606 m_capturesDragging = !swallowEvent || mev.scrollbar();
1608 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1609 // in case the scrollbar widget was destroyed when the mouse event was handled.
1610 if (mev.scrollbar()) {
1611 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1612 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1613 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1614 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1615 m_lastScrollbarUnderMouse = 0;
1619 // scrollbars should get events anyway, even disabled controls might be scrollable
1620 Scrollbar* scrollbar = mev.scrollbar();
1622 updateLastScrollbarUnderMouse(scrollbar, true);
1625 passMousePressEventToScrollbar(mev, scrollbar);
1627 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1628 // If a mouse event handler changes the input element type to one that has a widget associated,
1629 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1630 // event target node can't still be the shadow node.
1631 if (mev.targetNode()->isShadowRoot() && toShadowRoot(mev.targetNode())->host()->hasTagName(inputTag)) {
1632 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1633 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1636 FrameView* view = m_frame->view();
1637 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1639 scrollbar = mev.scrollbar();
1641 updateLastScrollbarUnderMouse(scrollbar, true);
1643 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1644 swallowEvent = true;
1646 swallowEvent = handleMousePressEvent(mev);
1649 return swallowEvent;
1652 // This method only exists for platforms that don't know how to deliver
1653 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1655 RefPtr<FrameView> protector(m_frame->view());
1657 m_frame->selection()->setCaretBlinkingSuspended(false);
1659 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1661 // We get this instead of a second mouse-up
1662 m_mousePressed = false;
1663 setLastKnownMousePosition(mouseEvent);
1665 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
1666 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1667 Frame* subframe = subframeForHitTestResult(mev);
1668 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1669 m_capturingMouseEventsNode = 0;
1670 if (subframe && passMousePressEventToSubframe(mev, subframe))
1673 m_clickCount = mouseEvent.clickCount();
1674 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1676 bool swallowClickEvent = mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1678 if (m_lastScrollbarUnderMouse)
1679 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1681 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1685 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1688 static RenderLayer* layerForNode(Node* node)
1693 RenderObject* renderer = node->renderer();
1697 RenderLayer* layer = renderer->enclosingLayer();
1704 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1706 RefPtr<FrameView> protector(m_frame->view());
1707 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1709 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1710 bool result = handleMouseMoveEvent(event, &hoveredNode);
1712 Page* page = m_frame->page();
1716 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1717 if (FrameView* frameView = m_frame->view()) {
1718 if (frameView->containsScrollableArea(layer))
1719 layer->mouseMovedInContentArea();
1723 if (FrameView* frameView = m_frame->view())
1724 frameView->mouseMovedInContentArea();
1726 hoveredNode.setToNonShadowAncestor();
1727 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1728 page->chrome()->setToolTip(hoveredNode);
1732 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1734 HitTestResult hoveredNode;
1735 return handleMouseMoveEvent(event, &hoveredNode, true);
1738 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1740 // in Radar 3703768 we saw frequent crashes apparently due to the
1741 // part being null here, which seems impossible, so check for nil
1742 // but also assert so that we can try to figure this out in debug
1743 // builds, if it happens.
1748 #if ENABLE(TOUCH_EVENTS)
1749 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1750 if (defaultPrevented)
1754 RefPtr<FrameView> protector(m_frame->view());
1756 setLastKnownMousePosition(mouseEvent);
1758 if (m_hoverTimer.isActive())
1759 m_hoverTimer.stop();
1761 m_cursorUpdateTimer.stop();
1763 cancelFakeMouseMoveEvent();
1767 toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1772 if (m_frameSetBeingResized)
1773 return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1775 // Send events right to a scrollbar if the mouse is pressed.
1776 if (m_lastScrollbarUnderMouse && m_mousePressed)
1777 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1779 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent;
1781 hitType |= HitTestRequest::Active;
1782 else if (onlyUpdateScrollbars) {
1783 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1784 // means that :hover and :active freeze in the state they were in, rather than updating
1785 // for nodes the mouse moves while the window is not key (which will be the case if
1786 // onlyUpdateScrollbars is true).
1787 hitType |= HitTestRequest::ReadOnly;
1790 #if ENABLE(TOUCH_EVENTS)
1791 // Treat any mouse move events as readonly if the user is currently touching the screen.
1793 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1795 HitTestRequest request(hitType);
1796 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1798 *hoveredNode = mev.hitTestResult();
1800 Scrollbar* scrollbar = 0;
1802 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1803 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1805 if (FrameView* view = m_frame->view())
1806 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1809 scrollbar = mev.scrollbar();
1811 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1812 if (onlyUpdateScrollbars)
1816 bool swallowEvent = false;
1817 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.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);
1832 if (scrollbar && !m_mousePressed)
1833 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1834 if (FrameView* view = m_frame->view()) {
1835 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey());
1836 if (optionalCursor.isCursorChange()) {
1837 m_currentMouseCursor = optionalCursor.cursor();
1838 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 OwnPtr<UserGestureIndicator> gestureIndicator;
1901 if (m_lastMouseDownUserGestureToken)
1902 gestureIndicator = adoptPtr(new UserGestureIndicator(m_lastMouseDownUserGestureToken.release()));
1904 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1906 #if ENABLE(PAN_SCROLLING)
1907 m_autoscrollController->handleMouseReleaseEvent(mouseEvent);
1910 m_mousePressed = false;
1911 setLastKnownMousePosition(mouseEvent);
1916 toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1921 if (m_frameSetBeingResized)
1922 return !dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1924 if (m_lastScrollbarUnderMouse) {
1926 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1927 bool cancelable = true;
1928 bool setUnder = false;
1929 return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastNodeUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder);
1932 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
1933 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1934 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1935 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1936 m_capturingMouseEventsNode = 0;
1937 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1940 bool swallowMouseUpEvent = !dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1942 bool contextMenuEvent = mouseEvent.button() == RightButton;
1943 #if PLATFORM(CHROMIUM) && OS(DARWIN)
1944 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1945 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1946 contextMenuEvent = true;
1949 bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && mouseIsReleasedOnPressedElement(mev.targetNode(), m_clickNode.get()) && !dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1951 if (m_resizeLayer) {
1952 m_resizeLayer->setInResizeMode(false);
1956 bool swallowMouseReleaseEvent = false;
1957 if (!swallowMouseUpEvent)
1958 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1962 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1965 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1967 // If the event was a middle click, attempt to copy global selection in after
1968 // the newly set caret position.
1970 // This code is called from either the mouse up or mouse down handling. There
1971 // is some debate about when the global selection is pasted:
1972 // xterm: pastes on up.
1973 // GTK: pastes on down.
1974 // Qt: pastes on up.
1975 // Firefox: pastes on up.
1976 // Chromium: pastes on up.
1978 // There is something of a webcompat angle to this well, as highlighted by
1979 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1980 // down then the text is pasted just before the onclick handler runs and
1981 // clears the text box. So it's important this happens after the event
1982 // handlers have been fired.
1984 if (mouseEvent.type() != PlatformEvent::MousePressed)
1987 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1991 if (!m_frame->page())
1993 Frame* focusFrame = m_frame->page()->focusController()->focusedOrMainFrame();
1994 // Do not paste here if the focus was moved somewhere else.
1995 if (m_frame == focusFrame && m_frame->editor()->client()->supportsGlobalSelection())
1996 return m_frame->editor()->command(ASCIILiteral("PasteGlobalSelection")).execute();
2002 #if ENABLE(DRAG_SUPPORT)
2003 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
2005 FrameView* view = m_frame->view();
2007 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2011 view->resetDeferredRepaintDelay();
2012 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2013 true, true, m_frame->document()->defaultView(),
2014 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2015 #if ENABLE(POINTER_LOCK)
2016 event.movementDelta().x(), event.movementDelta().y(),
2018 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2021 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
2022 return me->defaultPrevented();
2025 static bool targetIsFrame(Node* target, Frame*& frame)
2030 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
2033 frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
2038 static bool findDropZone(Node* target, Clipboard* clipboard)
2040 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
2041 for (; element; element = element->parentElement()) {
2042 bool matched = false;
2043 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2045 if (dropZoneStr.isEmpty())
2048 dropZoneStr.makeLower();
2050 SpaceSplitString keywords(dropZoneStr, false);
2051 if (keywords.isNull())
2054 DragOperation dragOperation = DragOperationNone;
2055 for (unsigned int i = 0; i < keywords.size(); i++) {
2056 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2057 if (op != DragOperationNone) {
2058 if (dragOperation == DragOperationNone)
2061 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
2063 if (matched && dragOperation != DragOperationNone)
2067 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2074 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2076 bool accept = false;
2078 if (!m_frame->view())
2081 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2082 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
2084 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
2085 RefPtr<Node> newTarget = mev.targetNode();
2086 if (newTarget && newTarget->isTextNode())
2087 newTarget = EventPathWalker::parent(newTarget.get());
2089 m_autoscrollController->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
2091 if (m_dragTarget != newTarget) {
2092 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2093 // it is sometimes incorrect when dragging within subframes, as seen with
2094 // LayoutTests/fast/events/drag-in-frames.html.
2096 // 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>.
2098 if (targetIsFrame(newTarget.get(), targetFrame)) {
2100 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2101 } else if (newTarget) {
2102 // 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.
2103 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2104 // for now we don't care if event handler cancels default behavior, since there is none
2105 dispatchDragSrcEvent(eventNames().dragEvent, event);
2107 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget.get(), event, clipboard);
2109 accept = findDropZone(newTarget.get(), clipboard);
2112 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2114 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2115 } else if (m_dragTarget)
2116 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2119 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2120 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2121 m_shouldOnlyFireDragOverEvent = true;
2125 if (targetIsFrame(newTarget.get(), targetFrame)) {
2127 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2128 } else if (newTarget) {
2129 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2130 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2131 // for now we don't care if event handler cancels default behavior, since there is none
2132 dispatchDragSrcEvent(eventNames().dragEvent, event);
2134 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget.get(), event, clipboard);
2136 accept = findDropZone(newTarget.get(), clipboard);
2137 m_shouldOnlyFireDragOverEvent = false;
2140 m_dragTarget = newTarget;
2145 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2148 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2150 targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard);
2151 } else if (m_dragTarget.get()) {
2152 if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
2153 dispatchDragSrcEvent(eventNames().dragEvent, event);
2154 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2159 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2162 bool preventedDefault = false;
2163 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2165 preventedDefault = targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
2166 } else if (m_dragTarget.get())
2167 preventedDefault = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
2169 return preventedDefault;
2172 void EventHandler::clearDragState()
2174 stopAutoscrollTimer();
2176 m_capturingMouseEventsNode = 0;
2177 m_shouldOnlyFireDragOverEvent = false;
2179 m_sendingEventToSubview = false;
2182 #endif // ENABLE(DRAG_SUPPORT)
2184 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
2186 m_capturingMouseEventsNode = n;
2187 m_eventHandlerWillResetCapturingMouseEventsNode = false;
2190 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
2193 ASSERT(m_frame->document());
2195 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
2199 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
2201 if (!referenceNode || !referenceNode->isSVGElement())
2204 ShadowRoot* shadowRoot = referenceNode->containingShadowRoot();
2208 Element* shadowTreeParentElement = shadowRoot->host();
2209 if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag))
2212 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
2216 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
2218 Node* result = targetNode;
2220 // If we're capturing, we always go right to that node.
2221 if (m_capturingMouseEventsNode)
2222 result = m_capturingMouseEventsNode.get();
2224 // If the target node is a text node, dispatch on the parent node - rdar://4196646
2225 if (result && result->isTextNode())
2226 result = EventPathWalker::parent(result);
2228 m_nodeUnderMouse = result;
2230 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
2232 // <use> shadow tree elements may have been recloned, update node under mouse in any case
2233 if (m_lastInstanceUnderMouse) {
2234 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
2235 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
2237 if (lastCorrespondingElement && lastCorrespondingUseElement) {
2238 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
2240 // Locate the recloned shadow tree element for our corresponding instance
2241 HashSet<SVGElementInstance*>::iterator end = instances.end();
2242 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
2243 SVGElementInstance* instance = (*it);
2244 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
2246 if (instance == m_lastInstanceUnderMouse)
2249 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
2252 SVGElement* shadowTreeElement = instance->shadowTreeElement();
2253 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
2256 m_lastNodeUnderMouse = shadowTreeElement;
2257 m_lastInstanceUnderMouse = instance;
2264 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2265 if (fireMouseOverOut) {
2266 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
2267 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
2268 Page* page = m_frame->page();
2270 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
2271 // The mouse has moved between frames.
2272 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2273 if (FrameView* frameView = frame->view())
2274 frameView->mouseExitedContentArea();
2276 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2277 // The mouse has moved between layers.
2278 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2279 if (FrameView* frameView = frame->view()) {
2280 if (frameView->containsScrollableArea(layerForLastNode))
2281 layerForLastNode->mouseExitedContentArea();
2286 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2287 // The mouse has moved between frames.
2288 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2289 if (FrameView* frameView = frame->view())
2290 frameView->mouseEnteredContentArea();
2292 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2293 // The mouse has moved between layers.
2294 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2295 if (FrameView* frameView = frame->view()) {
2296 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2297 layerForNodeUnderMouse->mouseEnteredContentArea();
2302 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2303 m_lastNodeUnderMouse = 0;
2304 m_lastScrollbarUnderMouse = 0;
2306 m_lastInstanceUnderMouse = 0;
2310 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2311 // send mouseout event to the old node
2312 if (m_lastNodeUnderMouse)
2313 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2314 // send mouseover event to the new node
2315 if (m_nodeUnderMouse)
2316 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2318 m_lastNodeUnderMouse = m_nodeUnderMouse;
2320 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2325 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2327 if (FrameView* view = m_frame->view())
2328 view->resetDeferredRepaintDelay();
2330 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2332 bool swallowEvent = false;
2334 if (m_nodeUnderMouse)
2335 swallowEvent = !(m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount));
2337 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2339 // If clicking on a frame scrollbar, do not mess up with content focus.
2340 if (FrameView* view = m_frame->view()) {
2341 if (view->scrollbarAtPoint(mouseEvent.position()))
2345 // The layout needs to be up to date to determine if an element is focusable.
2346 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2348 // Blur current focus node when a link/button is clicked; this
2349 // is expected by some sites that rely on onChange handlers running
2350 // from form fields before the button click is processed.
2351 Node* node = m_nodeUnderMouse.get();
2353 // Walk up the DOM tree to search for a node to focus.
2355 if (node->isMouseFocusable()) {
2356 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2357 // node on mouse down if it's selected and inside a focused node. It will be
2358 // focused if the user does a mouseup over it, however, because the mouseup
2359 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2360 Node* n = node->isShadowRoot() ? toShadowRoot(node)->host() : node;
2361 if (m_frame->selection()->isRange()
2362 && m_frame->selection()->toNormalizedRange()->compareNode(n, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2363 && n->isDescendantOf(m_frame->document()->focusedNode()))
2368 node = node->parentOrShadowHostNode();
2371 // Only change the focus when clicking scrollbars if it can transfered to a mouse focusable node.
2372 if ((!node || !node->isMouseFocusable()) && isInsideScrollbar(mouseEvent.position()))
2375 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2376 // if the page already set it (e.g., by canceling default behavior).
2377 if (Page* page = m_frame->page()) {
2378 if (node && node->isMouseFocusable()) {
2379 if (!page->focusController()->setFocusedNode(node, m_frame))
2380 swallowEvent = true;
2381 } else if (!node || !node->focused()) {
2382 if (!page->focusController()->setFocusedNode(0, m_frame))
2383 swallowEvent = true;
2388 return !swallowEvent;
2391 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2393 if (RenderView* renderView = m_frame->contentRenderer()) {
2394 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2395 HitTestResult result(windowPoint);
2396 renderView->hitTest(request, result);
2397 return result.scrollbar();
2403 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
2404 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2410 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2412 Document* doc = m_frame->document();
2414 RenderObject* docRenderer = doc->renderer();
2418 RefPtr<FrameView> protector(m_frame->view());
2420 FrameView* view = m_frame->view();
2423 setFrameWasScrolledByUser();
2424 LayoutPoint vPoint = view->windowToContents(e.position());
2426 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2427 HitTestResult result(vPoint);
2428 doc->renderView()->hitTest(request, result);
2430 bool useLatchedWheelEventNode = e.useLatchedEventNode();
2432 Node* node = result.innerNode();
2433 // Wheel events should not dispatch to text nodes.
2434 if (node && node->isTextNode())
2435 node = EventPathWalker::parent(node);
2438 if (useLatchedWheelEventNode) {
2439 if (!m_latchedWheelEventNode) {
2440 m_latchedWheelEventNode = node;
2441 m_widgetIsLatched = result.isOverWidget();
2443 node = m_latchedWheelEventNode.get();
2445 isOverWidget = m_widgetIsLatched;
2447 if (m_latchedWheelEventNode)
2448 m_latchedWheelEventNode = 0;
2449 if (m_previousWheelScrolledNode)
2450 m_previousWheelScrolledNode = 0;
2452 isOverWidget = result.isOverWidget();
2455 // FIXME: It should not be necessary to do this mutation here.
2456 // Instead, the handlers should know convert vertical scrolls
2458 PlatformWheelEvent event = e;
2459 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2460 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2463 // Figure out which view to send the event to.
2464 RenderObject* target = node->renderer();
2466 if (isOverWidget && target && target->isWidget()) {
2467 Widget* widget = toRenderWidget(target)->widget();
2468 if (widget && passWheelEventToWidget(e, widget))
2472 if (node && !node->dispatchWheelEvent(event))
2477 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2478 view = m_frame->view();
2482 return view->wheelEvent(event);
2485 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2487 if (!startNode || !wheelEvent)
2490 Node* stopNode = m_previousWheelScrolledNode.get();
2491 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2493 // Break up into two scrolls if we need to. Diagonal movement on
2494 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2495 if (scrollNode(wheelEvent->rawDeltaX(), granularity, ScrollLeft, ScrollRight, startNode, &stopNode))
2496 wheelEvent->setDefaultHandled();
2498 if (scrollNode(wheelEvent->rawDeltaY(), granularity, ScrollUp, ScrollDown, startNode, &stopNode))
2499 wheelEvent->setDefaultHandled();
2501 if (!m_latchedWheelEventNode)
2502 m_previousWheelScrolledNode = stopNode;
2505 #if ENABLE(GESTURE_EVENTS)
2506 bool EventHandler::handleGestureTapDown()
2508 FrameView* view = m_frame->view();
2511 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2512 scrollAnimator->cancelAnimations();
2513 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2516 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2517 ScrollableArea* sa = *it;
2518 ScrollAnimator* animator = sa->scrollAnimator();
2520 animator->cancelAnimations();
2525 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2527 Node* eventTarget = 0;
2528 Scrollbar* scrollbar = 0;
2529 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2530 || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2531 || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2532 scrollbar = m_scrollbarHandlingScrollGesture.get();
2533 eventTarget = m_scrollGestureHandlingNode.get();
2536 IntPoint adjustedPoint = gestureEvent.position();
2537 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2538 if (gestureEvent.type() == PlatformEvent::GestureTapDown) {
2539 #if ENABLE(TOUCH_ADJUSTMENT)
2540 adjustGesturePosition(gestureEvent, adjustedPoint);
2542 hitType |= HitTestRequest::Active;
2543 } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel)
2544 hitType |= HitTestRequest::Release;
2545 else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2546 // The mouseup event synthesized for this gesture will clear the active state of the
2547 // targeted node, so performing a ReadOnly hit test here is fine.
2548 hitType |= HitTestRequest::ReadOnly;
2551 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2553 if (!shouldGesturesTriggerActive())
2554 hitType |= HitTestRequest::ReadOnly;
2556 if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2557 IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2558 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2559 eventTarget = result.targetNode();
2561 FrameView* view = m_frame->view();
2562 scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2565 scrollbar = result.scrollbar();
2569 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2570 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin && eventSwallowed)
2571 m_scrollbarHandlingScrollGesture = scrollbar;
2572 else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd || !eventSwallowed)
2573 m_scrollbarHandlingScrollGesture = 0;
2580 bool eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2581 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2583 m_scrollGestureHandlingNode = eventTarget;
2590 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2591 // eliminate the need for this.
2592 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2594 switch (gestureEvent.type()) {
2595 case PlatformEvent::GestureScrollBegin:
2596 return handleGestureScrollBegin(gestureEvent);
2597 case PlatformEvent::GestureScrollUpdate:
2598 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2599 return handleGestureScrollUpdate(gestureEvent);
2600 case PlatformEvent::GestureScrollEnd:
2601 clearGestureScrollNodes();
2603 case PlatformEvent::GestureTap:
2604 return handleGestureTap(gestureEvent);
2605 case PlatformEvent::GestureTapDown:
2606 return handleGestureTapDown();
2607 case PlatformEvent::GestureLongPress:
2608 return handleGestureLongPress(gestureEvent);
2609 case PlatformEvent::GestureLongTap:
2610 return handleGestureLongTap(gestureEvent);
2611 case PlatformEvent::GestureTwoFingerTap:
2612 return handleGestureTwoFingerTap(gestureEvent);
2613 case PlatformEvent::GesturePinchBegin:
2614 case PlatformEvent::GesturePinchEnd:
2615 case PlatformEvent::GesturePinchUpdate:
2616 case PlatformEvent::GestureTapDownCancel:
2619 ASSERT_NOT_REACHED();
2625 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent)
2627 // FIXME: Refactor this code to not hit test multiple times. We use the adjusted position to ensure that the correct node is targeted by the later redundant hit tests.
2628 IntPoint adjustedPoint = gestureEvent.position();
2629 #if ENABLE(TOUCH_ADJUSTMENT)
2630 adjustGesturePosition(gestureEvent, adjustedPoint);
2633 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2634 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2635 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2636 mouseMoved(fakeMouseMove);
2639 // FIXME: deletaX is overloaded to mean different things for different gestures.
2640 // http://wkb.ug/93123
2641 if (gestureEvent.deltaX() > 0)
2642 tapCount = static_cast<int>(gestureEvent.deltaX());
2644 bool defaultPrevented = false;
2645 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2646 LeftButton, PlatformEvent::MousePressed, tapCount,
2647 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2648 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2650 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2651 LeftButton, PlatformEvent::MouseReleased, tapCount,
2652 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2653 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2655 return defaultPrevented;
2658 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent)
2660 #if ENABLE(DRAG_SUPPORT)
2661 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled()) {
2662 IntPoint adjustedPoint = gestureEvent.position();
2663 #if ENABLE(TOUCH_ADJUSTMENT)
2664 adjustGesturePosition(gestureEvent, adjustedPoint);
2666 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 0, false, false, false, false, WTF::currentTime());
2667 handleMousePressEvent(mouseDownEvent);
2668 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WTF::currentTime());
2669 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2670 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2671 m_didStartDrag = false;
2672 RefPtr<Frame> subframe = subframeForHitTestResult(mev);
2673 if (subframe && !m_mouseDownMayStartDrag) {
2674 if (subframe->eventHandler()->handleGestureLongPress(gestureEvent))
2677 handleDrag(mev, DontCheckDragHysteresis);
2682 return handleGestureForTextSelectionOrContextMenu(gestureEvent);
2685 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent)
2687 #if ENABLE(CONTEXT_MENUS) && !OS(ANDROID)
2688 if (!m_didLongPressInvokeContextMenu)
2689 return sendContextMenuEventForGesture(gestureEvent);
2694 bool EventHandler::handleGestureForTextSelectionOrContextMenu(const PlatformGestureEvent& gestureEvent)
2697 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2698 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
2699 Node* innerNode = result.targetNode();
2700 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2701 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2702 if (m_frame->selection()->isRange())
2706 #if ENABLE(CONTEXT_MENUS)
2707 m_didLongPressInvokeContextMenu = (gestureEvent.type() == PlatformEvent::GestureLongPress);
2708 return sendContextMenuEventForGesture(gestureEvent);
2714 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent)
2716 return handleGestureForTextSelectionOrContextMenu(gestureEvent);
2719 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2724 if (!widget->isFrameView())
2727 return toFrameView(widget)->frame()->eventHandler()->handleGestureEvent(gestureEvent);
2730 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2732 if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2733 Widget* widget = toRenderWidget(renderer)->widget();
2734 return widget && passGestureEventToWidget(gestureEvent, widget);
2739 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2741 Document* document = m_frame->document();
2742 RenderObject* documentRenderer = document->renderer();
2743 if (!documentRenderer)
2746 FrameView* view = m_frame->view();
2750 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2751 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::DisallowShadowContent);
2752 HitTestResult result(viewPoint);
2753 document->renderView()->hitTest(request, result);
2755 m_lastHitTestResultOverWidget = result.isOverWidget();
2756 m_scrollGestureHandlingNode = result.innerNode();
2757 m_previousGestureScrolledNode = 0;
2759 Node* node = m_scrollGestureHandlingNode.get();
2761 passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2763 return node && node->renderer();
2766 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2768 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2772 const float scaleFactor = m_frame->pageZoomFactor() * m_frame->frameScaleFactor();
2773 delta.scale(1 / scaleFactor, 1 / scaleFactor);
2775 Node* node = m_scrollGestureHandlingNode.get();
2777 return sendScrollEventToView(gestureEvent, delta);
2779 // Ignore this event if the targeted node does not have a valid renderer.
2780 RenderObject* renderer = node->renderer();
2784 RefPtr<FrameView> protector(m_frame->view());
2786 // Try to send the event to the correct view.
2787 if (passGestureEventToWidgetIfPossible(gestureEvent, renderer))
2791 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2792 if (scrollShouldNotPropagate)
2793 stopNode = m_previousGestureScrolledNode.get();
2795 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2796 ScrollGranularity granularity = ScrollByPixel;
2797 bool horizontalScroll = scrollNode(delta.width(), granularity, ScrollLeft, ScrollRight, node, &stopNode);
2798 bool verticalScroll = scrollNode(delta.height(), granularity, ScrollUp, ScrollDown, node, &stopNode);
2800 if (scrollShouldNotPropagate)
2801 m_previousGestureScrolledNode = stopNode;
2803 if (horizontalScroll || verticalScroll) {
2804 setFrameWasScrolledByUser();
2808 // Otherwise try to scroll the view.
2809 return sendScrollEventToView(gestureEvent, delta);
2812 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2814 FrameView* view = m_frame->view();
2818 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2819 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2820 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2821 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2822 scaledDelta.width(), scaledDelta.height(),
2823 scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2824 ScrollByPixelWheelEvent,
2825 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2826 #if PLATFORM(MAC) || PLATFORM(CHROMIUM)
2827 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2830 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2832 setFrameWasScrolledByUser();
2834 return scrolledFrame;
2837 void EventHandler::clearGestureScrollNodes()
2839 m_scrollGestureHandlingNode = 0;
2840 m_previousGestureScrolledNode = 0;
2843 bool EventHandler::isScrollbarHandlingGestures() const
2845 return m_scrollbarHandlingScrollGesture.get();
2847 #endif // ENABLE(GESTURE_EVENTS)
2849 #if ENABLE(TOUCH_ADJUSTMENT)
2850 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2852 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2854 return !event.area().isEmpty();
2858 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2860 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2861 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2863 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2864 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2866 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2867 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2868 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2869 // handle targetNode being a shadow DOM node.
2870 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2871 if (success && targetNode)
2872 targetNode = targetNode->deprecatedShadowAncestorNode();
2876 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2878 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2879 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2881 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2882 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2883 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2886 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2888 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2889 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent, touchRadius);
2891 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2892 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2893 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get());
2896 bool EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2898 if (!shouldApplyTouchAdjustment(gestureEvent))
2901 Node* targetNode = 0;
2902 switch (gestureEvent.type()) {
2903 case PlatformEvent::GestureTap:
2904 case PlatformEvent::GestureTapDown:
2905 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2907 case PlatformEvent::GestureLongPress:
2908 case PlatformEvent::GestureLongTap:
2909 case PlatformEvent::GestureTwoFingerTap:
2910 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2913 // FIXME: Implement handling for other types as needed.
2914 ASSERT_NOT_REACHED();
2920 #if ENABLE(CONTEXT_MENUS)
2921 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2923 Document* doc = m_frame->document();
2924 FrameView* v = m_frame->view();
2928 // Clear mouse press state to avoid initiating a drag while context menu is up.
2929 m_mousePressed = false;
2931 LayoutPoint viewportPos = v->windowToContents(event.position());
2932 HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
2933 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2935 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2936 && !m_frame->selection()->contains(viewportPos)
2938 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2939 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2940 // available for text selections. But only if we're above text.
2941 && (m_frame->selection()->isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2942 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2943 selectClosestWordOrLinkFromMouseEvent(mev);
2946 swallowEvent = !dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, false);
2948 return swallowEvent;
2951 bool EventHandler::sendContextMenuEventForKey()
2953 FrameView* view = m_frame->view();
2957 Document* doc = m_frame->document();
2961 // Clear mouse press state to avoid initiating a drag while context menu is up.
2962 m_mousePressed = false;
2964 static const int kContextMenuMargin = 1;
2966 #if OS(WINDOWS) && !OS(WINCE)
2967 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2969 int rightAligned = 0;
2973 Node* focusedNode = doc->focusedNode();
2974 FrameSelection* selection = m_frame->selection();
2975 Position start = selection->selection().start();
2977 if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) {
2978 RefPtr<Range> selectionRange = selection->toNormalizedRange();
2979 IntRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get());
2981 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2982 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2983 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2984 location = IntPoint(x, y);
2985 } else if (focusedNode) {
2986 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2989 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2990 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2992 location = IntPoint(
2993 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2994 kContextMenuMargin);
2997 m_frame->view()->setCursor(pointerCursor());
2999 IntPoint position = view->contentsToRootView(location);
3000 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
3002 Node* targetNode = doc->focusedNode();
3006 // Use the focused node as the target for hover and active.
3007 HitTestResult result(position);
3008 result.setInnerNode(targetNode);
3009 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowShadowContent, result.innerElement());
3011 // The contextmenu event is a mouse event even when invoked using the keyboard.
3012 // This is required for web compatibility.
3015 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
3017 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
3020 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
3022 return !dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
3025 #if ENABLE(GESTURE_EVENTS)
3026 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
3029 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
3031 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
3034 IntPoint adjustedPoint = event.position();
3035 #if ENABLE(TOUCH_ADJUSTMENT)
3036 adjustGesturePosition(event, adjustedPoint);
3038 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
3039 // To simulate right-click behavior, we send a right mouse down and then
3040 // context menu event.
3041 handleMousePressEvent(mouseEvent);
3042 return sendContextMenuEvent(mouseEvent);
3043 // We do not need to send a corresponding mouse release because in case of
3044 // right-click, the context menu takes capture and consumes all events.
3046 #endif // ENABLE(GESTURE_EVENTS)
3047 #endif // ENABLE(CONTEXT_MENUS)
3049 void EventHandler::scheduleHoverStateUpdate()
3051 if (!m_hoverTimer.isActive())
3052 m_hoverTimer.startOneShot(0);
3055 void EventHandler::scheduleCursorUpdate()
3057 if (!m_cursorUpdateTimer.isActive())
3058 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
3061 void EventHandler::dispatchFakeMouseMoveEventSoon()
3066 if (m_mousePositionIsUnknown)
3069 Settings* settings = m_frame->settings();
3070 if (settings && !settings->deviceSupportsMouse())
3073 // If the content has ever taken longer than fakeMouseMoveShortInterval we
3074 // reschedule the timer and use a longer time. This will cause the content
3075 // to receive these moves only after the user is done scrolling, reducing
3076 // pauses during the scroll.
3077 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
3078 if (m_fakeMouseMoveEventTimer.isActive())
3079 m_fakeMouseMoveEventTimer.stop();
3080 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
3082 if (!m_fakeMouseMoveEventTimer.isActive())
3083 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
3087 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
3089 FrameView* view = m_frame->view();
3093 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
3096 dispatchFakeMouseMoveEventSoon();
3099 void EventHandler::cancelFakeMouseMoveEvent()
3101 m_fakeMouseMoveEventTimer.stop();
3104 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
3106 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
3107 ASSERT(!m_mousePressed);
3109 Settings* settings = m_frame->settings();
3110 if (settings && !settings->deviceSupportsMouse())
3113 FrameView* view = m_frame->view();
3117 if (!m_frame->page() || !m_frame->page()->isOnscreen() || !m_frame->page()->focusController()->isActive())
3124 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
3125 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
3126 mouseMoved(fakeMouseMoveEvent);
3129 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
3131 m_frameSetBeingResized = frameSet;
3134 void EventHandler::resizeLayerDestroyed()
3136 ASSERT(m_resizeLayer);
3140 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
3142 m_hoverTimer.stop();
3145 ASSERT(m_frame->document());
3147 if (RenderView* renderer = m_frame->contentRenderer()) {
3148 if (FrameView* view = m_frame->view()) {
3149 HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowShadowContent);
3150 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
3151 renderer->hitTest(request, result);
3152 m_frame->document()->updateHoverActiveState(request, result.innerElement());
3157 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
3159 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3160 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3161 // lower case variants are present in a document, the correct element is matched based on Shift key state.
3162 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3163 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
3164 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
3166 String key = evt.unmodifiedText();
3167 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
3170 elem->accessKeyAction(false);
3175 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
3181 #if ENABLE(FULLSCREEN_API)
3182 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
3184 Document* document = m_frame->document();
3185 if (document->webkitFullScreenKeyboardInputAllowed())
3188 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3189 if (keyEvent.text().length() != 1)
3191 UChar character = keyEvent.text()[0];
3192 return character == ' ';
3195 int keyCode = keyEvent.windowsVirtualKeyCode();
3196 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3197 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3198 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3199 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3203 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3205 RefPtr<FrameView> protector(m_frame->view());
3207 #if ENABLE(FULLSCREEN_API)
3208 if (m_frame->document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
3212 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3213 capsLockStateMayHaveChanged();
3215 #if ENABLE(PAN_SCROLLING)
3216 if (Page* page = m_frame->page()) {
3217 if (page->mainFrame()->eventHandler()->panScrollInProgress()) {
3218 // If a key is pressed while the panScroll is in progress then we want to stop
3219 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3220 stopAutoscrollTimer();
3222 // If we were in panscroll mode, we swallow the key event
3228 // Check for cases where we are too early for events -- possible unmatched key up
3229 // from pressing return in the location bar.
3230 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
3234 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3235 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3237 if (FrameView* view = m_frame->view())
3238 view->resetDeferredRepaintDelay();
3240 // FIXME (bug 68185): this call should be made at another abstraction layer
3241 m_frame->loader()->resetMultipleFormSubmissionProtection();
3243 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3244 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3245 // with access keys. Then we dispatch keydown, but suppress its default handling.
3246 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3247 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3248 bool matchedAnAccessKey = false;
3249 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3250 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3252 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3253 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3254 return !node->dispatchKeyEvent(initialKeyEvent);
3256 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3258 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3259 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3260 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3261 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
3262 if (matchedAnAccessKey)
3263 keydown->setDefaultPrevented(true);
3264 keydown->setTarget(node);
3266 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3267 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3268 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3269 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3270 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3273 // Run input method in advance of DOM event handling. This may result in the IM
3274 // modifying the page prior the keydown event, but this behaviour is necessary
3275 // in order to match IE:
3276 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3277 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3278 m_frame->editor()->handleInputMethodKeydown(keydown.get());
3280 bool handledByInputMethod = keydown->defaultHandled();
3282 if (handledByInputMethod) {
3283 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3284 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
3285 keydown->setTarget(node);
3286 keydown->setDefaultHandled();
3289 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3290 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3291 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3292 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3293 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3294 return keydownResult;
3296 // Focus may have changed during keydown handling, so refetch node.
3297 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3298 if (!keydownResult) {
3299 node = eventTargetNodeForDocument(m_frame->document());
3304 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3305 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3306 if (keyPressEvent.text().isEmpty())
3307 return keydownResult;
3308 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
3309 keypress->setTarget(node);
3311 keypress->setDefaultPrevented(true);
3313 keypress->keypressCommands() = keydown->keypressCommands();
3315 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
3317 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3320 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3322 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3323 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3324 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3325 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3327 FocusDirection retVal = FocusDirectionNone;
3329 if (keyIdentifier == Down)
3330 retVal = FocusDirectionDown;
3331 else if (keyIdentifier == Up)
3332 retVal = FocusDirectionUp;
3333 else if (keyIdentifier == Left)
3334 retVal = FocusDirectionLeft;
3335 else if (keyIdentifier == Right)
3336 retVal = FocusDirectionRight;
3341 static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardEvent* event)
3346 bool isOptioned = event->getModifierState("Alt");
3347 bool isCommanded = event->getModifierState("Meta");
3349 SelectionDirection direction = DirectionForward;
3350 TextGranularity granularity = CharacterGranularity;
3352 switch (focusDirectionForKey(event->keyIdentifier())) {
3353 case FocusDirectionNone:
3355 case FocusDirectionForward:
3356 case FocusDirectionBackward:
3357 ASSERT_NOT_REACHED();
3359 case FocusDirectionUp:
3360 direction = DirectionBackward;
3361 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3363 case FocusDirectionDown:
3364 direction = DirectionForward;
3365 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3367 case FocusDirectionLeft:
3368 direction = DirectionLeft;
3369 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3371 case FocusDirectionRight:
3372 direction = DirectionRight;
3373 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3377 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3378 selection->modify(alternation, direction, granularity, UserTriggered);
3379 event->setDefaultHandled();
3382 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3384 if (event->type() == eventNames().keydownEvent) {
3385 m_frame->editor()->handleKeyboardEvent(event);
3386 if (event->defaultHandled())
3388 if (event->keyIdentifier() == "U+0009")
3389 defaultTabEventHandler(event);
3390 else if (event->keyIdentifier() == "U+0008")
3391 defaultBackspaceEventHandler(event);
3393 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3394 if (direction != FocusDirectionNone)
3395 defaultArrowEventHandler(direction, event);
3398 // provides KB navigation and selection for enhanced accessibility users
3399 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3400 handleKeyboardSelectionMovement(m_frame->selection(), event);
3402 if (event->type() == eventNames().keypressEvent) {
3403 m_frame->editor()->handleKeyboardEvent(event);
3404 if (event->defaultHandled())
3406 if (event->charCode() == ' ')
3407 defaultSpaceEventHandler(event);
3411 #if ENABLE(DRAG_SUPPORT)
3412 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3414 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3415 return dragHysteresisExceeded(dragViewportLocation);
3418 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3420 FrameView* view = m_frame->view();
3423 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3424 IntSize delta = dragLocation - m_mouseDownPos;
3426 int threshold = GeneralDragHysteresis;
3427 switch (dragState().m_dragType) {
3428 case DragSourceActionSelection:
3429 threshold = TextDragHysteresis;
3431 case DragSourceActionImage:
3432 threshold = ImageDragHysteresis;
3434 case DragSourceActionLink:
3435 threshold = LinkDragHysteresis;
3437 case DragSourceActionDHTML:
3439 case DragSourceActionNone:
3440 case DragSourceActionAny:
3441 ASSERT_NOT_REACHED();
3444 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3447 void EventHandler::freeClipboard()
3449 if (dragState().m_dragClipboard)
3450 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3453 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3455 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3456 HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowShadowContent);
3457 prepareMouseEvent(request, event);
3459 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
3460 dragState().m_dragClipboard->setDestinationOperation(operation);
3461 // for now we don't care if event handler cancels default behavior, since there is none
3462 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3465 dragState().m_dragSrc = 0;
3466 // In case the drag was ended due to an escape key press we need to ensure
3467 // that consecutive mousemove events don't reinitiate the drag and drop.
3468 m_mouseDownMayStartDrag = false;
3471 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3473 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3474 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3475 dragState().m_dragSrc = rootEditableElement;
3478 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3479 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3481 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3484 static bool ExactlyOneBitSet(DragSourceAction n)
3486 return n && !(n & (n - 1));
3489 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3491 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3492 // If we allowed the other side of the bridge to handle a drag
3493 // last time, then m_mousePressed might still be set. So we
3494 // clear it now to&nbs