2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "EventHandler.h"
30 #include "AXObjectCache.h"
31 #include "CachedImage.h"
33 #include "ChromeClient.h"
35 #include "CursorList.h"
37 #include "DocumentEventQueue.h"
38 #include "DragController.h"
39 #include "DragState.h"
41 #include "EventNames.h"
42 #include "FloatPoint.h"
43 #include "FloatRect.h"
44 #include "FocusController.h"
46 #include "FrameLoader.h"
47 #include "FrameSelection.h"
48 #include "FrameTree.h"
49 #include "FrameView.h"
50 #include "htmlediting.h"
51 #include "HTMLFrameElementBase.h"
52 #include "HTMLFrameSetElement.h"
53 #include "HTMLInputElement.h"
54 #include "HTMLNames.h"
55 #include "HitTestRequest.h"
56 #include "HitTestResult.h"
58 #include "InspectorInstrumentation.h"
59 #include "KeyboardEvent.h"
60 #include "MouseEvent.h"
61 #include "MouseEventWithHitTestResults.h"
63 #include "PlatformEvent.h"
64 #include "PlatformKeyboardEvent.h"
65 #include "PlatformWheelEvent.h"
66 #include "PluginDocument.h"
67 #include "RenderFrameSet.h"
68 #include "RenderLayer.h"
69 #include "RenderTextControlSingleLine.h"
70 #include "RenderView.h"
71 #include "RenderWidget.h"
72 #include "ScrollAnimator.h"
73 #include "Scrollbar.h"
75 #include "SpatialNavigation.h"
76 #include "StaticHashSetNodeList.h"
77 #include "StyleCachedImage.h"
78 #include "TextEvent.h"
79 #include "TextIterator.h"
80 #include "UserGestureIndicator.h"
81 #include "UserTypingGestureIndicator.h"
82 #include "WheelEvent.h"
83 #include "WindowsKeyboardCodes.h"
84 #include <wtf/Assertions.h>
85 #include <wtf/CurrentTime.h>
86 #include <wtf/StdLibExtras.h>
87 #include <wtf/TemporaryChange.h>
89 #if ENABLE(GESTURE_EVENTS)
90 #include "PlatformGestureEvent.h"
93 #if ENABLE(TOUCH_ADJUSTMENT)
94 #include "TouchAdjustment.h"
98 #include "SVGDocument.h"
99 #include "SVGElementInstance.h"
100 #include "SVGNames.h"
101 #include "SVGUseElement.h"
104 #if ENABLE(TOUCH_EVENTS)
105 #include "PlatformTouchEvent.h"
106 #include "TouchEvent.h"
107 #include "TouchList.h"
112 using namespace HTMLNames;
114 #if ENABLE(DRAG_SUPPORT)
115 // The link drag hysteresis is much larger than the others because there
116 // needs to be enough space to cancel the link press without starting a link drag,
117 // and because dragging links is rare.
118 const int LinkDragHysteresis = 40;
119 const int ImageDragHysteresis = 5;
120 const int TextDragHysteresis = 3;
121 const int GeneralDragHysteresis = 3;
122 #endif // ENABLE(DRAG_SUPPORT)
124 // Match key code of composition keydown event on windows.
125 // IE sends VK_PROCESSKEY which has value 229;
126 const int CompositionEventKeyCode = 229;
129 using namespace SVGNames;
132 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
133 const double autoscrollInterval = 0.05;
135 // The amount of time to wait before sending a fake mouse event, triggered
136 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
137 // otherwise the long interval is used.
138 const double fakeMouseMoveShortInterval = 0.1;
139 const double fakeMouseMoveLongInterval = 0.250;
141 enum NoCursorChangeType { NoCursorChange };
143 class OptionalCursor {
145 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
146 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
148 bool isCursorChange() const { return m_isCursorChange; }
149 const Cursor& cursor() const { return m_cursor; }
152 bool m_isCursorChange;
156 class MaximumDurationTracker {
158 explicit MaximumDurationTracker(double *maxDuration)
159 : m_maxDuration(maxDuration)
160 , m_start(monotonicallyIncreasingTime())
164 ~MaximumDurationTracker()
166 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
170 double* m_maxDuration;
174 #if ENABLE(TOUCH_EVENTS)
175 class SyntheticTouchPoint : public PlatformTouchPoint {
178 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
179 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
181 const static int idDefaultValue = 0;
182 const static int radiusYDefaultValue = 1;
183 const static int radiusXDefaultValue = 1;
184 const static float rotationAngleDefaultValue = 0.0f;
185 const static float forceDefaultValue = 1.0f;
187 m_id = idDefaultValue; // There is only one active TouchPoint.
188 m_screenPos = event.globalPosition();
189 m_pos = event.position();
190 m_radiusY = radiusYDefaultValue;
191 m_radiusX = radiusXDefaultValue;
192 m_rotationAngle = rotationAngleDefaultValue;
193 m_force = forceDefaultValue;
195 PlatformEvent::Type type = event.type();
196 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
199 case PlatformEvent::MouseMoved:
200 m_state = TouchMoved;
202 case PlatformEvent::MousePressed:
203 m_state = TouchPressed;
205 case PlatformEvent::MouseReleased:
206 m_state = TouchReleased;
209 ASSERT_NOT_REACHED();
215 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
217 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
219 switch (event.type()) {
220 case PlatformEvent::MouseMoved:
223 case PlatformEvent::MousePressed:
226 case PlatformEvent::MouseReleased:
230 ASSERT_NOT_REACHED();
234 m_timestamp = event.timestamp();
235 m_modifiers = event.modifiers();
236 m_touchPoints.append(SyntheticTouchPoint(event));
241 static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent::Granularity granularity)
243 switch (granularity) {
244 case WheelEvent::Page:
246 case WheelEvent::Line:
248 case WheelEvent::Pixel:
249 return ScrollByPixel;
251 return ScrollByPixel;
254 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
258 if (!node->renderer())
260 RenderBox* enclosingBox = node->renderer()->enclosingBox();
261 float absDelta = delta > 0 ? delta : -delta;
262 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode);
267 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
272 #if ENABLE(DRAG_SUPPORT)
273 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
281 EventHandler::EventHandler(Frame* frame)
283 , m_mousePressed(false)
284 , m_capturesDragging(false)
285 , m_mouseDownMayStartSelect(false)
286 #if ENABLE(DRAG_SUPPORT)
287 , m_mouseDownMayStartDrag(false)
288 , m_dragMayStartSelectionInstead(false)
290 , m_mouseDownWasSingleClickInSelection(false)
291 , m_selectionInitiationState(HaveNotStartedSelection)
292 , m_panScrollInProgress(false)
293 , m_panScrollButtonPressed(false)
294 , m_springLoadedPanScrollInProgress(false)
295 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
296 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
297 , m_autoscrollRenderer(0)
298 , m_autoscrollInProgress(false)
299 , m_mouseDownMayStartAutoscroll(false)
300 , m_mouseDownWasInSubframe(false)
301 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
306 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
308 , m_mouseDownTimestamp(0)
309 , m_useLatchedWheelEventNode(false)
310 , m_widgetIsLatched(false)
312 , m_mouseDownView(nil)
313 , m_sendingEventToSubview(false)
314 , m_activationEventNumber(-1)
316 #if ENABLE(TOUCH_EVENTS)
317 , m_touchPressed(false)
319 , m_maxMouseMovedDuration(0)
320 , m_baseEventType(PlatformEvent::NoType)
324 EventHandler::~EventHandler()
326 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
329 #if ENABLE(DRAG_SUPPORT)
330 DragState& EventHandler::dragState()
332 DEFINE_STATIC_LOCAL(DragState, state, ());
335 #endif // ENABLE(DRAG_SUPPORT)
337 void EventHandler::clear()
340 m_fakeMouseMoveEventTimer.stop();
342 m_nodeUnderMouse = 0;
343 m_lastNodeUnderMouse = 0;
345 m_instanceUnderMouse = 0;
346 m_lastInstanceUnderMouse = 0;
348 m_lastMouseMoveEventSubframe = 0;
349 m_lastScrollbarUnderMouse = 0;
352 m_frameSetBeingResized = 0;
353 #if ENABLE(DRAG_SUPPORT)
355 m_shouldOnlyFireDragOverEvent = false;
357 m_currentMousePosition = IntPoint();
358 m_mousePressNode = 0;
359 m_mousePressed = false;
360 m_capturesDragging = false;
361 m_capturingMouseEventsNode = 0;
362 m_latchedWheelEventNode = 0;
363 m_previousWheelScrolledNode = 0;
364 #if ENABLE(TOUCH_EVENTS)
365 m_originatingTouchPointTargets.clear();
367 m_maxMouseMovedDuration = 0;
368 #if ENABLE(GESTURE_EVENTS)
369 m_baseEventType = PlatformEvent::NoType;
373 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
375 if (nodeToBeRemoved->contains(m_clickNode.get()))
379 static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
382 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
383 selection->setSelection(newSelection);
386 static inline bool dispatchSelectStart(Node* node)
388 if (!node || !node->renderer())
391 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
394 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity)
396 if (Position::nodeIsUserSelectNone(targetNode))
399 if (!dispatchSelectStart(targetNode))
402 if (newSelection.isRange())
403 m_selectionInitiationState = ExtendedSelection;
405 granularity = CharacterGranularity;
406 m_selectionInitiationState = PlacedCaret;
409 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, granularity);
414 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
416 Node* innerNode = targetNode(result);
417 VisibleSelection newSelection;
419 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
420 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
421 if (pos.isNotNull()) {
422 newSelection = VisibleSelection(pos);
423 newSelection.expandUsingGranularity(WordGranularity);
426 if (newSelection.isRange() && result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
427 newSelection.appendTrailingWhitespace();
429 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
433 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
435 if (!result.hitTestResult().isLiveLink())
436 return selectClosestWordFromMouseEvent(result);
438 Node* innerNode = targetNode(result);
440 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
441 VisibleSelection newSelection;
442 Element* URLElement = result.hitTestResult().URLElement();
443 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
444 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
445 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
447 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
451 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
453 if (event.event().button() != LeftButton)
456 if (m_frame->selection()->isRange())
457 // A double-click when range is already selected
458 // should not change the selection. So, do not call
459 // selectClosestWordFromMouseEvent, but do set
460 // m_beganSelectingText to prevent handleMouseReleaseEvent
461 // from setting caret selection.
462 m_selectionInitiationState = ExtendedSelection;
464 selectClosestWordFromMouseEvent(event);
469 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
471 if (event.event().button() != LeftButton)
474 Node* innerNode = targetNode(event);
475 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
478 VisibleSelection newSelection;
479 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
480 if (pos.isNotNull()) {
481 newSelection = VisibleSelection(pos);
482 newSelection.expandUsingGranularity(ParagraphGranularity);
485 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity);
488 static int textDistance(const Position& start, const Position& end)
490 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
491 return TextIterator::rangeLength(range.get(), true);
494 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
496 Node* innerNode = targetNode(event);
497 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
500 // Extend the selection if the Shift key is down, unless the click is in a link.
501 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
503 // Don't restart the selection when the mouse is pressed on an
504 // existing selection so we can allow for text dragging.
505 if (FrameView* view = m_frame->view()) {
506 LayoutPoint vPoint = view->windowToContents(event.event().position());
507 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
508 m_mouseDownWasSingleClickInSelection = true;
513 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
514 if (visiblePos.isNull())
515 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
516 Position pos = visiblePos.deepEquivalent();
518 VisibleSelection newSelection = m_frame->selection()->selection();
519 TextGranularity granularity = CharacterGranularity;
521 if (extendSelection && newSelection.isCaretOrRange()) {
522 ASSERT(m_frame->settings());
523 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
524 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
525 // was created right-to-left
526 Position start = newSelection.start();
527 Position end = newSelection.end();
528 int distanceToStart = textDistance(start, pos);
529 int distanceToEnd = textDistance(pos, end);
530 if (distanceToStart <= distanceToEnd)
531 newSelection = VisibleSelection(end, pos);
533 newSelection = VisibleSelection(start, pos);
535 newSelection.setExtent(pos);
537 if (m_frame->selection()->granularity() != CharacterGranularity) {
538 granularity = m_frame->selection()->granularity();
539 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
542 newSelection = VisibleSelection(visiblePos);
544 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
547 static inline bool canMouseDownStartSelect(Node* node)
549 if (!node || !node->renderer())
552 if (!node->canStartSelection())
558 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
560 #if ENABLE(DRAG_SUPPORT)
562 dragState().m_dragSrc = 0;
565 cancelFakeMouseMoveEvent();
567 m_frame->document()->updateLayoutIgnorePendingStylesheets();
569 if (ScrollView* scrollView = m_frame->view()) {
570 if (scrollView->isPointInScrollbarCorner(event.event().position()))
574 bool singleClick = event.event().clickCount() <= 1;
576 // If we got the event back, that must mean it wasn't prevented,
577 // so it's allowed to start a drag or selection.
578 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
580 #if ENABLE(DRAG_SUPPORT)
581 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
582 m_mouseDownMayStartDrag = singleClick;
585 m_mouseDownWasSingleClickInSelection = false;
587 m_mouseDown = event.event();
589 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
593 if (m_frame->document()->isSVGDocument()
594 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
595 if (event.event().shiftKey() && singleClick) {
597 static_cast<SVGDocument*>(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
603 // We don't do this at the start of mouse down handling,
604 // because we don't want to do it until we know we didn't hit a widget.
608 Node* innerNode = targetNode(event);
610 m_mousePressNode = innerNode;
611 #if ENABLE(DRAG_SUPPORT)
612 m_dragStartPos = event.event().position();
615 bool swallowEvent = false;
616 m_mousePressed = true;
617 m_selectionInitiationState = HaveNotStartedSelection;
619 if (event.event().clickCount() == 2)
620 swallowEvent = handleMousePressEventDoubleClick(event);
621 else if (event.event().clickCount() >= 3)
622 swallowEvent = handleMousePressEventTripleClick(event);
624 swallowEvent = handleMousePressEventSingleClick(event);
626 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
627 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
632 // There are two kinds of renderer that can autoscroll.
633 static bool canAutoscroll(RenderObject* renderer)
635 if (!renderer->isBox())
638 // Check for a box that can be scrolled in its own right.
639 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
642 // Check for a box that represents the top level of a web page.
643 // This can be scrolled by calling Chrome::scrollRectIntoView.
644 // This only has an effect on the Mac platform in applications
645 // that put web views into scrolling containers, such as Mac OS X Mail.
646 // The code for this is in RenderLayer::scrollRectToVisible.
647 if (renderer->node() != renderer->document())
649 Frame* frame = renderer->frame();
652 Page* page = frame->page();
653 return page && page->mainFrame() == frame;
656 #if ENABLE(DRAG_SUPPORT)
657 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
659 if (handleDrag(event))
665 Node* targetNode = EventHandler::targetNode(event);
666 if (event.event().button() != LeftButton || !targetNode)
669 RenderObject* renderer = targetNode->renderer();
671 renderer = targetNode->parentNode() ? targetNode->parentNode()->renderer() : 0;
672 if (!renderer || !renderer->isListBox())
676 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
677 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
680 m_mouseDownMayStartDrag = false;
682 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
683 // Find a renderer that can autoscroll.
684 while (renderer && !canAutoscroll(renderer)) {
685 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
686 renderer = renderer->document()->ownerElement()->renderer();
688 renderer = renderer->parent();
692 m_autoscrollInProgress = true;
693 handleAutoscroll(renderer);
696 m_mouseDownMayStartAutoscroll = false;
699 if (m_selectionInitiationState != ExtendedSelection) {
700 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
701 HitTestResult result(m_mouseDownPos);
702 m_frame->document()->renderView()->hitTest(request, result);
704 updateSelectionForMouseDrag(result);
706 updateSelectionForMouseDrag(event.hitTestResult());
710 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
712 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
713 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
714 // in handleMousePressEvent
716 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
719 if (event.button() != LeftButton || event.clickCount() != 1)
722 FrameView* view = m_frame->view();
726 Page* page = m_frame->page();
730 updateDragSourceActionsAllowed();
731 HitTestRequest request(HitTestRequest::ReadOnly);
732 HitTestResult result(view->windowToContents(event.position()));
733 m_frame->contentRenderer()->hitTest(request, result);
735 return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), roundedIntPoint(result.point()), state);
738 void EventHandler::updateSelectionForMouseDrag()
740 FrameView* view = m_frame->view();
743 RenderView* renderer = m_frame->contentRenderer();
747 HitTestRequest request(HitTestRequest::ReadOnly |
748 HitTestRequest::Active |
749 HitTestRequest::Move);
750 HitTestResult result(view->windowToContents(m_currentMousePosition));
751 renderer->hitTest(request, result);
752 updateSelectionForMouseDrag(result);
755 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
757 LayoutPoint selectionEndPoint = localPoint;
758 Element* editableElement = selection.rootEditableElement();
760 if (!targetNode->renderer())
761 return VisiblePosition();
763 if (editableElement && !editableElement->contains(targetNode)) {
764 if (!editableElement->renderer())
765 return VisiblePosition();
767 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
768 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
769 targetNode = editableElement;
772 return targetNode->renderer()->positionForPoint(selectionEndPoint);
775 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
777 if (!m_mouseDownMayStartSelect)
780 Node* target = targetNode(hitTestResult);
784 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
786 // Don't modify the selection if we're not on a node.
787 if (targetPosition.isNull())
790 // Restart the selection if this is the first mouse move. This work is usually
791 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
792 VisibleSelection newSelection = m_frame->selection()->selection();
795 // Special case to limit selection to the containing block for SVG text.
796 // FIXME: Isn't there a better non-SVG-specific way to do this?
797 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
798 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
799 if (selectionBaseRenderer->isSVGText())
800 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
804 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
807 if (m_selectionInitiationState != ExtendedSelection) {
808 // Always extend selection here because it's caused by a mouse drag
809 m_selectionInitiationState = ExtendedSelection;
810 newSelection = VisibleSelection(targetPosition);
813 newSelection.setExtent(targetPosition);
814 if (m_frame->selection()->granularity() != CharacterGranularity)
815 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
817 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection()->granularity(),
818 FrameSelection::AdjustEndpointsAtBidiBoundary);
820 #endif // ENABLE(DRAG_SUPPORT)
822 void EventHandler::lostMouseCapture()
824 m_frame->selection()->setCaretBlinkingSuspended(false);
827 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
829 if (eventLoopHandleMouseUp(event))
832 // If this was the first click in the window, we don't even want to clear the selection.
833 // This case occurs when the user clicks on a draggable element, since we have to process
834 // the mouse down and drag events to see if we might start a drag. For other first clicks
835 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
836 // ignored upstream of this layer.
837 return eventActivatedView(event.event());
840 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
842 if (m_autoscrollInProgress)
843 stopAutoscrollTimer();
845 if (handleMouseUp(event))
848 // Used to prevent mouseMoveEvent from initiating a drag before
849 // the mouse is pressed again.
850 m_frame->selection()->setCaretBlinkingSuspended(false);
851 m_mousePressed = false;
852 m_capturesDragging = false;
853 #if ENABLE(DRAG_SUPPORT)
854 m_mouseDownMayStartDrag = false;
856 m_mouseDownMayStartSelect = false;
857 m_mouseDownMayStartAutoscroll = false;
858 m_mouseDownWasInSubframe = false;
860 bool handled = false;
862 // Clear the selection if the mouse didn't move after the last mouse
863 // press and it's not a context menu click. We do this so when clicking
864 // on the selection, the selection goes away. However, if we are
865 // editing, place the caret.
866 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
867 #if ENABLE(DRAG_SUPPORT)
868 && m_dragStartPos == event.event().position()
870 && m_frame->selection()->isRange()
871 && event.event().button() != RightButton) {
872 VisibleSelection newSelection;
873 Node* node = targetNode(event);
874 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
875 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
876 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
877 newSelection = VisibleSelection(pos);
880 setSelectionIfNeeded(m_frame->selection(), newSelection);
885 m_frame->selection()->notifyRendererOfSelectionChange(UserTriggered);
887 m_frame->selection()->selectFrameElementInParentIfFullySelected();
892 void EventHandler::handleAutoscroll(RenderObject* renderer)
894 // We don't want to trigger the autoscroll or the panScroll if it's already active
895 if (m_autoscrollTimer.isActive())
898 setAutoscrollRenderer(renderer);
900 #if ENABLE(PAN_SCROLLING)
901 if (m_panScrollInProgress) {
902 m_panScrollStartPos = currentMousePosition();
903 if (FrameView* view = m_frame->view())
904 view->addPanScrollIcon(m_panScrollStartPos);
905 // If we're not in the top frame we notify it that we doing a panScroll.
906 if (Page* page = m_frame->page()) {
907 Frame* mainFrame = page->mainFrame();
908 if (m_frame != mainFrame)
909 mainFrame->eventHandler()->m_panScrollInProgress = true;
914 startAutoscrollTimer();
917 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
919 RenderObject* r = autoscrollRenderer();
920 if (!r || !r->isBox()) {
921 stopAutoscrollTimer();
925 if (m_autoscrollInProgress) {
926 if (!m_mousePressed) {
927 stopAutoscrollTimer();
930 toRenderBox(r)->autoscroll();
932 // we verify that the main frame hasn't received the order to stop the panScroll
933 if (Page* page = m_frame->page()) {
934 if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) {
935 stopAutoscrollTimer();
939 #if ENABLE(PAN_SCROLLING)
940 updatePanScrollState();
941 toRenderBox(r)->panScroll(m_panScrollStartPos);
946 #if ENABLE(PAN_SCROLLING)
948 void EventHandler::startPanScrolling(RenderObject* renderer)
950 m_panScrollInProgress = true;
951 m_panScrollButtonPressed = true;
952 handleAutoscroll(renderer);
956 void EventHandler::updatePanScrollState()
958 FrameView* view = m_frame->view();
962 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
963 // So we don't want to change the cursor over this area
964 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
965 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
966 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
967 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
969 if ((east || west || north || south) && m_panScrollButtonPressed)
970 m_springLoadedPanScrollInProgress = true;
974 view->setCursor(northEastPanningCursor());
976 view->setCursor(northWestPanningCursor());
978 view->setCursor(northPanningCursor());
981 view->setCursor(southEastPanningCursor());
983 view->setCursor(southWestPanningCursor());
985 view->setCursor(southPanningCursor());
987 view->setCursor(eastPanningCursor());
989 view->setCursor(westPanningCursor());
991 view->setCursor(middlePanningCursor());
994 #endif // ENABLE(PAN_SCROLLING)
996 RenderObject* EventHandler::autoscrollRenderer() const
998 return m_autoscrollRenderer;
1001 void EventHandler::updateAutoscrollRenderer()
1003 if (!m_autoscrollRenderer)
1006 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
1008 if (Node* nodeAtPoint = hitTest.innerNode())
1009 m_autoscrollRenderer = nodeAtPoint->renderer();
1011 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
1012 m_autoscrollRenderer = m_autoscrollRenderer->parent();
1015 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
1017 m_autoscrollRenderer = renderer;
1020 #if ENABLE(DRAG_SUPPORT)
1021 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1024 return DragSourceActionNone;
1026 Page* page = m_frame->page();
1028 return DragSourceActionNone;
1030 FrameView* view = m_frame->view();
1032 return DragSourceActionNone;
1034 return page->dragController()->delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1036 #endif // ENABLE(DRAG_SUPPORT)
1038 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1040 enum ShadowContentFilterPolicy shadowContentFilterPolicy = allowShadowContent ? AllowShadowContent : DoNotAllowShadowContent;
1041 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1043 if (!m_frame->contentRenderer())
1046 hitType |= HitTestRequest::IgnoreClipping;
1047 m_frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
1050 Node* n = result.innerNode();
1051 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
1053 RenderWidget* renderWidget = toRenderWidget(n->renderer());
1054 Widget* widget = renderWidget->widget();
1055 if (!widget || !widget->isFrameView())
1057 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
1058 if (!frame || !frame->contentRenderer())
1060 FrameView* view = static_cast<FrameView*>(widget);
1061 LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
1062 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
1063 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1064 frame->contentRenderer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
1065 result = widgetHitTestResult;
1067 if (testScrollbars == ShouldHitTestScrollbars) {
1068 Scrollbar* eventScrollbar = view->scrollbarAtPoint(roundedIntPoint(point));
1070 result.setScrollbar(eventScrollbar);
1074 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
1075 // Another hit test at the main frame level should get us the correct visible result.
1076 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
1077 if (Page* page = m_frame->page()) {
1078 Frame* mainFrame = page->mainFrame();
1079 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
1080 FrameView* resultView = resultFrame->view();
1081 FrameView* mainView = mainFrame->view();
1082 if (resultView && mainView) {
1083 IntPoint mainFramePoint = mainView->rootViewToContents(resultView->contentsToRootView(roundedIntPoint(result.point())));
1084 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
1089 if (!allowShadowContent)
1090 result.setToNonShadowAncestor();
1096 void EventHandler::startAutoscrollTimer()
1098 m_autoscrollTimer.startRepeating(autoscrollInterval);
1101 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1103 if (m_autoscrollInProgress) {
1104 if (m_mouseDownWasInSubframe) {
1105 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
1106 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
1111 if (autoscrollRenderer()) {
1112 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
1113 toRenderBox(autoscrollRenderer())->stopAutoscroll();
1114 #if ENABLE(PAN_SCROLLING)
1115 if (m_panScrollInProgress) {
1116 if (FrameView* view = m_frame->view()) {
1117 view->removePanScrollIcon();
1118 view->setCursor(pointerCursor());
1123 setAutoscrollRenderer(0);
1126 m_autoscrollTimer.stop();
1128 m_panScrollInProgress = false;
1129 m_springLoadedPanScrollInProgress = false;
1131 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1132 if (Page* page = m_frame->page()) {
1133 Frame* mainFrame = page->mainFrame();
1134 if (m_frame != mainFrame)
1135 mainFrame->eventHandler()->m_panScrollInProgress = false;
1138 m_autoscrollInProgress = false;
1141 Node* EventHandler::mousePressNode() const
1143 return m_mousePressNode.get();
1146 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1148 m_mousePressNode = node;
1151 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1153 Node* node = startingNode;
1156 node = m_frame->document()->focusedNode();
1159 node = m_mousePressNode.get();
1162 RenderObject* r = node->renderer();
1163 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1164 setFrameWasScrolledByUser();
1172 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1174 Node* node = startingNode;
1177 node = m_frame->document()->focusedNode();
1180 node = m_mousePressNode.get();
1183 RenderObject* r = node->renderer();
1184 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1185 setFrameWasScrolledByUser();
1193 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1195 // The layout needs to be up to date to determine if we can scroll. We may be
1196 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1197 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1198 if (scrollOverflow(direction, granularity, startingNode))
1200 Frame* frame = m_frame;
1201 FrameView* view = frame->view();
1202 if (view && view->scroll(direction, granularity))
1204 frame = frame->tree()->parent();
1207 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1210 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1212 // The layout needs to be up to date to determine if we can scroll. We may be
1213 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1214 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1215 if (logicalScrollOverflow(direction, granularity, startingNode))
1217 Frame* frame = m_frame;
1218 FrameView* view = frame->view();
1220 bool scrolled = false;
1222 // Mac also resets the scroll position in the inline direction.
1223 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1226 if (view && view->logicalScroll(direction, granularity))
1232 frame = frame->tree()->parent();
1236 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1239 IntPoint EventHandler::currentMousePosition() const
1241 return m_currentMousePosition;
1244 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1246 if (!hitTestResult.isOverWidget())
1248 return subframeForTargetNode(targetNode(hitTestResult));
1251 Frame* EventHandler::subframeForTargetNode(Node* node)
1256 RenderObject* renderer = node->renderer();
1257 if (!renderer || !renderer->isWidget())
1260 Widget* widget = toRenderWidget(renderer)->widget();
1261 if (!widget || !widget->isFrameView())
1264 return static_cast<FrameView*>(widget)->frame();
1267 static bool isSubmitImage(Node* node)
1269 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1272 // Returns true if the node's editable block is not current focused for editing
1273 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1275 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1278 OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1280 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1281 return NoCursorChange;
1283 Page* page = m_frame->page();
1285 return NoCursorChange;
1286 if (page->mainFrame()->eventHandler()->m_panScrollInProgress)
1287 return NoCursorChange;
1289 Node* node = targetNode(event);
1290 RenderObject* renderer = node ? node->renderer() : 0;
1291 RenderStyle* style = renderer ? renderer->style() : 0;
1292 bool horizontalText = !style || style->isHorizontalWritingMode();
1293 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1295 // During selection, use an I-beam no matter what we're over.
1296 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1297 if (m_mousePressed && m_mouseDownMayStartSelect
1298 #if ENABLE(DRAG_SUPPORT)
1299 && !m_mouseDownMayStartDrag
1301 && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1305 Cursor overrideCursor;
1306 switch (renderer->getCursor(roundedIntPoint(event.localPoint()), overrideCursor)) {
1307 case SetCursorBasedOnStyle:
1310 return overrideCursor;
1311 case DoNotSetCursor:
1312 return NoCursorChange;
1316 if (style && style->cursors()) {
1317 const CursorList* cursors = style->cursors();
1318 for (unsigned i = 0; i < cursors->size(); ++i) {
1319 CachedImage* cimage = 0;
1320 StyleImage* image = (*cursors)[i].image();
1321 if (image && image->isCachedImage())
1322 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1325 IntPoint hotSpot = (*cursors)[i].hotSpot();
1326 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1327 IntSize size = cimage->imageForRenderer(renderer)->size();
1328 if (size.width() > 128 || size.height() > 128)
1330 if (!cimage->errorOccurred())
1331 return Cursor(cimage->imageForRenderer(renderer), hotSpot);
1335 switch (style ? style->cursor() : CURSOR_AUTO) {
1337 bool editable = (node && node->rendererIsEditable());
1338 bool editableLinkEnabled = false;
1340 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1342 ASSERT(m_frame->settings());
1343 switch (m_frame->settings()->editableLinkBehavior()) {
1345 case EditableLinkDefaultBehavior:
1346 case EditableLinkAlwaysLive:
1347 editableLinkEnabled = true;
1350 case EditableLinkNeverLive:
1351 editableLinkEnabled = false;
1354 case EditableLinkLiveWhenNotFocused:
1355 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1358 case EditableLinkOnlyLiveWithShiftKey:
1359 editableLinkEnabled = event.event().shiftKey();
1364 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1365 return handCursor();
1366 bool inResizer = false;
1368 if (RenderLayer* layer = renderer->enclosingLayer()) {
1369 if (FrameView* view = m_frame->view())
1370 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().position()));
1373 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1375 return pointerCursor();
1378 return crossCursor();
1379 case CURSOR_POINTER:
1380 return handCursor();
1382 return moveCursor();
1383 case CURSOR_ALL_SCROLL:
1384 return moveCursor();
1385 case CURSOR_E_RESIZE:
1386 return eastResizeCursor();
1387 case CURSOR_W_RESIZE:
1388 return westResizeCursor();
1389 case CURSOR_N_RESIZE:
1390 return northResizeCursor();
1391 case CURSOR_S_RESIZE:
1392 return southResizeCursor();
1393 case CURSOR_NE_RESIZE:
1394 return northEastResizeCursor();
1395 case CURSOR_SW_RESIZE:
1396 return southWestResizeCursor();
1397 case CURSOR_NW_RESIZE:
1398 return northWestResizeCursor();
1399 case CURSOR_SE_RESIZE:
1400 return southEastResizeCursor();
1401 case CURSOR_NS_RESIZE:
1402 return northSouthResizeCursor();
1403 case CURSOR_EW_RESIZE:
1404 return eastWestResizeCursor();
1405 case CURSOR_NESW_RESIZE:
1406 return northEastSouthWestResizeCursor();
1407 case CURSOR_NWSE_RESIZE:
1408 return northWestSouthEastResizeCursor();
1409 case CURSOR_COL_RESIZE:
1410 return columnResizeCursor();
1411 case CURSOR_ROW_RESIZE:
1412 return rowResizeCursor();
1414 return iBeamCursor();
1416 return waitCursor();
1418 return helpCursor();
1419 case CURSOR_VERTICAL_TEXT:
1420 return verticalTextCursor();
1422 return cellCursor();
1423 case CURSOR_CONTEXT_MENU:
1424 return contextMenuCursor();
1425 case CURSOR_PROGRESS:
1426 return progressCursor();
1427 case CURSOR_NO_DROP:
1428 return noDropCursor();
1430 return aliasCursor();
1432 return copyCursor();
1434 return noneCursor();
1435 case CURSOR_NOT_ALLOWED:
1436 return notAllowedCursor();
1437 case CURSOR_DEFAULT:
1438 return pointerCursor();
1439 case CURSOR_WEBKIT_ZOOM_IN:
1440 return zoomInCursor();
1441 case CURSOR_WEBKIT_ZOOM_OUT:
1442 return zoomOutCursor();
1443 case CURSOR_WEBKIT_GRAB:
1444 return grabCursor();
1445 case CURSOR_WEBKIT_GRABBING:
1446 return grabbingCursor();
1448 return pointerCursor();
1451 static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1453 FrameView* view = frame->view();
1454 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1455 // Historically the code would just crash; this is clearly no worse than that.
1456 return view ? view->windowToContents(windowPoint) : windowPoint;
1459 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1461 return targetNode(event.hitTestResult());
1464 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1466 Node* node = hitTestResult.innerNode();
1469 if (node->inDocument())
1472 Element* element = node->parentElement();
1473 if (element && element->inDocument())
1480 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1482 RefPtr<FrameView> protector(m_frame->view());
1484 #if ENABLE(TOUCH_EVENTS)
1485 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1486 if (defaultPrevented)
1490 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1492 // FIXME (bug 68185): this call should be made at another abstraction layer
1493 m_frame->loader()->resetMultipleFormSubmissionProtection();
1495 cancelFakeMouseMoveEvent();
1496 m_mousePressed = true;
1497 m_capturesDragging = true;
1498 m_currentMousePosition = mouseEvent.position();
1499 m_mouseDownTimestamp = mouseEvent.timestamp();
1500 #if ENABLE(DRAG_SUPPORT)
1501 m_mouseDownMayStartDrag = false;
1503 m_mouseDownMayStartSelect = false;
1504 m_mouseDownMayStartAutoscroll = false;
1505 if (FrameView* view = m_frame->view())
1506 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1511 m_mouseDownWasInSubframe = false;
1513 HitTestRequest request(HitTestRequest::Active);
1514 // Save the document point we generate in case the window coordinate is invalidated by what happens
1515 // when we dispatch the event.
1516 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1517 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1519 if (!targetNode(mev)) {
1524 m_mousePressNode = targetNode(mev);
1526 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1531 Frame* subframe = subframeForHitTestResult(mev);
1532 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1533 // Start capturing future events for this frame. We only do this if we didn't clear
1534 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1535 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1536 if (m_mousePressed && m_capturesDragging) {
1537 m_capturingMouseEventsNode = targetNode(mev);
1538 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1544 #if ENABLE(PAN_SCROLLING)
1545 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1546 // because it will set m_panScrollInProgress to false on return.
1547 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress;
1548 if (isPanScrollInProgress || m_autoscrollInProgress)
1549 stopAutoscrollTimer();
1550 if (isPanScrollInProgress) {
1551 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1552 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1558 m_clickCount = mouseEvent.clickCount();
1559 m_clickNode = targetNode(mev);
1561 if (FrameView* view = m_frame->view()) {
1562 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1563 IntPoint p = view->windowToContents(mouseEvent.position());
1564 if (layer && layer->isPointInResizeControl(p)) {
1565 layer->setInResizeMode(true);
1566 m_resizeLayer = layer;
1567 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1573 m_frame->selection()->setCaretBlinkingSuspended(true);
1575 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1576 m_capturesDragging = !swallowEvent || mev.scrollbar();
1578 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1579 // in case the scrollbar widget was destroyed when the mouse event was handled.
1580 if (mev.scrollbar()) {
1581 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1582 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1583 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1584 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1585 m_lastScrollbarUnderMouse = 0;
1589 // scrollbars should get events anyway, even disabled controls might be scrollable
1590 Scrollbar* scrollbar = mev.scrollbar();
1592 updateLastScrollbarUnderMouse(scrollbar, true);
1595 passMousePressEventToScrollbar(mev, scrollbar);
1597 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1598 // If a mouse event handler changes the input element type to one that has a widget associated,
1599 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1600 // event target node can't still be the shadow node.
1601 if (targetNode(mev)->isShadowRoot() && targetNode(mev)->shadowHost()->hasTagName(inputTag)) {
1602 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1603 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1606 FrameView* view = m_frame->view();
1607 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1609 scrollbar = mev.scrollbar();
1611 updateLastScrollbarUnderMouse(scrollbar, true);
1613 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1614 swallowEvent = true;
1616 swallowEvent = handleMousePressEvent(mev);
1619 return swallowEvent;
1622 // This method only exists for platforms that don't know how to deliver
1623 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1625 RefPtr<FrameView> protector(m_frame->view());
1627 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1629 // We get this instead of a second mouse-up
1630 m_mousePressed = false;
1631 m_currentMousePosition = mouseEvent.position();
1633 HitTestRequest request(HitTestRequest::Active);
1634 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1635 Frame* subframe = subframeForHitTestResult(mev);
1636 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1637 m_capturingMouseEventsNode = 0;
1638 if (subframe && passMousePressEventToSubframe(mev, subframe))
1641 m_clickCount = mouseEvent.clickCount();
1642 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1644 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1646 if (m_lastScrollbarUnderMouse)
1647 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1649 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1653 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1656 static RenderLayer* layerForNode(Node* node)
1661 RenderObject* renderer = node->renderer();
1665 RenderLayer* layer = renderer->enclosingLayer();
1672 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1674 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1675 RefPtr<FrameView> protector(m_frame->view());
1678 #if ENABLE(TOUCH_EVENTS)
1679 // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events.
1680 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event);
1681 if (defaultPrevented)
1685 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1686 bool result = handleMouseMoveEvent(event, &hoveredNode);
1688 Page* page = m_frame->page();
1692 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1693 if (FrameView* frameView = m_frame->view()) {
1694 if (frameView->containsScrollableArea(layer))
1695 layer->mouseMovedInContentArea();
1699 if (FrameView* frameView = m_frame->view())
1700 frameView->mouseMovedInContentArea();
1702 hoveredNode.setToNonShadowAncestor();
1703 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1704 page->chrome()->setToolTip(hoveredNode);
1708 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1710 HitTestResult hoveredNode;
1711 return handleMouseMoveEvent(event, &hoveredNode, true);
1714 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1716 // in Radar 3703768 we saw frequent crashes apparently due to the
1717 // part being null here, which seems impossible, so check for nil
1718 // but also assert so that we can try to figure this out in debug
1719 // builds, if it happens.
1724 RefPtr<FrameView> protector(m_frame->view());
1725 m_currentMousePosition = mouseEvent.position();
1727 if (m_hoverTimer.isActive())
1728 m_hoverTimer.stop();
1730 cancelFakeMouseMoveEvent();
1734 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1739 if (m_frameSetBeingResized)
1740 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1742 // Send events right to a scrollbar if the mouse is pressed.
1743 if (m_lastScrollbarUnderMouse && m_mousePressed)
1744 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1746 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move;
1748 hitType |= HitTestRequest::Active;
1750 #if ENABLE(TOUCH_EVENTS)
1751 // Treat any mouse move events as readonly if the user is currently touching the screen.
1753 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1755 HitTestRequest request(hitType);
1756 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1758 *hoveredNode = mev.hitTestResult();
1760 Scrollbar* scrollbar = 0;
1762 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1763 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1765 if (FrameView* view = m_frame->view())
1766 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1769 scrollbar = mev.scrollbar();
1771 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1772 if (onlyUpdateScrollbars)
1776 bool swallowEvent = false;
1777 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1779 // 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.
1780 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1781 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1784 // Update over/out state before passing the event to the subframe.
1785 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1787 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1788 // node to be detached from its FrameView, in which case the event should not be passed.
1789 if (newSubframe->view())
1790 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1792 if (scrollbar && !m_mousePressed)
1793 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1794 if (FrameView* view = m_frame->view()) {
1795 OptionalCursor optionalCursor = selectCursor(mev, scrollbar);
1796 if (optionalCursor.isCursorChange())
1797 view->setCursor(optionalCursor.cursor());
1801 m_lastMouseMoveEventSubframe = newSubframe;
1806 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1807 #if ENABLE(DRAG_SUPPORT)
1809 swallowEvent = handleMouseDraggedEvent(mev);
1810 #endif // ENABLE(DRAG_SUPPORT)
1812 return swallowEvent;
1815 void EventHandler::invalidateClick()
1821 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1823 RefPtr<FrameView> protector(m_frame->view());
1825 #if ENABLE(TOUCH_EVENTS)
1826 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1827 if (defaultPrevented)
1831 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1833 #if ENABLE(PAN_SCROLLING)
1834 if (mouseEvent.button() == MiddleButton)
1835 m_panScrollButtonPressed = false;
1836 if (m_springLoadedPanScrollInProgress)
1837 stopAutoscrollTimer();
1840 m_mousePressed = false;
1841 m_currentMousePosition = mouseEvent.position();
1846 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1851 if (m_frameSetBeingResized)
1852 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1854 if (m_lastScrollbarUnderMouse) {
1856 return m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1859 HitTestRequest request(HitTestRequest::Release);
1860 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1861 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1862 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1863 m_capturingMouseEventsNode = 0;
1864 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1867 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1869 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1871 if (m_resizeLayer) {
1872 m_resizeLayer->setInResizeMode(false);
1876 bool swallowMouseReleaseEvent = false;
1877 if (!swallowMouseUpEvent)
1878 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1882 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1885 #if ENABLE(DRAG_SUPPORT)
1886 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1888 FrameView* view = m_frame->view();
1890 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1894 view->resetDeferredRepaintDelay();
1895 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1896 true, true, m_frame->document()->defaultView(),
1897 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1898 #if ENABLE(POINTER_LOCK)
1899 event.movementDelta().x(), event.movementDelta().y(),
1901 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1905 dragTarget->dispatchEvent(me.get(), ec);
1906 return me->defaultPrevented();
1909 static bool targetIsFrame(Node* target, Frame*& frame)
1914 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
1917 frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
1922 static bool findDropZone(Node* target, Clipboard* clipboard)
1924 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1925 for (; element; element = element->parentElement()) {
1926 bool matched = false;
1927 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1929 if (dropZoneStr.isEmpty())
1932 dropZoneStr.makeLower();
1934 SpaceSplitString keywords(dropZoneStr, false);
1935 if (keywords.isNull())
1938 DragOperation dragOperation = DragOperationNone;
1939 for (unsigned int i = 0; i < keywords.size(); i++) {
1940 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1941 if (op != DragOperationNone) {
1942 if (dragOperation == DragOperationNone)
1945 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1947 if (matched && dragOperation != DragOperationNone)
1951 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1958 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1960 bool accept = false;
1962 if (!m_frame->view())
1965 HitTestRequest request(HitTestRequest::ReadOnly);
1966 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1968 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1969 RefPtr<Node> newTarget = targetNode(mev);
1970 if (newTarget && newTarget->isTextNode())
1971 newTarget = newTarget->parentNode();
1973 newTarget = newTarget->shadowAncestorNode();
1975 if (m_dragTarget != newTarget) {
1976 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1977 // it is sometimes incorrect when dragging within subframes, as seen with
1978 // LayoutTests/fast/events/drag-in-frames.html.
1980 // 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>.
1982 if (targetIsFrame(newTarget.get(), targetFrame)) {
1984 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
1985 } else if (newTarget) {
1986 // 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.
1987 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
1988 // for now we don't care if event handler cancels default behavior, since there is none
1989 dispatchDragSrcEvent(eventNames().dragEvent, event);
1991 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget.get(), event, clipboard);
1993 accept = findDropZone(newTarget.get(), clipboard);
1996 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1998 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
1999 } else if (m_dragTarget)
2000 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2003 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2004 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2005 m_shouldOnlyFireDragOverEvent = true;
2009 if (targetIsFrame(newTarget.get(), targetFrame)) {
2011 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2012 } else if (newTarget) {
2013 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2014 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2015 // for now we don't care if event handler cancels default behavior, since there is none
2016 dispatchDragSrcEvent(eventNames().dragEvent, event);
2018 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget.get(), event, clipboard);
2020 accept = findDropZone(newTarget.get(), clipboard);
2021 m_shouldOnlyFireDragOverEvent = false;
2024 m_dragTarget = newTarget;
2029 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2032 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2034 targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard);
2035 } else if (m_dragTarget.get()) {
2036 if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
2037 dispatchDragSrcEvent(eventNames().dragEvent, event);
2038 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2043 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2046 bool preventedDefault = false;
2047 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2049 preventedDefault = targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
2050 } else if (m_dragTarget.get())
2051 preventedDefault = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
2053 return preventedDefault;
2056 void EventHandler::clearDragState()
2059 m_capturingMouseEventsNode = 0;
2060 m_shouldOnlyFireDragOverEvent = false;
2062 m_sendingEventToSubview = false;
2065 #endif // ENABLE(DRAG_SUPPORT)
2067 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
2069 m_capturingMouseEventsNode = n;
2070 m_eventHandlerWillResetCapturingMouseEventsNode = false;
2073 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
2076 ASSERT(m_frame->document());
2078 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
2082 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
2084 if (!referenceNode || !referenceNode->isSVGElement())
2087 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
2088 if (!shadowTreeElement)
2091 Element* shadowTreeParentElement = shadowTreeElement->shadowHost();
2092 if (!shadowTreeParentElement)
2095 ASSERT(shadowTreeParentElement->hasTagName(useTag));
2096 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
2100 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
2102 Node* result = targetNode;
2104 // If we're capturing, we always go right to that node.
2105 if (m_capturingMouseEventsNode)
2106 result = m_capturingMouseEventsNode.get();
2108 // If the target node is a text node, dispatch on the parent node - rdar://4196646
2109 if (result && result->isTextNode())
2110 result = result->parentNode();
2112 m_nodeUnderMouse = result;
2114 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
2116 // <use> shadow tree elements may have been recloned, update node under mouse in any case
2117 if (m_lastInstanceUnderMouse) {
2118 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
2119 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
2121 if (lastCorrespondingElement && lastCorrespondingUseElement) {
2122 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
2124 // Locate the recloned shadow tree element for our corresponding instance
2125 HashSet<SVGElementInstance*>::iterator end = instances.end();
2126 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
2127 SVGElementInstance* instance = (*it);
2128 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
2130 if (instance == m_lastInstanceUnderMouse)
2133 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
2136 SVGElement* shadowTreeElement = instance->shadowTreeElement();
2137 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
2140 m_lastNodeUnderMouse = shadowTreeElement;
2141 m_lastInstanceUnderMouse = instance;
2148 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2149 if (fireMouseOverOut) {
2150 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
2151 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
2152 Page* page = m_frame->page();
2154 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
2155 // The mouse has moved between frames.
2156 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2157 if (FrameView* frameView = frame->view())
2158 frameView->mouseExitedContentArea();
2160 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2161 // The mouse has moved between layers.
2162 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2163 if (FrameView* frameView = frame->view()) {
2164 if (frameView->containsScrollableArea(layerForLastNode))
2165 layerForLastNode->mouseExitedContentArea();
2170 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2171 // The mouse has moved between frames.
2172 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2173 if (FrameView* frameView = frame->view())
2174 frameView->mouseEnteredContentArea();
2176 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2177 // The mouse has moved between layers.
2178 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2179 if (FrameView* frameView = frame->view()) {
2180 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2181 layerForNodeUnderMouse->mouseEnteredContentArea();
2186 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2187 m_lastNodeUnderMouse = 0;
2188 m_lastScrollbarUnderMouse = 0;
2190 m_lastInstanceUnderMouse = 0;
2194 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2195 // send mouseout event to the old node
2196 if (m_lastNodeUnderMouse)
2197 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2198 // send mouseover event to the new node
2199 if (m_nodeUnderMouse)
2200 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2202 m_lastNodeUnderMouse = m_nodeUnderMouse;
2204 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2209 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2211 if (FrameView* view = m_frame->view())
2212 view->resetDeferredRepaintDelay();
2214 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2216 bool swallowEvent = false;
2218 if (m_nodeUnderMouse)
2219 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2221 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2223 // If clicking on a frame scrollbar, do not mess up with content focus.
2224 if (FrameView* view = m_frame->view()) {
2225 if (view->scrollbarAtPoint(mouseEvent.position()))
2229 // The layout needs to be up to date to determine if an element is focusable.
2230 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2232 // Blur current focus node when a link/button is clicked; this
2233 // is expected by some sites that rely on onChange handlers running
2234 // from form fields before the button click is processed.
2235 Node* node = m_nodeUnderMouse.get();
2237 // Walk up the DOM tree to search for a node to focus.
2239 if (node->isMouseFocusable()) {
2240 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2241 // node on mouse down if it's selected and inside a focused node. It will be
2242 // focused if the user does a mouseup over it, however, because the mouseup
2243 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2244 ExceptionCode ec = 0;
2245 Node* n = node->isShadowRoot() ? node->shadowHost() : node;
2246 if (m_frame->selection()->isRange()
2247 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2248 && n->isDescendantOf(m_frame->document()->focusedNode()))
2253 node = node->parentOrHostNode();
2256 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2257 // if the page already set it (e.g., by canceling default behavior).
2258 if (Page* page = m_frame->page()) {
2259 if (node && node->isMouseFocusable()) {
2260 if (!page->focusController()->setFocusedNode(node, m_frame))
2261 swallowEvent = true;
2262 } else if (!node || !node->focused()) {
2263 if (!page->focusController()->setFocusedNode(0, m_frame))
2264 swallowEvent = true;
2269 return swallowEvent;
2272 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
2273 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const
2279 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2281 Document* doc = m_frame->document();
2283 RenderObject* docRenderer = doc->renderer();
2287 RefPtr<FrameView> protector(m_frame->view());
2289 FrameView* view = m_frame->view();
2292 setFrameWasScrolledByUser();
2293 LayoutPoint vPoint = view->windowToContents(e.position());
2298 HitTestRequest request(HitTestRequest::ReadOnly);
2299 HitTestResult result(vPoint);
2300 doc->renderView()->hitTest(request, result);
2303 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2306 if (m_useLatchedWheelEventNode) {
2307 if (!m_latchedWheelEventNode) {
2308 m_latchedWheelEventNode = result.innerNode();
2309 m_widgetIsLatched = result.isOverWidget();
2312 node = m_latchedWheelEventNode.get();
2313 isOverWidget = m_widgetIsLatched;
2315 if (m_latchedWheelEventNode)
2316 m_latchedWheelEventNode = 0;
2317 if (m_previousWheelScrolledNode)
2318 m_previousWheelScrolledNode = 0;
2320 node = result.innerNode();
2321 isOverWidget = result.isOverWidget();
2324 // FIXME: It should not be necessary to do this mutation here.
2325 // Instead, the handlers should know convert vertical scrolls
2327 PlatformWheelEvent event = e;
2328 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result))
2329 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2332 // Figure out which view to send the event to.
2333 RenderObject* target = node->renderer();
2335 if (isOverWidget && target && target->isWidget()) {
2336 Widget* widget = toRenderWidget(target)->widget();
2337 if (widget && passWheelEventToWidget(e, widget))
2341 node = node->shadowAncestorNode();
2342 if (node && !node->dispatchWheelEvent(event))
2347 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2348 view = m_frame->view();
2352 return view->wheelEvent(event);
2355 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2357 if (!startNode || !wheelEvent)
2360 Node* stopNode = m_previousWheelScrolledNode.get();
2361 ScrollGranularity granularity = m_baseEventType == PlatformEvent::GestureScrollEnd ? ScrollByPixelVelocity : wheelGranularityToScrollGranularity(wheelEvent->granularity());
2363 // Break up into two scrolls if we need to. Diagonal movement on
2364 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2365 if (scrollNode(wheelEvent->rawDeltaX(), granularity, ScrollLeft, ScrollRight, startNode, &stopNode))
2366 wheelEvent->setDefaultHandled();
2368 if (scrollNode(wheelEvent->rawDeltaY(), granularity, ScrollUp, ScrollDown, startNode, &stopNode))
2369 wheelEvent->setDefaultHandled();
2371 if (!m_useLatchedWheelEventNode)
2372 m_previousWheelScrolledNode = stopNode;
2375 #if ENABLE(GESTURE_EVENTS)
2376 bool EventHandler::handleGestureTapDown()
2378 FrameView* view = m_frame->view();
2381 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2382 scrollAnimator->cancelAnimations();
2383 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2386 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2387 ScrollableArea* sa = *it;
2388 ScrollAnimator* animator = sa->scrollAnimator();
2390 animator->cancelAnimations();
2395 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2397 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2398 // eliminate the need for this.
2399 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2401 switch (gestureEvent.type()) {
2402 case PlatformEvent::GestureScrollBegin:
2403 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, false);
2404 case PlatformEvent::GestureScrollEnd:
2405 return handleGestureScrollCore(gestureEvent, ScrollByPixelVelocityWheelEvent, true);
2406 case PlatformEvent::GestureScrollUpdate:
2407 return handleGestureScrollUpdate(gestureEvent);
2408 case PlatformEvent::GestureTap:
2409 return handleGestureTap(gestureEvent);
2410 case PlatformEvent::GestureTapDown:
2411 return handleGestureTapDown();
2412 case PlatformEvent::GestureDoubleTap:
2413 case PlatformEvent::GestureLongPress:
2414 case PlatformEvent::GesturePinchBegin:
2415 case PlatformEvent::GesturePinchEnd:
2416 case PlatformEvent::GesturePinchUpdate:
2419 ASSERT_NOT_REACHED();
2425 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent)
2427 // FIXME: Refactor this code to not hit test multiple times.
2428 IntPoint adjustedPoint = gestureEvent.position();
2429 #if ENABLE(TOUCH_ADJUSTMENT)
2430 if (!gestureEvent.area().isEmpty()) {
2431 Node* targetNode = 0;
2432 // For now we use the adjusted position to ensure the later redundant hit-tests hits the right node.
2433 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2438 bool defaultPrevented = false;
2439 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2440 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2441 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2442 mouseMoved(fakeMouseMove);
2443 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2444 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2445 return defaultPrevented;
2448 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2450 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, true);
2453 bool EventHandler::handleGestureScrollCore(const PlatformGestureEvent& gestureEvent, PlatformWheelEventGranularity granularity, bool latchedWheel)
2455 TemporaryChange<bool> latched(m_useLatchedWheelEventNode, latchedWheel);
2456 const float tickDivisor = (float)WheelEvent::tickMultiplier;
2457 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2458 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2459 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2460 gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor,
2462 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2463 return handleWheelEvent(syntheticWheelEvent);
2467 #if ENABLE(TOUCH_ADJUSTMENT)
2468 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2470 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2471 HitTestResult result = hitTestResultAtPoint(touchCenter, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2473 IntRect touchRect = result.rectForPoint(touchCenter);
2474 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2475 return findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2478 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2480 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2481 HitTestResult result = hitTestResultAtPoint(touchCenter, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2483 IntRect touchRect = result.rectForPoint(touchCenter);
2484 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2485 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get());
2489 #if ENABLE(CONTEXT_MENUS)
2490 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2492 Document* doc = m_frame->document();
2493 FrameView* v = m_frame->view();
2498 LayoutPoint viewportPos = v->windowToContents(event.position());
2499 HitTestRequest request(HitTestRequest::Active);
2500 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2502 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2503 && !m_frame->selection()->contains(viewportPos)
2504 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2505 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2506 // available for text selections. But only if we're above text.
2507 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2508 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2509 selectClosestWordOrLinkFromMouseEvent(mev);
2512 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2514 return swallowEvent;
2517 bool EventHandler::sendContextMenuEventForKey()
2519 FrameView* view = m_frame->view();
2523 Document* doc = m_frame->document();
2527 static const int kContextMenuMargin = 1;
2529 #if OS(WINDOWS) && !OS(WINCE)
2530 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2532 int rightAligned = 0;
2536 Node* focusedNode = doc->focusedNode();
2537 FrameSelection* selection = m_frame->selection();
2538 Position start = selection->selection().start();
2540 if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) {
2541 RefPtr<Range> selectionRange = selection->toNormalizedRange();
2542 IntRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get());
2544 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2545 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2546 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2547 location = IntPoint(x, y);
2548 } else if (focusedNode) {
2549 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2552 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2553 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2555 location = IntPoint(
2556 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2557 kContextMenuMargin);
2560 m_frame->view()->setCursor(pointerCursor());
2562 IntPoint position = view->contentsToRootView(location);
2563 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2565 Node* targetNode = doc->focusedNode();
2569 // Use the focused node as the target for hover and active.
2570 HitTestResult result(position);
2571 result.setInnerNode(targetNode);
2572 HitTestRequest request(HitTestRequest::Active);
2573 doc->renderView()->layer()->updateHoverActiveState(request, result);
2574 doc->updateStyleIfNeeded();
2576 // The contextmenu event is a mouse event even when invoked using the keyboard.
2577 // This is required for web compatibility.
2580 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2582 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2585 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2587 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2590 #endif // ENABLE(CONTEXT_MENUS)
2592 void EventHandler::scheduleHoverStateUpdate()
2594 if (!m_hoverTimer.isActive())
2595 m_hoverTimer.startOneShot(0);
2598 void EventHandler::dispatchFakeMouseMoveEventSoon()
2603 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2604 // reschedule the timer and use a longer time. This will cause the content
2605 // to receive these moves only after the user is done scrolling, reducing
2606 // pauses during the scroll.
2607 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2608 if (m_fakeMouseMoveEventTimer.isActive())
2609 m_fakeMouseMoveEventTimer.stop();
2610 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2612 if (!m_fakeMouseMoveEventTimer.isActive())
2613 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2617 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2619 FrameView* view = m_frame->view();
2623 if (!quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2626 dispatchFakeMouseMoveEventSoon();
2629 void EventHandler::cancelFakeMouseMoveEvent()
2631 m_fakeMouseMoveEventTimer.stop();
2634 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2636 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2637 ASSERT(!m_mousePressed);
2639 FrameView* view = m_frame->view();
2647 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2648 IntPoint globalPoint = view->contentsToScreen(IntRect(view->windowToContents(m_currentMousePosition), IntSize())).location();
2649 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2650 mouseMoved(fakeMouseMoveEvent);
2653 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2655 m_frameSetBeingResized = frameSet;
2658 void EventHandler::resizeLayerDestroyed()
2660 ASSERT(m_resizeLayer);
2664 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2666 m_hoverTimer.stop();
2669 ASSERT(m_frame->document());
2671 if (RenderView* renderer = m_frame->contentRenderer()) {
2672 if (FrameView* view = m_frame->view()) {
2673 HitTestRequest request(HitTestRequest::Move);
2674 HitTestResult result(view->windowToContents(m_currentMousePosition));
2675 renderer->hitTest(request, result);
2676 m_frame->document()->updateStyleIfNeeded();
2681 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2683 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2684 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2685 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2686 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2687 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2688 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2690 String key = evt.unmodifiedText();
2691 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2694 elem->accessKeyAction(false);
2699 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2705 #if ENABLE(FULLSCREEN_API)
2706 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2708 Document* document = m_frame->document();
2709 if (document->webkitFullScreenKeyboardInputAllowed())
2712 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2713 if (keyEvent.text().length() != 1)
2715 UChar character = keyEvent.text()[0];
2716 return character == ' ';
2719 int keyCode = keyEvent.windowsVirtualKeyCode();
2720 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2721 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2722 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2723 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2727 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2729 RefPtr<FrameView> protector(m_frame->view());
2731 #if ENABLE(FULLSCREEN_API)
2732 if (m_frame->document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
2736 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2737 capsLockStateMayHaveChanged();
2739 #if ENABLE(PAN_SCROLLING)
2740 if (Page* page = m_frame->page()) {
2741 if (page->mainFrame()->eventHandler()->m_panScrollInProgress) {
2742 // If a key is pressed while the panScroll is in progress then we want to stop
2743 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2744 stopAutoscrollTimer();
2746 // If we were in panscroll mode, we swallow the key event
2752 // Check for cases where we are too early for events -- possible unmatched key up
2753 // from pressing return in the location bar.
2754 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2758 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2759 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2761 if (FrameView* view = m_frame->view())
2762 view->resetDeferredRepaintDelay();
2764 // FIXME (bug 68185): this call should be made at another abstraction layer
2765 m_frame->loader()->resetMultipleFormSubmissionProtection();
2767 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2768 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2769 // with access keys. Then we dispatch keydown, but suppress its default handling.
2770 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2771 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2772 bool matchedAnAccessKey = false;
2773 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2774 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2776 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2777 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2778 return !node->dispatchKeyEvent(initialKeyEvent);
2780 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2783 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2784 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2785 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
2786 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2787 if (matchedAnAccessKey)
2788 keydown->setDefaultPrevented(true);
2789 keydown->setTarget(node);
2791 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2792 node->dispatchEvent(keydown, ec);
2793 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2794 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2795 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2798 // Run input method in advance of DOM event handling. This may result in the IM
2799 // modifying the page prior the keydown event, but this behaviour is necessary
2800 // in order to match IE:
2801 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2802 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2803 m_frame->editor()->handleInputMethodKeydown(keydown.get());
2805 bool handledByInputMethod = keydown->defaultHandled();
2807 if (handledByInputMethod) {
2808 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2809 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2810 keydown->setTarget(node);
2811 keydown->setDefaultHandled();
2814 node->dispatchEvent(keydown, ec);
2815 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2816 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2817 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2818 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2819 return keydownResult;
2821 // Focus may have changed during keydown handling, so refetch node.
2822 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2823 if (!keydownResult) {
2824 node = eventTargetNodeForDocument(m_frame->document());
2829 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2830 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
2831 if (keyPressEvent.text().isEmpty())
2832 return keydownResult;
2833 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
2834 keypress->setTarget(node);
2836 keypress->setDefaultPrevented(true);
2838 keypress->keypressCommands() = keydown->keypressCommands();
2840 node->dispatchEvent(keypress, ec);
2842 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2845 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
2847 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
2848 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
2849 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
2850 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
2852 FocusDirection retVal = FocusDirectionNone;
2854 if (keyIdentifier == Down)
2855 retVal = FocusDirectionDown;
2856 else if (keyIdentifier == Up)
2857 retVal = FocusDirectionUp;
2858 else if (keyIdentifier == Left)
2859 retVal = FocusDirectionLeft;
2860 else if (keyIdentifier == Right)
2861 retVal = FocusDirectionRight;
2866 static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardEvent* event)
2871 bool isOptioned = event->getModifierState("Alt");
2872 bool isCommanded = event->getModifierState("Meta");
2874 SelectionDirection direction = DirectionForward;
2875 TextGranularity granularity = CharacterGranularity;
2877 switch (focusDirectionForKey(event->keyIdentifier())) {
2878 case FocusDirectionNone:
2880 case FocusDirectionForward:
2881 case FocusDirectionBackward:
2882 ASSERT_NOT_REACHED();
2884 case FocusDirectionUp:
2885 direction = DirectionBackward;
2886 granularity = isCommanded ? DocumentBoundary : LineGranularity;
2888 case FocusDirectionDown:
2889 direction = DirectionForward;
2890 granularity = isCommanded ? DocumentBoundary : LineGranularity;
2892 case FocusDirectionLeft:
2893 direction = DirectionLeft;
2894 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
2896 case FocusDirectionRight:
2897 direction = DirectionRight;
2898 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
2902 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
2903 selection->modify(alternation, direction, granularity, UserTriggered);
2904 event->setDefaultHandled();
2907 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2909 if (event->type() == eventNames().keydownEvent) {
2910 m_frame->editor()->handleKeyboardEvent(event);
2911 if (event->defaultHandled())
2913 if (event->keyIdentifier() == "U+0009")
2914 defaultTabEventHandler(event);
2915 else if (event->keyIdentifier() == "U+0008")
2916 defaultBackspaceEventHandler(event);
2918 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
2919 if (direction != FocusDirectionNone)
2920 defaultArrowEventHandler(direction, event);
2923 // provides KB navigation and selection for enhanced accessibility users
2924 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2925 handleKeyboardSelectionMovement(m_frame->selection(), event);
2927 if (event->type() == eventNames().keypressEvent) {
2928 m_frame->editor()->handleKeyboardEvent(event);
2929 if (event->defaultHandled())
2931 if (event->charCode() == ' ')
2932 defaultSpaceEventHandler(event);
2936 #if ENABLE(DRAG_SUPPORT)
2937 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
2939 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
2940 return dragHysteresisExceeded(dragViewportLocation);
2943 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
2945 FrameView* view = m_frame->view();
2948 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
2949 IntSize delta = dragLocation - m_mouseDownPos;
2951 int threshold = GeneralDragHysteresis;
2952 switch (dragState().m_dragType) {
2953 case DragSourceActionSelection:
2954 threshold = TextDragHysteresis;
2956 case DragSourceActionImage:
2957 threshold = ImageDragHysteresis;
2959 case DragSourceActionLink:
2960 threshold = LinkDragHysteresis;
2962 case DragSourceActionDHTML:
2964 case DragSourceActionNone:
2965 case DragSourceActionAny:
2966 ASSERT_NOT_REACHED();
2969 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
2972 void EventHandler::freeClipboard()
2974 if (dragState().m_dragClipboard)
2975 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
2978 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
2980 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
2981 HitTestRequest request(HitTestRequest::Release);
2982 prepareMouseEvent(request, event);
2984 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2985 dragState().m_dragClipboard->setDestinationOperation(operation);
2986 // for now we don't care if event handler cancels default behavior, since there is none
2987 dispatchDragSrcEvent(eventNames().dragendEvent, event);
2990 dragState().m_dragSrc = 0;
2991 // In case the drag was ended due to an escape key press we need to ensure
2992 // that consecutive mousemove events don't reinitiate the drag and drop.
2993 m_mouseDownMayStartDrag = false;
2996 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
2998 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
2999 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3000 dragState().m_dragSrc = rootEditableElement;
3003 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3004 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3006 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3009 static bool ExactlyOneBitSet(DragSourceAction n)
3011 return n && !(n & (n - 1));
3014 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
3016 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3017 // If we allowed the other side of the bridge to handle a drag
3018 // last time, then m_mousePressed might still be set. So we
3019 // clear it now to make sure the next move after a drag
3020 // doesn't look like a drag.
3021 m_mousePressed = false;
3025 if (eventLoopHandleMouseDragged(event))
3028 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3030 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
3031 dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents;
3033 // try to find an element that wants to be dragged
3034 HitTestRequest request(HitTestRequest::ReadOnly);
3035 HitTestResult result(m_mouseDownPos);
3036 m_frame->contentRenderer()->hitTest(request, result);
3037 Node* node = result.innerNode();
3038 if (node && m_frame->page())
3039 dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState());
3041 dragState().m_dragSrc = 0;
3043 if (!dragState().m_dragSrc)
3044 m_mouseDownMayStartDrag = false; // no element is draggable
3046 m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection);
3049 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3050 // or else we bail on the dragging stuff and allow selection to occur
3051 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3052 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3053 if ((dragState().m_dragType & DragSourceActionImage)) {
3054 // ... unless the mouse is over an image, then we start dragging just the image
3055 dragState().m_dragType = DragSourceActionImage;
3056 } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) {
3057 // ... but only bail if we're not over an unselectable element.
3058 m_mouseDownMayStartDrag = false;
3059 dragState().m_dragSrc = 0;
3060 // ... but if this was the first click in the window, we don't even want to start selection
3061 if (eventActivatedView(event.event()))
3062 m_mouseDownMayStartSelect = false;
3064 // Prevent the following case from occuring:
3065 // 1. User starts a drag immediately after mouse down over an unselectable element.
3066 // 2. We enter this block and decided that since we're over an unselectable element,
3067 // don't cancel the drag.
3068 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't
3069 // exceeded the drag hysteresis yet.
3070 // 4. We enter this block again, and since it's now marked as a selection drag, we
3072 m_dragMayStartSelectionInstead = false;
3076 if (!m_mouseDownMayStartDrag)
3077 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3079 if (!ExactlyOneBitSet(dragState().m_dragType)) {
3080 ASSERT((dragState().m_dragType & DragSourceActionSelection));
3081 ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML
3082 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage
3083 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink);
3084 dragState().m_dragType = DragSourceActionSelection;
3087 // We are starting a text/image/url drag, so the cursor should be an arrow
3088 if (FrameView* view = m_frame->view()) {
3089 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3090 view->setCursor(pointerCursor());
3093 if (!dragHysteresisExceeded(event.event().position()))
3096 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3099 DragOperation srcOp = DragOperationNone;
3101 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3102 // to make sure it gets numbified
3103 dragState().m_dragClipboard = createDraggingClipboard();
3105 if (dragState().shouldDispatchEvents()) {
3106 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
3108 if (dragState().m_dragType == DragSourceActionDHTML) {
3109 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3110 // FIXME: This doesn't work correctly with transforms.
3111 FloatPoint absPos = renderer->localToAbsolute();
3112 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3113 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
3115 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3116 // the element in some way. In this case we just kill the drag.
3117 m_mouseDownMayStartDrag = false;
3122 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3123 && !m_frame->selection()->isInPasswordField();
3125 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3126 // image can still be changed as we drag, but not the pasteboard data.
3127 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3129 if (m_mouseDownMayStartDrag) {
3130 // gather values from DHTML element, if it set any
3131 srcOp = dragState().m_dragClipboard->sourceOperation();
3133 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3134 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3135 // started the drag when that happens. So we have to assume it's started before we
3137 dragState().m_dragClipboard->setDragHasStarted();
3141 if (m_mouseDownMayStartDrag) {
3142 Page* page = m_frame->page();
3143 DragController* dragController = page ? page->dragController() : 0;
3144 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3145 if (!startedDrag && dragState().shouldDispatchEvents()) {
3146 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3147 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3148 m_mouseDownMayStartDrag = false;
3153 if (!m_mouseDownMayStartDrag) {
3154 // something failed to start the drag, cleanup
3156 dragState().m_dragSrc = 0;
3159 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3162 #endif // ENABLE(DRAG_SUPPORT)
3164 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3166 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3167 // and avoid dispatching text input events from keydown default handlers.
3168 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
3173 EventTarget* target;
3174 if (underlyingEvent)
3175 target = underlyingEvent->target();
3177 target = eventTargetNodeForDocument(m_frame->document());
3181 if (FrameView* view = m_frame->view())
3182 view->resetDeferredRepaintDelay();
3184 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3185 event->setUnderlyingEvent(underlyingEvent);
3188 target->dispatchEvent(event, ec);
3189 return event->defaultHandled();
3192 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3195 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3197 && event->keyIdentifier() == "U+0009";
3200 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3202 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(EFL)
3203 return EventHandler::isKeyboardOptionTab(event);
3209 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3211 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3213 Page* page = m_frame->page();
3217 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
3218 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3221 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3223 if (m_frame->editor()->handleTextEvent(event))
3224 event->setDefaultHandled();
3228 // Qt handles the space event in platform-specific WebKit code.
3229 // Eventually it would be good to eliminate that and use the code here instead.
3230 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
3235 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3237 ASSERT(event->type() == eventNames().keypressEvent);
3239 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3242 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3243 if (logicalScrollOverflow(direction, ScrollByPage)) {
3244 event->setDefaultHandled();
3248 FrameView* view = m_frame->view();
3252 if (view->logicalScroll(direction, ScrollByPage))
3253 event->setDefaultHandled();
3258 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3260 ASSERT(event->type() == eventNames().keydownEvent);
3262 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3265 if (!m_frame->editor()->behavior().shouldNavigateBackOnBackspace())
3268 Page* page = m_frame->page();
3272 if (!m_frame->settings()->backspaceKeyNavigationEnabled())
3275 bool handledEvent = false;
3277 if (event->shiftKey())
3278 handledEvent = page->goForward();
3280 handledEvent = page->goBack();
3283 event->setDefaultHandled();
3287 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3289 ASSERT(event->type() == eventNames().keydownEvent);
3291 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3294 Page* page = m_frame->page();
3298 if (!isSpatialNavigationEnabled(m_frame))
3301 // Arrows and other possible directional navigation keys can be used in design
3303 if (m_frame->document()->inDesignMode())
3306 if (page->focusController()->advanceFocus(focusDirection, event))
3307 event->setDefaultHandled();
3310 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3312 ASSERT(event->type() == eventNames().keydownEvent);
3314 // We should only advance focus on tabs if no special modifier keys are held down.
3315 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3318 Page* page = m_frame->page();
3321 if (!page->tabKeyCyclesThroughElements())
3324 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3326 // Tabs can be used in design mode editing.
3327 if (m_frame->document()->inDesignMode())
3330 if (page->focusController()->advanceFocus(focusDirection, event))
3331 event->setDefaultHandled();
3334 void EventHandler::capsLockStateMayHaveChanged()
3336 Document* d = m_frame->document();
3337 if (Node* node = d->focusedNode()) {
3338 if (RenderObject* r = node->renderer()) {
3339 if (r->isTextField())
3340 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3345 void EventHandler::sendResizeEvent()
3347 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
3350 void EventHandler::sendScrollEvent()
3352 setFrameWasScrolledByUser();
3353 if (m_frame->view() && m_frame->document())
3354 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), DocumentEventQueue::ScrollEventDocumentTarget);
3357 void EventHandler::setFrameWasScrolledByUser()
3359 FrameView* v = m_frame->view();
3361 v->setWasScrolledByUser(true);
3364 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3366 if (!scrollbar || !scrollbar->enabled())
3368 setFrameWasScrolledByUser();
3369 return scrollbar->mouseDown(mev.event());
3372 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3373 // last to scrollbar if setLast is true; else set last to 0.
3374 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3376 if (m_lastScrollbarUnderMouse != scrollbar) {
3377 // Send mouse exited to the old scrollbar.
3378 if (m_lastScrollbarUnderMouse)
3379 m_lastScrollbarUnderMouse->mouseExited();
3381 // Send mouse entered if we're setting a new scrollbar.
3382 if (scrollbar && setLast)
3383 scrollbar->mouseEntered();
3385 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3389 #if ENABLE(TOUCH_EVENTS)
3391 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3394 case PlatformTouchPoint::TouchReleased:
3395 return eventNames().touchendEvent;
3396 case PlatformTouchPoint::TouchCancelled:
3397 return eventNames().touchcancelEvent;
3398 case PlatformTouchPoint::TouchPressed:
3399 return eventNames().touchstartEvent;
3400 case PlatformTouchPoint::TouchMoved:
3401 return eventNames().touchmoveEvent;
3402 case PlatformTouchPoint::TouchStationary:
3403 // TouchStationary state is not converted to touch events, so fall through to assert.
3405 ASSERT_NOT_REACHED();
3410 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3412 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3413 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3414 // for an overview of how these lists fit together.
3416 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3417 RefPtr<TouchList> touches = TouchList::create();
3419 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3420 // 'targetTouches' list in the JS event.
3421 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3422 TargetTouchesMap touchesByTarget;
3424 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3425 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3427 // The touches corresponding to the particular change state this struct instance represents.
3428 RefPtr<TouchList> m_touches;
3429 // Set of targets involved in m_touches.
3430 EventTargetSet m_targets;
3431 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3433 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3435 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3437 for (unsigned i = 0; i < points.size(); ++i) {
3438 const PlatformTouchPoint& point = points[i];
3439 PlatformTouchPoint::State pointState = point.state();
3440 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3442 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3443 // The HitTestRequest types used for mouse events map quite adequately
3444 // to touch events. Note that in addition to meaning that the hit test
3445 // should affect the active state of the current node if necessary,
3446 // HitTestRequest::Active signifies that the hit test is taking place
3447 // with the mouse (or finger in this case) being pressed.
3448 switch (pointState) {
3449 case PlatformTouchPoint::TouchPressed:
3450 hitType |= HitTestRequest::Active;
3452 case PlatformTouchPoint::TouchMoved:
3453 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3455 case PlatformTouchPoint::TouchReleased:
3456 case PlatformTouchPoint::TouchCancelled:
3457 hitType |= HitTestRequest::Release;
3459 case PlatformTouchPoint::TouchStationary:
3460 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3463 ASSERT_NOT_REACHED();
3467 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3468 unsigned touchPointTargetKey = point.id() + 1;