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"
34 #include "ComposedShadowTreeWalker.h"
36 #include "CursorList.h"
38 #include "DocumentEventQueue.h"
39 #include "DragController.h"
40 #include "DragState.h"
42 #include "EventNames.h"
43 #include "FloatPoint.h"
44 #include "FloatRect.h"
45 #include "FocusController.h"
47 #include "FrameLoader.h"
48 #include "FrameSelection.h"
49 #include "FrameTree.h"
50 #include "FrameView.h"
51 #include "htmlediting.h"
52 #include "HTMLFrameElementBase.h"
53 #include "HTMLFrameSetElement.h"
54 #include "HTMLInputElement.h"
55 #include "HTMLNames.h"
56 #include "HitTestRequest.h"
57 #include "HitTestResult.h"
59 #include "InspectorInstrumentation.h"
60 #include "KeyboardEvent.h"
61 #include "MouseEvent.h"
62 #include "MouseEventWithHitTestResults.h"
64 #include "PlatformEvent.h"
65 #include "PlatformKeyboardEvent.h"
66 #include "PlatformWheelEvent.h"
67 #include "PluginDocument.h"
68 #include "RenderFrameSet.h"
69 #include "RenderLayer.h"
70 #include "RenderTextControlSingleLine.h"
71 #include "RenderView.h"
72 #include "RenderWidget.h"
73 #include "ScrollAnimator.h"
74 #include "Scrollbar.h"
76 #include "ShadowRoot.h"
77 #include "SpatialNavigation.h"
78 #include "StaticHashSetNodeList.h"
79 #include "StyleCachedImage.h"
80 #include "TextEvent.h"
81 #include "TextIterator.h"
82 #include "UserGestureIndicator.h"
83 #include "UserTypingGestureIndicator.h"
84 #include "WheelEvent.h"
85 #include "WindowsKeyboardCodes.h"
86 #include <wtf/Assertions.h>
87 #include <wtf/CurrentTime.h>
88 #include <wtf/StdLibExtras.h>
89 #include <wtf/TemporaryChange.h>
91 #if ENABLE(GESTURE_EVENTS)
92 #include "PlatformGestureEvent.h"
95 #if ENABLE(TOUCH_ADJUSTMENT)
96 #include "TouchAdjustment.h"
100 #include "SVGDocument.h"
101 #include "SVGElementInstance.h"
102 #include "SVGNames.h"
103 #include "SVGUseElement.h"
106 #if ENABLE(TOUCH_EVENTS)
107 #include "PlatformTouchEvent.h"
108 #include "TouchEvent.h"
109 #include "TouchList.h"
112 #if ENABLE(TIZEN_LINK_EFFECT)
113 #include "TizenLinkEffect.h"
118 using namespace HTMLNames;
120 #if ENABLE(DRAG_SUPPORT)
121 // The link drag hysteresis is much larger than the others because there
122 // needs to be enough space to cancel the link press without starting a link drag,
123 // and because dragging links is rare.
124 const int LinkDragHysteresis = 40;
125 const int ImageDragHysteresis = 5;
126 const int TextDragHysteresis = 3;
127 const int GeneralDragHysteresis = 3;
128 #endif // ENABLE(DRAG_SUPPORT)
130 // Match key code of composition keydown event on windows.
131 // IE sends VK_PROCESSKEY which has value 229;
132 const int CompositionEventKeyCode = 229;
135 using namespace SVGNames;
138 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
139 const double autoscrollInterval = 0.05;
141 // The amount of time to wait before sending a fake mouse event, triggered
142 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
143 // otherwise the long interval is used.
144 const double fakeMouseMoveShortInterval = 0.1;
145 const double fakeMouseMoveLongInterval = 0.250;
147 enum NoCursorChangeType { NoCursorChange };
149 class OptionalCursor {
151 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
152 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
154 bool isCursorChange() const { return m_isCursorChange; }
155 const Cursor& cursor() const { return m_cursor; }
158 bool m_isCursorChange;
162 class MaximumDurationTracker {
164 explicit MaximumDurationTracker(double *maxDuration)
165 : m_maxDuration(maxDuration)
166 , m_start(monotonicallyIncreasingTime())
170 ~MaximumDurationTracker()
172 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
176 double* m_maxDuration;
180 #if ENABLE(TOUCH_EVENTS)
181 class SyntheticTouchPoint : public PlatformTouchPoint {
184 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
185 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
187 const static int idDefaultValue = 0;
188 const static int radiusYDefaultValue = 1;
189 const static int radiusXDefaultValue = 1;
190 const static float rotationAngleDefaultValue = 0.0f;
191 const static float forceDefaultValue = 1.0f;
193 m_id = idDefaultValue; // There is only one active TouchPoint.
194 m_screenPos = event.globalPosition();
195 m_pos = event.position();
196 m_radiusY = radiusYDefaultValue;
197 m_radiusX = radiusXDefaultValue;
198 m_rotationAngle = rotationAngleDefaultValue;
199 m_force = forceDefaultValue;
201 PlatformEvent::Type type = event.type();
202 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
205 case PlatformEvent::MouseMoved:
206 m_state = TouchMoved;
208 case PlatformEvent::MousePressed:
209 m_state = TouchPressed;
211 case PlatformEvent::MouseReleased:
212 m_state = TouchReleased;
215 ASSERT_NOT_REACHED();
221 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
223 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
225 switch (event.type()) {
226 case PlatformEvent::MouseMoved:
229 case PlatformEvent::MousePressed:
232 case PlatformEvent::MouseReleased:
236 ASSERT_NOT_REACHED();
240 m_timestamp = event.timestamp();
241 m_modifiers = event.modifiers();
242 m_touchPoints.append(SyntheticTouchPoint(event));
247 static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent::Granularity granularity)
249 switch (granularity) {
250 case WheelEvent::Page:
252 case WheelEvent::Line:
254 case WheelEvent::Pixel:
255 return ScrollByPixel;
257 return ScrollByPixel;
260 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
264 if (!node->renderer())
266 RenderBox* enclosingBox = node->renderer()->enclosingBox();
267 float absDelta = delta > 0 ? delta : -delta;
268 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode);
273 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
278 #if ENABLE(DRAG_SUPPORT)
279 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
287 EventHandler::EventHandler(Frame* frame)
289 , m_mousePressed(false)
290 , m_capturesDragging(false)
291 , m_mouseDownMayStartSelect(false)
292 #if ENABLE(DRAG_SUPPORT)
293 , m_mouseDownMayStartDrag(false)
294 , m_dragMayStartSelectionInstead(false)
296 , m_mouseDownWasSingleClickInSelection(false)
297 , m_selectionInitiationState(HaveNotStartedSelection)
298 , m_panScrollInProgress(false)
299 , m_panScrollButtonPressed(false)
300 , m_springLoadedPanScrollInProgress(false)
301 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
302 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
303 , m_autoscrollRenderer(0)
304 , m_autoscrollInProgress(false)
305 , m_mouseDownMayStartAutoscroll(false)
306 , m_mouseDownWasInSubframe(false)
307 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
312 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
314 , m_mouseDownTimestamp(0)
315 , m_useLatchedWheelEventNode(false)
316 , m_widgetIsLatched(false)
318 , m_mouseDownView(nil)
319 , m_sendingEventToSubview(false)
320 , m_activationEventNumber(-1)
322 #if ENABLE(TOUCH_EVENTS)
323 , m_touchPressed(false)
325 , m_maxMouseMovedDuration(0)
326 , m_baseEventType(PlatformEvent::NoType)
330 EventHandler::~EventHandler()
332 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
335 #if ENABLE(DRAG_SUPPORT)
336 DragState& EventHandler::dragState()
338 DEFINE_STATIC_LOCAL(DragState, state, ());
341 #endif // ENABLE(DRAG_SUPPORT)
343 void EventHandler::clear()
346 m_fakeMouseMoveEventTimer.stop();
348 m_nodeUnderMouse = 0;
349 m_lastNodeUnderMouse = 0;
351 m_instanceUnderMouse = 0;
352 m_lastInstanceUnderMouse = 0;
354 m_lastMouseMoveEventSubframe = 0;
355 m_lastScrollbarUnderMouse = 0;
358 m_frameSetBeingResized = 0;
359 #if ENABLE(DRAG_SUPPORT)
361 m_shouldOnlyFireDragOverEvent = false;
363 m_currentMousePosition = IntPoint();
364 m_currentMouseGlobalPosition = IntPoint();
365 m_mousePressNode = 0;
366 m_mousePressed = false;
367 m_capturesDragging = false;
368 m_capturingMouseEventsNode = 0;
369 m_latchedWheelEventNode = 0;
370 m_previousWheelScrolledNode = 0;
371 #if ENABLE(TOUCH_EVENTS)
372 m_originatingTouchPointTargets.clear();
374 m_maxMouseMovedDuration = 0;
375 #if ENABLE(GESTURE_EVENTS)
376 m_baseEventType = PlatformEvent::NoType;
380 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
382 if (nodeToBeRemoved->contains(m_clickNode.get()))
386 static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
389 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
390 selection->setSelection(newSelection);
393 static inline bool dispatchSelectStart(Node* node)
395 if (!node || !node->renderer())
398 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
401 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity)
403 if (Position::nodeIsUserSelectNone(targetNode))
406 if (!dispatchSelectStart(targetNode))
409 if (newSelection.isRange())
410 m_selectionInitiationState = ExtendedSelection;
412 granularity = CharacterGranularity;
413 m_selectionInitiationState = PlacedCaret;
416 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, granularity);
421 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
423 Node* innerNode = targetNode(result);
424 VisibleSelection newSelection;
426 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
427 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
428 if (pos.isNotNull()) {
429 newSelection = VisibleSelection(pos);
430 newSelection.expandUsingGranularity(WordGranularity);
433 if (newSelection.isRange() && result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
434 newSelection.appendTrailingWhitespace();
436 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
440 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
442 if (!result.hitTestResult().isLiveLink())
443 return selectClosestWordFromMouseEvent(result);
445 Node* innerNode = targetNode(result);
447 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
448 VisibleSelection newSelection;
449 Element* URLElement = result.hitTestResult().URLElement();
450 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
451 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
452 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
454 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
458 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
460 if (event.event().button() != LeftButton)
463 if (m_frame->selection()->isRange())
464 // A double-click when range is already selected
465 // should not change the selection. So, do not call
466 // selectClosestWordFromMouseEvent, but do set
467 // m_beganSelectingText to prevent handleMouseReleaseEvent
468 // from setting caret selection.
469 m_selectionInitiationState = ExtendedSelection;
471 selectClosestWordFromMouseEvent(event);
476 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
478 if (event.event().button() != LeftButton)
481 Node* innerNode = targetNode(event);
482 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
485 VisibleSelection newSelection;
486 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
487 if (pos.isNotNull()) {
488 newSelection = VisibleSelection(pos);
489 newSelection.expandUsingGranularity(ParagraphGranularity);
492 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity);
495 static int textDistance(const Position& start, const Position& end)
497 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
498 return TextIterator::rangeLength(range.get(), true);
501 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
503 m_frame->document()->updateLayoutIgnorePendingStylesheets();
504 Node* innerNode = targetNode(event);
505 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) {
506 #if ENABLE(TIZEN_LINK_EFFECT)
507 TizenLinkEffect::playLinkEffect();
512 // Extend the selection if the Shift key is down, unless the click is in a link.
513 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
515 // Don't restart the selection when the mouse is pressed on an
516 // existing selection so we can allow for text dragging.
517 if (FrameView* view = m_frame->view()) {
518 LayoutPoint vPoint = view->windowToContents(event.event().position());
519 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
520 m_mouseDownWasSingleClickInSelection = true;
525 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
526 if (visiblePos.isNull())
527 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
528 Position pos = visiblePos.deepEquivalent();
530 VisibleSelection newSelection = m_frame->selection()->selection();
531 TextGranularity granularity = CharacterGranularity;
533 if (extendSelection && newSelection.isCaretOrRange()) {
534 ASSERT(m_frame->settings());
535 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
536 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
537 // was created right-to-left
538 Position start = newSelection.start();
539 Position end = newSelection.end();
540 int distanceToStart = textDistance(start, pos);
541 int distanceToEnd = textDistance(pos, end);
542 if (distanceToStart <= distanceToEnd)
543 newSelection = VisibleSelection(end, pos);
545 newSelection = VisibleSelection(start, pos);
547 newSelection.setExtent(pos);
549 if (m_frame->selection()->granularity() != CharacterGranularity) {
550 granularity = m_frame->selection()->granularity();
551 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
554 newSelection = VisibleSelection(visiblePos);
556 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
559 static inline bool canMouseDownStartSelect(Node* node)
561 if (!node || !node->renderer())
564 if (!node->canStartSelection())
570 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
572 #if ENABLE(DRAG_SUPPORT)
574 #if ENABLE(TIZEN_DRAG_SUPPORT)
575 if(m_frame->page()->dragController()->dragState())
577 dragState().m_dragSrc = 0;
580 cancelFakeMouseMoveEvent();
582 m_frame->document()->updateLayoutIgnorePendingStylesheets();
584 if (ScrollView* scrollView = m_frame->view()) {
585 if (scrollView->isPointInScrollbarCorner(event.event().position()))
589 bool singleClick = event.event().clickCount() <= 1;
591 // If we got the event back, that must mean it wasn't prevented,
592 // so it's allowed to start a drag or selection.
593 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
595 #if ENABLE(DRAG_SUPPORT)
596 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
597 #if ENABLE(TIZEN_DRAG_SUPPORT)
598 if(m_frame->page()->dragController()->dragState())
600 m_mouseDownMayStartDrag = singleClick;
603 m_mouseDownWasSingleClickInSelection = false;
605 m_mouseDown = event.event();
607 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
611 if (m_frame->document()->isSVGDocument()
612 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
613 if (event.event().shiftKey() && singleClick) {
615 static_cast<SVGDocument*>(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
621 // We don't do this at the start of mouse down handling,
622 // because we don't want to do it until we know we didn't hit a widget.
626 Node* innerNode = targetNode(event);
628 m_mousePressNode = innerNode;
629 #if ENABLE(DRAG_SUPPORT)
630 #if ENABLE(TIZEN_DRAG_SUPPORT)
631 if(m_frame->page()->dragController()->dragState())
633 m_dragStartPos = event.event().position();
636 bool swallowEvent = false;
637 m_mousePressed = true;
638 m_selectionInitiationState = HaveNotStartedSelection;
640 if (event.event().clickCount() == 2)
641 swallowEvent = handleMousePressEventDoubleClick(event);
642 else if (event.event().clickCount() >= 3)
643 swallowEvent = handleMousePressEventTripleClick(event);
645 swallowEvent = handleMousePressEventSingleClick(event);
647 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
648 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
650 #if ENABLE(TIZEN_DRAG_SUPPORT)
651 if(m_frame->page()->dragController()->dragState()) {
652 IntPoint fakePoint(0,0);
653 PlatformMouseEvent fakeMouseEvent(fakePoint, fakePoint, NoButton, PlatformEvent::NoType, 0, false, false, false, false, currentTime());
654 mouseMoved(fakeMouseEvent);
661 // There are two kinds of renderer that can autoscroll.
662 static bool canAutoscroll(RenderObject* renderer)
664 if (!renderer->isBox())
667 // Check for a box that can be scrolled in its own right.
668 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
671 // Check for a box that represents the top level of a web page.
672 // This can be scrolled by calling Chrome::scrollRectIntoView.
673 // This only has an effect on the Mac platform in applications
674 // that put web views into scrolling containers, such as Mac OS X Mail.
675 // The code for this is in RenderLayer::scrollRectToVisible.
676 if (renderer->node() != renderer->document())
678 Frame* frame = renderer->frame();
681 Page* page = frame->page();
682 return page && page->mainFrame() == frame;
685 #if ENABLE(DRAG_SUPPORT)
686 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
688 if (handleDrag(event))
694 Node* targetNode = EventHandler::targetNode(event);
695 if (event.event().button() != LeftButton || !targetNode)
698 RenderObject* renderer = targetNode->renderer();
700 renderer = targetNode->parentNode() ? targetNode->parentNode()->renderer() : 0;
701 if (!renderer || !renderer->isListBox())
705 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
706 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
709 m_mouseDownMayStartDrag = false;
711 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
712 // Find a renderer that can autoscroll.
713 while (renderer && !canAutoscroll(renderer)) {
714 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
715 renderer = renderer->document()->ownerElement()->renderer();
717 renderer = renderer->parent();
721 m_autoscrollInProgress = true;
722 handleAutoscroll(renderer);
725 m_mouseDownMayStartAutoscroll = false;
728 if (m_selectionInitiationState != ExtendedSelection) {
729 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
730 HitTestResult result(m_mouseDownPos);
731 m_frame->document()->renderView()->hitTest(request, result);
733 updateSelectionForMouseDrag(result);
735 updateSelectionForMouseDrag(event.hitTestResult());
739 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
741 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
742 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
743 // in handleMousePressEvent
745 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
748 if (event.button() != LeftButton || event.clickCount() != 1)
751 FrameView* view = m_frame->view();
755 Page* page = m_frame->page();
759 updateDragSourceActionsAllowed();
760 HitTestRequest request(HitTestRequest::ReadOnly);
761 HitTestResult result(view->windowToContents(event.position()));
762 m_frame->contentRenderer()->hitTest(request, result);
764 return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), roundedIntPoint(result.point()), state);
767 void EventHandler::updateSelectionForMouseDrag()
769 FrameView* view = m_frame->view();
772 RenderView* renderer = m_frame->contentRenderer();
776 HitTestRequest request(HitTestRequest::ReadOnly |
777 HitTestRequest::Active |
778 HitTestRequest::Move);
779 HitTestResult result(view->windowToContents(m_currentMousePosition));
780 renderer->hitTest(request, result);
781 updateSelectionForMouseDrag(result);
784 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
786 LayoutPoint selectionEndPoint = localPoint;
787 Element* editableElement = selection.rootEditableElement();
789 if (!targetNode->renderer())
790 return VisiblePosition();
792 if (editableElement && !editableElement->contains(targetNode)) {
793 if (!editableElement->renderer())
794 return VisiblePosition();
796 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
797 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
798 targetNode = editableElement;
801 return targetNode->renderer()->positionForPoint(selectionEndPoint);
804 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
806 if (!m_mouseDownMayStartSelect)
809 Node* target = targetNode(hitTestResult);
813 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
815 // Don't modify the selection if we're not on a node.
816 if (targetPosition.isNull())
819 // Restart the selection if this is the first mouse move. This work is usually
820 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
821 VisibleSelection newSelection = m_frame->selection()->selection();
824 // Special case to limit selection to the containing block for SVG text.
825 // FIXME: Isn't there a better non-SVG-specific way to do this?
826 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
827 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
828 if (selectionBaseRenderer->isSVGText())
829 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
833 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
836 if (m_selectionInitiationState != ExtendedSelection) {
837 // Always extend selection here because it's caused by a mouse drag
838 m_selectionInitiationState = ExtendedSelection;
839 newSelection = VisibleSelection(targetPosition);
842 newSelection.setExtent(targetPosition);
843 if (m_frame->selection()->granularity() != CharacterGranularity)
844 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
846 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection()->granularity(),
847 FrameSelection::AdjustEndpointsAtBidiBoundary);
849 #endif // ENABLE(DRAG_SUPPORT)
851 void EventHandler::lostMouseCapture()
853 m_frame->selection()->setCaretBlinkingSuspended(false);
856 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
858 if (eventLoopHandleMouseUp(event))
861 // If this was the first click in the window, we don't even want to clear the selection.
862 // This case occurs when the user clicks on a draggable element, since we have to process
863 // the mouse down and drag events to see if we might start a drag. For other first clicks
864 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
865 // ignored upstream of this layer.
866 return eventActivatedView(event.event());
869 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
871 if (m_autoscrollInProgress)
872 stopAutoscrollTimer();
874 if (handleMouseUp(event))
877 // Used to prevent mouseMoveEvent from initiating a drag before
878 // the mouse is pressed again.
879 m_frame->selection()->setCaretBlinkingSuspended(false);
880 m_mousePressed = false;
881 m_capturesDragging = false;
882 #if ENABLE(DRAG_SUPPORT)
883 m_mouseDownMayStartDrag = false;
885 m_mouseDownMayStartSelect = false;
886 m_mouseDownMayStartAutoscroll = false;
887 m_mouseDownWasInSubframe = false;
889 bool handled = false;
891 // Clear the selection if the mouse didn't move after the last mouse
892 // press and it's not a context menu click. We do this so when clicking
893 // on the selection, the selection goes away. However, if we are
894 // editing, place the caret.
895 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
896 #if ENABLE(DRAG_SUPPORT)
897 && m_dragStartPos == event.event().position()
899 && m_frame->selection()->isRange()
900 && event.event().button() != RightButton) {
901 VisibleSelection newSelection;
902 Node* node = targetNode(event);
903 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
904 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
905 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
906 newSelection = VisibleSelection(pos);
909 setSelectionIfNeeded(m_frame->selection(), newSelection);
914 m_frame->selection()->notifyRendererOfSelectionChange(UserTriggered);
916 m_frame->selection()->selectFrameElementInParentIfFullySelected();
921 void EventHandler::handleAutoscroll(RenderObject* renderer)
923 // We don't want to trigger the autoscroll or the panScroll if it's already active
924 if (m_autoscrollTimer.isActive())
927 setAutoscrollRenderer(renderer);
929 #if ENABLE(PAN_SCROLLING)
930 if (m_panScrollInProgress) {
931 m_panScrollStartPos = currentMousePosition();
932 if (FrameView* view = m_frame->view())
933 view->addPanScrollIcon(m_panScrollStartPos);
934 // If we're not in the top frame we notify it that we doing a panScroll.
935 if (Page* page = m_frame->page()) {
936 Frame* mainFrame = page->mainFrame();
937 if (m_frame != mainFrame)
938 mainFrame->eventHandler()->m_panScrollInProgress = true;
943 startAutoscrollTimer();
946 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
948 RenderObject* r = autoscrollRenderer();
949 if (!r || !r->isBox()) {
950 stopAutoscrollTimer();
954 if (m_autoscrollInProgress) {
955 if (!m_mousePressed) {
956 stopAutoscrollTimer();
959 toRenderBox(r)->autoscroll();
961 // we verify that the main frame hasn't received the order to stop the panScroll
962 if (Page* page = m_frame->page()) {
963 if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) {
964 stopAutoscrollTimer();
968 #if ENABLE(PAN_SCROLLING)
969 updatePanScrollState();
970 toRenderBox(r)->panScroll(m_panScrollStartPos);
975 #if ENABLE(PAN_SCROLLING)
977 void EventHandler::startPanScrolling(RenderObject* renderer)
979 m_panScrollInProgress = true;
980 m_panScrollButtonPressed = true;
981 handleAutoscroll(renderer);
985 void EventHandler::updatePanScrollState()
987 FrameView* view = m_frame->view();
991 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
992 // So we don't want to change the cursor over this area
993 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
994 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
995 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
996 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
998 if ((east || west || north || south) && m_panScrollButtonPressed)
999 m_springLoadedPanScrollInProgress = true;
1003 view->setCursor(northEastPanningCursor());
1005 view->setCursor(northWestPanningCursor());
1007 view->setCursor(northPanningCursor());
1010 view->setCursor(southEastPanningCursor());
1012 view->setCursor(southWestPanningCursor());
1014 view->setCursor(southPanningCursor());
1016 view->setCursor(eastPanningCursor());
1018 view->setCursor(westPanningCursor());
1020 view->setCursor(middlePanningCursor());
1023 #endif // ENABLE(PAN_SCROLLING)
1025 RenderObject* EventHandler::autoscrollRenderer() const
1027 return m_autoscrollRenderer;
1030 void EventHandler::updateAutoscrollRenderer()
1032 if (!m_autoscrollRenderer)
1035 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
1037 if (Node* nodeAtPoint = hitTest.innerNode())
1038 m_autoscrollRenderer = nodeAtPoint->renderer();
1040 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
1041 m_autoscrollRenderer = m_autoscrollRenderer->parent();
1044 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
1046 m_autoscrollRenderer = renderer;
1049 #if ENABLE(DRAG_SUPPORT)
1050 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1053 return DragSourceActionNone;
1055 Page* page = m_frame->page();
1057 return DragSourceActionNone;
1059 FrameView* view = m_frame->view();
1061 return DragSourceActionNone;
1063 return page->dragController()->delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1065 #endif // ENABLE(DRAG_SUPPORT)
1067 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1069 enum ShadowContentFilterPolicy shadowContentFilterPolicy = allowShadowContent ? AllowShadowContent : DoNotAllowShadowContent;
1070 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1072 if (!m_frame->contentRenderer())
1075 hitType |= HitTestRequest::IgnoreClipping;
1076 m_frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
1079 Node* n = result.innerNode();
1080 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
1082 RenderWidget* renderWidget = toRenderWidget(n->renderer());
1083 Widget* widget = renderWidget->widget();
1084 if (!widget || !widget->isFrameView())
1086 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
1087 if (!frame || !frame->contentRenderer())
1089 FrameView* view = static_cast<FrameView*>(widget);
1090 LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
1091 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
1092 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1093 frame->contentRenderer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
1094 result = widgetHitTestResult;
1096 if (testScrollbars == ShouldHitTestScrollbars) {
1097 Scrollbar* eventScrollbar = view->scrollbarAtPoint(roundedIntPoint(point));
1099 result.setScrollbar(eventScrollbar);
1103 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
1104 // Another hit test at the main frame level should get us the correct visible result.
1105 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
1106 if (Page* page = m_frame->page()) {
1107 Frame* mainFrame = page->mainFrame();
1108 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame) {
1109 FrameView* resultView = resultFrame->view();
1110 FrameView* mainView = mainFrame->view();
1111 if (resultView && mainView) {
1112 IntPoint mainFramePoint = mainView->rootViewToContents(resultView->contentsToRootView(roundedIntPoint(result.point())));
1113 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
1118 if (!allowShadowContent)
1119 result.setToNonShadowAncestor();
1125 void EventHandler::startAutoscrollTimer()
1127 m_autoscrollTimer.startRepeating(autoscrollInterval);
1130 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1132 if (m_autoscrollInProgress) {
1133 if (m_mouseDownWasInSubframe) {
1134 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
1135 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
1140 if (autoscrollRenderer()) {
1141 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
1142 toRenderBox(autoscrollRenderer())->stopAutoscroll();
1143 #if ENABLE(PAN_SCROLLING)
1144 if (m_panScrollInProgress) {
1145 if (FrameView* view = m_frame->view()) {
1146 view->removePanScrollIcon();
1147 view->setCursor(pointerCursor());
1152 setAutoscrollRenderer(0);
1155 m_autoscrollTimer.stop();
1157 m_panScrollInProgress = false;
1158 m_springLoadedPanScrollInProgress = false;
1160 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1161 if (Page* page = m_frame->page()) {
1162 Frame* mainFrame = page->mainFrame();
1163 if (m_frame != mainFrame)
1164 mainFrame->eventHandler()->m_panScrollInProgress = false;
1167 m_autoscrollInProgress = false;
1170 Node* EventHandler::mousePressNode() const
1172 return m_mousePressNode.get();
1175 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1177 m_mousePressNode = node;
1180 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1182 Node* node = startingNode;
1185 node = m_frame->document()->focusedNode();
1188 node = m_mousePressNode.get();
1191 RenderObject* r = node->renderer();
1192 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1193 setFrameWasScrolledByUser();
1201 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
1202 bool EventHandler::scrollOverflow(const FloatPoint& trajectoryVector)
1204 bool scrolled = false;
1205 if (m_mousePressNode) {
1206 RenderObject* r = m_mousePressNode->renderer();
1207 if (r && !r->isListBox()) {
1208 float multiplier = 0;
1209 ScrollDirection direction;
1211 float delta = trajectoryVector.y();
1213 multiplier = (delta < 0) ? -delta : delta;
1214 direction = (delta < 0) ? ScrollUp : ScrollDown;
1215 scrolled |= r->enclosingBox()->scroll(direction, ScrollByPixel, multiplier);
1217 delta = trajectoryVector.x();
1219 multiplier = (delta < 0) ? -delta : delta;
1220 direction = (delta < 0) ? ScrollLeft : ScrollRight;
1221 scrolled |= r->enclosingBox()->scroll(direction, ScrollByPixel, multiplier);
1225 setFrameWasScrolledByUser();
1227 #if ENABLE(TIZEN_INPUT_BOX_SCROLL)
1229 if (r && r->isTextField()) {
1230 WebCore::RenderTextControl* renderText = toRenderTextControl(r);
1231 int leftScrollOffset = renderText->scrollLeft();
1232 m_mousePressNode->document()->frame()->selection()->setCaretVisible(false);
1233 leftScrollOffset += trajectoryVector.x();
1234 renderText->setScrollLeft(leftScrollOffset);
1235 renderText->setScrollTop((int)trajectoryVector.y());
1236 m_mousePressNode->document()->frame()->selection()->setCaretVisible(true);
1246 bool EventHandler::setMousePressNodeAtPoint(const IntPoint& point, bool checkOverflowLayer, RenderObject*& overflowRenderer)
1248 HitTestResult result = hitTestResultAtPoint(point, false);
1249 Node* node = result.innerNode();
1251 setMousePressNode(0);
1256 RenderObject* renderer = node->renderer();
1258 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
1259 if (checkOverflowLayer) {
1260 // Find overflow layer.
1261 if (renderer->isBoxModelObject() && renderer->hasLayer()
1262 && renderer->enclosingLayer()->hasAcceleratedTouchScrolling()
1263 && renderer->enclosingLayer()->layerForScrollingContents()) {
1264 overflowRenderer = renderer;
1265 setMousePressNode(node);
1270 // Find overflow node.
1271 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow()
1272 && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
1273 setMousePressNode(node);
1276 #if ENABLE(TIZEN_INPUT_BOX_SCROLL)
1277 // Setting mouse press for inline text box
1278 if (renderer->isBox() && renderer->isTextField()) {
1279 setMousePressNode(node);
1283 renderer = renderer->parent();
1286 if (node->document()->frame())
1287 node = static_cast<Node*>(node->document()->frame()->ownerElement());
1292 setMousePressNode(0);
1297 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1299 Node* node = startingNode;
1302 node = m_frame->document()->focusedNode();
1305 node = m_mousePressNode.get();
1308 RenderObject* r = node->renderer();
1309 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1310 setFrameWasScrolledByUser();
1318 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1320 // The layout needs to be up to date to determine if we can scroll. We may be
1321 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1322 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1323 if (scrollOverflow(direction, granularity, startingNode))
1325 Frame* frame = m_frame;
1326 FrameView* view = frame->view();
1327 if (view && view->scroll(direction, granularity))
1329 frame = frame->tree()->parent();
1332 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1335 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1337 // The layout needs to be up to date to determine if we can scroll. We may be
1338 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1339 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1340 if (logicalScrollOverflow(direction, granularity, startingNode))
1342 Frame* frame = m_frame;
1343 FrameView* view = frame->view();
1345 bool scrolled = false;
1347 // Mac also resets the scroll position in the inline direction.
1348 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1351 if (view && view->logicalScroll(direction, granularity))
1357 frame = frame->tree()->parent();
1361 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1364 IntPoint EventHandler::currentMousePosition() const
1366 return m_currentMousePosition;
1369 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1371 if (!hitTestResult.isOverWidget())
1373 return subframeForTargetNode(targetNode(hitTestResult));
1376 Frame* EventHandler::subframeForTargetNode(Node* node)
1381 RenderObject* renderer = node->renderer();
1382 if (!renderer || !renderer->isWidget())
1385 Widget* widget = toRenderWidget(renderer)->widget();
1386 if (!widget || !widget->isFrameView())
1389 return static_cast<FrameView*>(widget)->frame();
1392 static bool isSubmitImage(Node* node)
1394 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1397 // Returns true if the node's editable block is not current focused for editing
1398 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1400 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1403 OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1405 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1406 return NoCursorChange;
1408 Page* page = m_frame->page();
1410 return NoCursorChange;
1411 if (page->mainFrame()->eventHandler()->m_panScrollInProgress)
1412 return NoCursorChange;
1414 Node* node = targetNode(event);
1415 RenderObject* renderer = node ? node->renderer() : 0;
1416 RenderStyle* style = renderer ? renderer->style() : 0;
1417 bool horizontalText = !style || style->isHorizontalWritingMode();
1418 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1420 // During selection, use an I-beam no matter what we're over.
1421 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1422 if (m_mousePressed && m_mouseDownMayStartSelect
1423 #if ENABLE(DRAG_SUPPORT)
1424 && !m_mouseDownMayStartDrag
1426 && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1430 Cursor overrideCursor;
1431 switch (renderer->getCursor(roundedIntPoint(event.localPoint()), overrideCursor)) {
1432 case SetCursorBasedOnStyle:
1435 return overrideCursor;
1436 case DoNotSetCursor:
1437 return NoCursorChange;
1441 if (style && style->cursors()) {
1442 const CursorList* cursors = style->cursors();
1443 for (unsigned i = 0; i < cursors->size(); ++i) {
1444 CachedImage* cimage = 0;
1445 StyleImage* image = (*cursors)[i].image();
1446 if (image && image->isCachedImage())
1447 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1450 IntPoint hotSpot = (*cursors)[i].hotSpot();
1451 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1452 IntSize size = cimage->imageForRenderer(renderer)->size();
1453 if (size.width() > 128 || size.height() > 128)
1455 if (!cimage->errorOccurred())
1456 return Cursor(cimage->imageForRenderer(renderer), hotSpot);
1460 switch (style ? style->cursor() : CURSOR_AUTO) {
1462 bool editable = (node && node->rendererIsEditable());
1463 bool editableLinkEnabled = false;
1465 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1467 ASSERT(m_frame->settings());
1468 switch (m_frame->settings()->editableLinkBehavior()) {
1470 case EditableLinkDefaultBehavior:
1471 case EditableLinkAlwaysLive:
1472 editableLinkEnabled = true;
1475 case EditableLinkNeverLive:
1476 editableLinkEnabled = false;
1479 case EditableLinkLiveWhenNotFocused:
1480 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1483 case EditableLinkOnlyLiveWithShiftKey:
1484 editableLinkEnabled = event.event().shiftKey();
1489 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1490 return handCursor();
1491 bool inResizer = false;
1493 if (RenderLayer* layer = renderer->enclosingLayer()) {
1494 if (FrameView* view = m_frame->view())
1495 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().position()));
1498 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1500 return pointerCursor();
1503 return crossCursor();
1504 case CURSOR_POINTER:
1505 return handCursor();
1507 return moveCursor();
1508 case CURSOR_ALL_SCROLL:
1509 return moveCursor();
1510 case CURSOR_E_RESIZE:
1511 return eastResizeCursor();
1512 case CURSOR_W_RESIZE:
1513 return westResizeCursor();
1514 case CURSOR_N_RESIZE:
1515 return northResizeCursor();
1516 case CURSOR_S_RESIZE:
1517 return southResizeCursor();
1518 case CURSOR_NE_RESIZE:
1519 return northEastResizeCursor();
1520 case CURSOR_SW_RESIZE:
1521 return southWestResizeCursor();
1522 case CURSOR_NW_RESIZE:
1523 return northWestResizeCursor();
1524 case CURSOR_SE_RESIZE:
1525 return southEastResizeCursor();
1526 case CURSOR_NS_RESIZE:
1527 return northSouthResizeCursor();
1528 case CURSOR_EW_RESIZE:
1529 return eastWestResizeCursor();
1530 case CURSOR_NESW_RESIZE:
1531 return northEastSouthWestResizeCursor();
1532 case CURSOR_NWSE_RESIZE:
1533 return northWestSouthEastResizeCursor();
1534 case CURSOR_COL_RESIZE:
1535 return columnResizeCursor();
1536 case CURSOR_ROW_RESIZE:
1537 return rowResizeCursor();
1539 return iBeamCursor();
1541 return waitCursor();
1543 return helpCursor();
1544 case CURSOR_VERTICAL_TEXT:
1545 return verticalTextCursor();
1547 return cellCursor();
1548 case CURSOR_CONTEXT_MENU:
1549 return contextMenuCursor();
1550 case CURSOR_PROGRESS:
1551 return progressCursor();
1552 case CURSOR_NO_DROP:
1553 return noDropCursor();
1555 return aliasCursor();
1557 return copyCursor();
1559 return noneCursor();
1560 case CURSOR_NOT_ALLOWED:
1561 return notAllowedCursor();
1562 case CURSOR_DEFAULT:
1563 return pointerCursor();
1564 case CURSOR_WEBKIT_ZOOM_IN:
1565 return zoomInCursor();
1566 case CURSOR_WEBKIT_ZOOM_OUT:
1567 return zoomOutCursor();
1568 case CURSOR_WEBKIT_GRAB:
1569 return grabCursor();
1570 case CURSOR_WEBKIT_GRABBING:
1571 return grabbingCursor();
1573 return pointerCursor();
1576 static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1578 FrameView* view = frame->view();
1579 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1580 // Historically the code would just crash; this is clearly no worse than that.
1581 return view ? view->windowToContents(windowPoint) : windowPoint;
1584 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1586 return targetNode(event.hitTestResult());
1589 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1591 Node* node = hitTestResult.innerNode();
1594 if (node->inDocument())
1597 Element* element = node->parentElement();
1598 if (element && element->inDocument())
1605 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1607 RefPtr<FrameView> protector(m_frame->view());
1609 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1614 #if ENABLE(TOUCH_EVENTS)
1615 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1616 if (defaultPrevented)
1620 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1622 // FIXME (bug 68185): this call should be made at another abstraction layer
1623 m_frame->loader()->resetMultipleFormSubmissionProtection();
1625 cancelFakeMouseMoveEvent();
1626 m_mousePressed = true;
1627 m_capturesDragging = true;
1628 m_currentMousePosition = mouseEvent.position();
1629 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1630 m_mouseDownTimestamp = mouseEvent.timestamp();
1631 #if ENABLE(DRAG_SUPPORT)
1632 m_mouseDownMayStartDrag = false;
1634 m_mouseDownMayStartSelect = false;
1635 m_mouseDownMayStartAutoscroll = false;
1636 if (FrameView* view = m_frame->view())
1637 #if ENABLE(TIZEN_DRAG_SUPPORT)
1638 m_mouseDownPos = mouseEvent.position();
1640 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1646 m_mouseDownWasInSubframe = false;
1648 HitTestRequest request(HitTestRequest::Active);
1649 // Save the document point we generate in case the window coordinate is invalidated by what happens
1650 // when we dispatch the event.
1651 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1652 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1654 if (!targetNode(mev)) {
1659 m_mousePressNode = targetNode(mev);
1661 Frame* subframe = subframeForHitTestResult(mev);
1662 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1663 // Start capturing future events for this frame. We only do this if we didn't clear
1664 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1665 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1666 if (m_mousePressed && m_capturesDragging) {
1667 m_capturingMouseEventsNode = targetNode(mev);
1668 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1674 #if ENABLE(PAN_SCROLLING)
1675 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1676 // because it will set m_panScrollInProgress to false on return.
1677 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress;
1678 if (isPanScrollInProgress || m_autoscrollInProgress)
1679 stopAutoscrollTimer();
1680 if (isPanScrollInProgress) {
1681 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1682 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1688 m_clickCount = mouseEvent.clickCount();
1689 m_clickNode = targetNode(mev);
1691 if (FrameView* view = m_frame->view()) {
1692 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1693 IntPoint p = view->windowToContents(mouseEvent.position());
1694 if (layer && layer->isPointInResizeControl(p)) {
1695 layer->setInResizeMode(true);
1696 m_resizeLayer = layer;
1697 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1703 m_frame->selection()->setCaretBlinkingSuspended(true);
1705 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1706 m_capturesDragging = !swallowEvent || mev.scrollbar();
1708 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1709 // in case the scrollbar widget was destroyed when the mouse event was handled.
1710 if (mev.scrollbar()) {
1711 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1712 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1713 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1714 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1715 m_lastScrollbarUnderMouse = 0;
1719 // scrollbars should get events anyway, even disabled controls might be scrollable
1720 Scrollbar* scrollbar = mev.scrollbar();
1722 updateLastScrollbarUnderMouse(scrollbar, true);
1725 passMousePressEventToScrollbar(mev, scrollbar);
1727 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1728 // If a mouse event handler changes the input element type to one that has a widget associated,
1729 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1730 // event target node can't still be the shadow node.
1731 if (targetNode(mev)->isShadowRoot() && toShadowRoot(targetNode(mev))->host()->hasTagName(inputTag)) {
1732 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1733 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1736 FrameView* view = m_frame->view();
1737 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1739 scrollbar = mev.scrollbar();
1741 updateLastScrollbarUnderMouse(scrollbar, true);
1743 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1744 swallowEvent = true;
1746 swallowEvent = handleMousePressEvent(mev);
1749 return swallowEvent;
1752 // This method only exists for platforms that don't know how to deliver
1753 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1755 RefPtr<FrameView> protector(m_frame->view());
1757 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1759 // We get this instead of a second mouse-up
1760 m_mousePressed = false;
1761 m_currentMousePosition = mouseEvent.position();
1762 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1764 HitTestRequest request(HitTestRequest::Active);
1765 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1766 Frame* subframe = subframeForHitTestResult(mev);
1767 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1768 m_capturingMouseEventsNode = 0;
1769 if (subframe && passMousePressEventToSubframe(mev, subframe))
1772 m_clickCount = mouseEvent.clickCount();
1773 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1775 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1777 if (m_lastScrollbarUnderMouse)
1778 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1780 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1784 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1787 static RenderLayer* layerForNode(Node* node)
1792 RenderObject* renderer = node->renderer();
1796 RenderLayer* layer = renderer->enclosingLayer();
1803 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1805 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1806 RefPtr<FrameView> protector(m_frame->view());
1809 #if ENABLE(TOUCH_EVENTS)
1810 // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events.
1811 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event);
1812 if (defaultPrevented)
1816 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1817 bool result = handleMouseMoveEvent(event, &hoveredNode);
1819 Page* page = m_frame->page();
1823 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1824 if (FrameView* frameView = m_frame->view()) {
1825 if (frameView->containsScrollableArea(layer))
1826 layer->mouseMovedInContentArea();
1830 if (FrameView* frameView = m_frame->view())
1831 frameView->mouseMovedInContentArea();
1833 hoveredNode.setToNonShadowAncestor();
1834 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1835 page->chrome()->setToolTip(hoveredNode);
1839 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1841 HitTestResult hoveredNode;
1842 return handleMouseMoveEvent(event, &hoveredNode, true);
1845 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1847 // in Radar 3703768 we saw frequent crashes apparently due to the
1848 // part being null here, which seems impossible, so check for nil
1849 // but also assert so that we can try to figure this out in debug
1850 // builds, if it happens.
1855 RefPtr<FrameView> protector(m_frame->view());
1856 m_currentMousePosition = mouseEvent.position();
1857 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1859 if (m_hoverTimer.isActive())
1860 m_hoverTimer.stop();
1862 cancelFakeMouseMoveEvent();
1866 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1871 if (m_frameSetBeingResized)
1872 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1874 // Send events right to a scrollbar if the mouse is pressed.
1875 if (m_lastScrollbarUnderMouse && m_mousePressed)
1876 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1878 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move;
1880 hitType |= HitTestRequest::Active;
1881 else if (onlyUpdateScrollbars) {
1882 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1883 // means that :hover and :active freeze in the state they were in, rather than updating
1884 // for nodes the mouse moves while the window is not key (which will be the case if
1885 // onlyUpdateScrollbars is true).
1886 hitType |= HitTestRequest::ReadOnly;
1889 #if ENABLE(TOUCH_EVENTS)
1890 // Treat any mouse move events as readonly if the user is currently touching the screen.
1892 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1894 HitTestRequest request(hitType);
1895 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1897 *hoveredNode = mev.hitTestResult();
1899 Scrollbar* scrollbar = 0;
1901 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1902 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1904 if (FrameView* view = m_frame->view())
1905 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1908 scrollbar = mev.scrollbar();
1910 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1911 if (onlyUpdateScrollbars)
1915 bool swallowEvent = false;
1916 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1918 // 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.
1919 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1920 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1923 // Update over/out state before passing the event to the subframe.
1924 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1926 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1927 // node to be detached from its FrameView, in which case the event should not be passed.
1928 if (newSubframe->view())
1929 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1931 if (scrollbar && !m_mousePressed)
1932 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1933 if (FrameView* view = m_frame->view()) {
1934 OptionalCursor optionalCursor = selectCursor(mev, scrollbar);
1935 if (optionalCursor.isCursorChange())
1936 view->setCursor(optionalCursor.cursor());
1940 m_lastMouseMoveEventSubframe = newSubframe;
1945 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1946 #if ENABLE(DRAG_SUPPORT)
1947 #if ENABLE(TIZEN_DRAG_SUPPORT)
1948 if (!swallowEvent && m_frame->page()->dragController()->dragState())
1952 swallowEvent = handleMouseDraggedEvent(mev);
1953 #endif // ENABLE(DRAG_SUPPORT)
1955 return swallowEvent;
1958 void EventHandler::invalidateClick()
1964 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1966 RefPtr<FrameView> protector(m_frame->view());
1968 #if ENABLE(TOUCH_EVENTS)
1969 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1970 if (defaultPrevented)
1974 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1976 #if ENABLE(PAN_SCROLLING)
1977 if (mouseEvent.button() == MiddleButton)
1978 m_panScrollButtonPressed = false;
1979 if (m_springLoadedPanScrollInProgress)
1980 stopAutoscrollTimer();
1983 m_mousePressed = false;
1984 m_currentMousePosition = mouseEvent.position();
1985 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1990 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1995 if (m_frameSetBeingResized)
1996 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1998 if (m_lastScrollbarUnderMouse) {
2000 return m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
2003 HitTestRequest request(HitTestRequest::Release);
2004 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
2005 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
2006 if (m_eventHandlerWillResetCapturingMouseEventsNode)
2007 m_capturingMouseEventsNode = 0;
2008 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
2011 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
2013 Node* clickTarget = targetNode(mev);
2015 clickTarget = clickTarget->shadowAncestorNode();
2016 Node* adjustedClickNode = m_clickNode ? m_clickNode->shadowAncestorNode() : 0;
2018 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && clickTarget == adjustedClickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
2020 if (m_resizeLayer) {
2021 m_resizeLayer->setInResizeMode(false);
2025 bool swallowMouseReleaseEvent = false;
2026 if (!swallowMouseUpEvent)
2027 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
2031 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2034 #if ENABLE(DRAG_SUPPORT)
2035 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
2037 FrameView* view = m_frame->view();
2039 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2043 view->resetDeferredRepaintDelay();
2044 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2045 true, true, m_frame->document()->defaultView(),
2046 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2047 #if ENABLE(POINTER_LOCK)
2048 event.movementDelta().x(), event.movementDelta().y(),
2050 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2054 dragTarget->dispatchEvent(me.get(), ec);
2055 return me->defaultPrevented();
2058 static bool targetIsFrame(Node* target, Frame*& frame)
2063 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
2066 frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
2071 static bool findDropZone(Node* target, Clipboard* clipboard)
2073 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
2074 for (; element; element = element->parentElement()) {
2075 bool matched = false;
2076 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2078 if (dropZoneStr.isEmpty())
2081 dropZoneStr.makeLower();
2083 SpaceSplitString keywords(dropZoneStr, false);
2084 if (keywords.isNull())
2087 DragOperation dragOperation = DragOperationNone;
2088 for (unsigned int i = 0; i < keywords.size(); i++) {
2089 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2090 if (op != DragOperationNone) {
2091 if (dragOperation == DragOperationNone)
2094 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
2096 if (matched && dragOperation != DragOperationNone)
2100 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2107 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2109 bool accept = false;
2111 if (!m_frame->view())
2114 HitTestRequest request(HitTestRequest::ReadOnly);
2115 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
2117 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
2118 RefPtr<Node> newTarget = targetNode(mev);
2119 if (newTarget && newTarget->isTextNode())
2120 newTarget = newTarget->parentNode();
2122 if (m_dragTarget != newTarget) {
2123 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2124 // it is sometimes incorrect when dragging within subframes, as seen with
2125 // LayoutTests/fast/events/drag-in-frames.html.
2127 // 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>.
2129 if (targetIsFrame(newTarget.get(), targetFrame)) {
2131 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2132 } else if (newTarget) {
2133 // 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.
2134 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2135 // for now we don't care if event handler cancels default behavior, since there is none
2136 dispatchDragSrcEvent(eventNames().dragEvent, event);
2138 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget.get(), event, clipboard);
2140 accept = findDropZone(newTarget.get(), clipboard);
2143 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2145 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2146 } else if (m_dragTarget)
2147 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2150 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2151 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2152 m_shouldOnlyFireDragOverEvent = true;
2156 if (targetIsFrame(newTarget.get(), targetFrame)) {
2158 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2159 } else if (newTarget) {
2160 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2161 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2162 // for now we don't care if event handler cancels default behavior, since there is none
2163 dispatchDragSrcEvent(eventNames().dragEvent, event);
2165 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget.get(), event, clipboard);
2167 accept = findDropZone(newTarget.get(), clipboard);
2168 m_shouldOnlyFireDragOverEvent = false;
2171 m_dragTarget = newTarget;
2176 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2179 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2181 targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard);
2182 } else if (m_dragTarget.get()) {
2183 if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
2184 dispatchDragSrcEvent(eventNames().dragEvent, event);
2185 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2190 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2193 bool preventedDefault = false;
2194 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2196 preventedDefault = targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
2197 } else if (m_dragTarget.get())
2198 preventedDefault = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
2200 return preventedDefault;
2203 void EventHandler::clearDragState()
2206 m_capturingMouseEventsNode = 0;
2207 m_shouldOnlyFireDragOverEvent = false;
2209 m_sendingEventToSubview = false;
2212 #endif // ENABLE(DRAG_SUPPORT)
2214 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
2216 m_capturingMouseEventsNode = n;
2217 m_eventHandlerWillResetCapturingMouseEventsNode = false;
2220 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
2223 ASSERT(m_frame->document());
2225 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
2229 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
2231 if (!referenceNode || !referenceNode->isSVGElement())
2234 ShadowRoot* shadowRoot = referenceNode->shadowRoot();
2238 Element* shadowTreeParentElement = shadowRoot->host();
2239 if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag))
2242 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
2246 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
2248 Node* result = targetNode;
2250 // If we're capturing, we always go right to that node.
2251 if (m_capturingMouseEventsNode)
2252 result = m_capturingMouseEventsNode.get();
2254 // If the target node is a text node, dispatch on the parent node - rdar://4196646
2255 if (result && result->isTextNode()) {
2256 ComposedShadowTreeParentWalker walker(result);
2257 walker.parentIncludingInsertionPointAndShadowRoot();
2258 result = walker.get();
2261 m_nodeUnderMouse = result;
2263 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
2265 // <use> shadow tree elements may have been recloned, update node under mouse in any case
2266 if (m_lastInstanceUnderMouse) {
2267 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
2268 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
2270 if (lastCorrespondingElement && lastCorrespondingUseElement) {
2271 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
2273 // Locate the recloned shadow tree element for our corresponding instance
2274 HashSet<SVGElementInstance*>::iterator end = instances.end();
2275 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
2276 SVGElementInstance* instance = (*it);
2277 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
2279 if (instance == m_lastInstanceUnderMouse)
2282 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
2285 SVGElement* shadowTreeElement = instance->shadowTreeElement();
2286 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
2289 m_lastNodeUnderMouse = shadowTreeElement;
2290 m_lastInstanceUnderMouse = instance;
2297 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2298 if (fireMouseOverOut) {
2299 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
2300 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
2301 Page* page = m_frame->page();
2303 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
2304 // The mouse has moved between frames.
2305 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2306 if (FrameView* frameView = frame->view())
2307 frameView->mouseExitedContentArea();
2309 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2310 // The mouse has moved between layers.
2311 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2312 if (FrameView* frameView = frame->view()) {
2313 if (frameView->containsScrollableArea(layerForLastNode))
2314 layerForLastNode->mouseExitedContentArea();
2319 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2320 // The mouse has moved between frames.
2321 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2322 if (FrameView* frameView = frame->view())
2323 frameView->mouseEnteredContentArea();
2325 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2326 // The mouse has moved between layers.
2327 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2328 if (FrameView* frameView = frame->view()) {
2329 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2330 layerForNodeUnderMouse->mouseEnteredContentArea();
2335 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2336 m_lastNodeUnderMouse = 0;
2337 m_lastScrollbarUnderMouse = 0;
2339 m_lastInstanceUnderMouse = 0;
2343 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2344 // send mouseout event to the old node
2345 if (m_lastNodeUnderMouse)
2346 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2347 // send mouseover event to the new node
2348 if (m_nodeUnderMouse)
2349 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2351 m_lastNodeUnderMouse = m_nodeUnderMouse;
2353 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2358 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2360 if (FrameView* view = m_frame->view())
2361 view->resetDeferredRepaintDelay();
2363 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2365 bool swallowEvent = false;
2367 if (m_nodeUnderMouse)
2368 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2370 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2372 // If clicking on a frame scrollbar, do not mess up with content focus.
2373 if (FrameView* view = m_frame->view()) {
2374 if (view->scrollbarAtPoint(mouseEvent.position()))
2378 // The layout needs to be up to date to determine if an element is focusable.
2379 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2381 // Blur current focus node when a link/button is clicked; this
2382 // is expected by some sites that rely on onChange handlers running
2383 // from form fields before the button click is processed.
2384 Node* node = m_nodeUnderMouse.get();
2386 // Walk up the DOM tree to search for a node to focus.
2388 if (node->isMouseFocusable()) {
2389 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2390 // node on mouse down if it's selected and inside a focused node. It will be
2391 // focused if the user does a mouseup over it, however, because the mouseup
2392 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2393 ExceptionCode ec = 0;
2394 Node* n = node->isShadowRoot() ? toShadowRoot(node)->host() : node;
2395 if (m_frame->selection()->isRange()
2396 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2397 && n->isDescendantOf(m_frame->document()->focusedNode()))
2402 node = node->parentOrHostNode();
2405 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2406 // if the page already set it (e.g., by canceling default behavior).
2407 if (Page* page = m_frame->page()) {
2408 if (node && node->isMouseFocusable()) {
2409 if (!page->focusController()->setFocusedNode(node, m_frame))
2410 swallowEvent = true;
2411 } else if (!node || !node->focused()) {
2412 if (!page->focusController()->setFocusedNode(0, m_frame))
2413 swallowEvent = true;
2418 return swallowEvent;
2421 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
2422 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2428 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2430 Document* doc = m_frame->document();
2432 RenderObject* docRenderer = doc->renderer();
2436 RefPtr<FrameView> protector(m_frame->view());
2438 FrameView* view = m_frame->view();
2441 setFrameWasScrolledByUser();
2442 LayoutPoint vPoint = view->windowToContents(e.position());
2447 HitTestRequest request(HitTestRequest::ReadOnly);
2448 HitTestResult result(vPoint);
2449 doc->renderView()->hitTest(request, result);
2452 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2455 if (m_useLatchedWheelEventNode) {
2456 if (!m_latchedWheelEventNode) {
2457 m_latchedWheelEventNode = result.innerNode();
2458 m_widgetIsLatched = result.isOverWidget();
2461 node = m_latchedWheelEventNode.get();
2462 isOverWidget = m_widgetIsLatched;
2464 if (m_latchedWheelEventNode)
2465 m_latchedWheelEventNode = 0;
2466 if (m_previousWheelScrolledNode)
2467 m_previousWheelScrolledNode = 0;
2469 node = result.innerNode();
2470 isOverWidget = result.isOverWidget();
2473 // FIXME: It should not be necessary to do this mutation here.
2474 // Instead, the handlers should know convert vertical scrolls
2476 PlatformWheelEvent event = e;
2477 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2478 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2481 // Figure out which view to send the event to.
2482 RenderObject* target = node->renderer();
2484 if (isOverWidget && target && target->isWidget()) {
2485 Widget* widget = toRenderWidget(target)->widget();
2486 if (widget && passWheelEventToWidget(e, widget))
2490 if (node && !node->dispatchWheelEvent(event))
2495 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2496 view = m_frame->view();
2500 return view->wheelEvent(event);
2503 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2505 if (!startNode || !wheelEvent)
2508 Node* stopNode = m_previousWheelScrolledNode.get();
2509 ScrollGranularity granularity = m_baseEventType == PlatformEvent::GestureScrollEnd ? ScrollByPixelVelocity : wheelGranularityToScrollGranularity(wheelEvent->granularity());
2511 // Break up into two scrolls if we need to. Diagonal movement on
2512 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2513 if (scrollNode(wheelEvent->rawDeltaX(), granularity, ScrollLeft, ScrollRight, startNode, &stopNode))
2514 wheelEvent->setDefaultHandled();
2516 if (scrollNode(wheelEvent->rawDeltaY(), granularity, ScrollUp, ScrollDown, startNode, &stopNode))
2517 wheelEvent->setDefaultHandled();
2519 if (!m_useLatchedWheelEventNode)
2520 m_previousWheelScrolledNode = stopNode;
2523 #if ENABLE(GESTURE_EVENTS)
2524 bool EventHandler::handleGestureTapDown()
2526 FrameView* view = m_frame->view();
2529 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2530 scrollAnimator->cancelAnimations();
2531 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2534 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2535 ScrollableArea* sa = *it;
2536 ScrollAnimator* animator = sa->scrollAnimator();
2538 animator->cancelAnimations();
2543 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2545 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2546 // eliminate the need for this.
2547 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2549 switch (gestureEvent.type()) {
2550 case PlatformEvent::GestureScrollBegin:
2551 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, false);
2552 case PlatformEvent::GestureScrollEnd:
2553 return handleGestureScrollCore(gestureEvent, ScrollByPixelVelocityWheelEvent, true);
2554 case PlatformEvent::GestureScrollUpdate:
2555 return handleGestureScrollUpdate(gestureEvent);
2556 case PlatformEvent::GestureTap:
2557 return handleGestureTap(gestureEvent);
2558 case PlatformEvent::GestureTapDown:
2559 return handleGestureTapDown();
2560 case PlatformEvent::GestureDoubleTap:
2561 case PlatformEvent::GestureLongPress:
2562 case PlatformEvent::GesturePinchBegin:
2563 case PlatformEvent::GesturePinchEnd:
2564 case PlatformEvent::GesturePinchUpdate:
2567 ASSERT_NOT_REACHED();
2573 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent)
2575 // FIXME: Refactor this code to not hit test multiple times. We use the adjusted position to ensure that the correct node is targeted by the later redundant hit tests.
2576 IntPoint adjustedPoint = gestureEvent.position();
2577 #if ENABLE(TOUCH_ADJUSTMENT)
2578 if (!gestureEvent.area().isEmpty())
2579 adjustGesturePosition(gestureEvent, adjustedPoint);
2582 bool defaultPrevented = false;
2583 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2584 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2585 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2586 mouseMoved(fakeMouseMove);
2587 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2588 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2589 return defaultPrevented;
2592 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2594 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, true);
2597 bool EventHandler::handleGestureScrollCore(const PlatformGestureEvent& gestureEvent, PlatformWheelEventGranularity granularity, bool latchedWheel)
2599 TemporaryChange<bool> latched(m_useLatchedWheelEventNode, latchedWheel);
2600 const float tickDivisor = (float)WheelEvent::tickMultiplier;
2601 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2602 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2603 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2604 gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor,
2606 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2607 return handleWheelEvent(syntheticWheelEvent);
2611 #if ENABLE(TOUCH_ADJUSTMENT)
2612 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2614 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2615 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2616 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2618 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2619 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2621 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2622 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2623 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2624 // handle targetNode being a shadow DOM node.
2625 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2626 if (success && targetNode)
2627 targetNode = targetNode->shadowAncestorNode();
2631 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2633 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2634 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2635 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2637 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2638 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2639 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2642 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2644 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2645 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2646 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2648 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2649 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2650 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get());
2653 bool EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2655 Node* targetNode = 0;
2656 switch (gestureEvent.type()) {
2657 case PlatformEvent::GestureTap:
2658 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2660 case PlatformEvent::GestureLongPress:
2661 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2664 // FIXME: Implement handling for other types as needed.
2665 ASSERT_NOT_REACHED();
2671 #if ENABLE(CONTEXT_MENUS)
2672 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2674 Document* doc = m_frame->document();
2675 FrameView* v = m_frame->view();
2680 LayoutPoint viewportPos = v->windowToContents(event.position());
2681 HitTestRequest request(HitTestRequest::Active);
2682 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2684 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2685 && !m_frame->selection()->contains(viewportPos)
2686 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2687 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2688 // available for text selections. But only if we're above text.
2689 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2690 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2691 selectClosestWordOrLinkFromMouseEvent(mev);
2694 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2696 return swallowEvent;
2699 bool EventHandler::sendContextMenuEventForKey()
2701 FrameView* view = m_frame->view();
2705 Document* doc = m_frame->document();
2709 static const int kContextMenuMargin = 1;
2711 #if OS(WINDOWS) && !OS(WINCE)
2712 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2714 int rightAligned = 0;
2718 Node* focusedNode = doc->focusedNode();
2719 FrameSelection* selection = m_frame->selection();
2720 Position start = selection->selection().start();
2722 if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) {
2723 RefPtr<Range> selectionRange = selection->toNormalizedRange();
2724 IntRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get());
2726 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2727 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2728 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2729 location = IntPoint(x, y);
2730 } else if (focusedNode) {
2731 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2734 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2735 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2737 location = IntPoint(
2738 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2739 kContextMenuMargin);
2742 m_frame->view()->setCursor(pointerCursor());
2744 IntPoint position = view->contentsToRootView(location);
2745 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2747 Node* targetNode = doc->focusedNode();
2751 // Use the focused node as the target for hover and active.
2752 HitTestResult result(position);
2753 result.setInnerNode(targetNode);
2754 HitTestRequest request(HitTestRequest::Active);
2755 doc->renderView()->layer()->updateHoverActiveState(request, result);
2756 doc->updateStyleIfNeeded();
2758 // The contextmenu event is a mouse event even when invoked using the keyboard.
2759 // This is required for web compatibility.
2762 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2764 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2767 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2769 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2772 #if ENABLE(GESTURE_EVENTS)
2773 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2776 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2778 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2781 IntPoint adjustedPoint = event.position();
2782 #if ENABLE(TOUCH_ADJUSTMENT)
2783 if (!event.area().isEmpty())
2784 adjustGesturePosition(event, adjustedPoint);
2786 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2787 return sendContextMenuEvent(mouseEvent);
2789 #endif // ENABLE(GESTURE_EVENTS)
2790 #endif // ENABLE(CONTEXT_MENUS)
2792 void EventHandler::scheduleHoverStateUpdate()
2794 if (!m_hoverTimer.isActive())
2795 m_hoverTimer.startOneShot(0);
2798 void EventHandler::dispatchFakeMouseMoveEventSoon()
2803 Settings* settings = m_frame->settings();
2804 if (settings && !settings->deviceSupportsMouse())
2807 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2808 // reschedule the timer and use a longer time. This will cause the content
2809 // to receive these moves only after the user is done scrolling, reducing
2810 // pauses during the scroll.
2811 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2812 if (m_fakeMouseMoveEventTimer.isActive())
2813 m_fakeMouseMoveEventTimer.stop();
2814 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2816 if (!m_fakeMouseMoveEventTimer.isActive())
2817 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2821 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2823 FrameView* view = m_frame->view();
2827 if (!quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2830 dispatchFakeMouseMoveEventSoon();
2833 void EventHandler::cancelFakeMouseMoveEvent()
2835 m_fakeMouseMoveEventTimer.stop();
2838 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2840 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2841 ASSERT(!m_mousePressed);
2843 Settings* settings = m_frame->settings();
2844 if (settings && !settings->deviceSupportsMouse())
2847 FrameView* view = m_frame->view();
2855 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2856 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, m_currentMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2857 mouseMoved(fakeMouseMoveEvent);
2860 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2862 m_frameSetBeingResized = frameSet;
2865 void EventHandler::resizeLayerDestroyed()
2867 ASSERT(m_resizeLayer);
2871 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2873 m_hoverTimer.stop();
2876 ASSERT(m_frame->document());
2878 if (RenderView* renderer = m_frame->contentRenderer()) {
2879 if (FrameView* view = m_frame->view()) {
2880 HitTestRequest request(HitTestRequest::Move);
2881 HitTestResult result(view->windowToContents(m_currentMousePosition));
2882 renderer->hitTest(request, result);
2883 m_frame->document()->updateStyleIfNeeded();
2888 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2890 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2891 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2892 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2893 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2894 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2895 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2897 String key = evt.unmodifiedText();
2898 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2901 elem->accessKeyAction(false);
2906 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2912 #if ENABLE(FULLSCREEN_API)
2913 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2915 Document* document = m_frame->document();
2916 if (document->webkitFullScreenKeyboardInputAllowed())
2919 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2920 if (keyEvent.text().length() != 1)
2922 UChar character = keyEvent.text()[0];
2923 return character == ' ';
2926 int keyCode = keyEvent.windowsVirtualKeyCode();
2927 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2928 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2929 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2930 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2934 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2936 RefPtr<FrameView> protector(m_frame->view());
2938 #if ENABLE(FULLSCREEN_API)
2939 if (m_frame->document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
2943 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2944 capsLockStateMayHaveChanged();
2946 #if ENABLE(PAN_SCROLLING)
2947 if (Page* page = m_frame->page()) {
2948 if (page->mainFrame()->eventHandler()->m_panScrollInProgress) {
2949 // If a key is pressed while the panScroll is in progress then we want to stop
2950 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2951 stopAutoscrollTimer();
2953 // If we were in panscroll mode, we swallow the key event
2959 // Check for cases where we are too early for events -- possible unmatched key up
2960 // from pressing return in the location bar.
2961 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2965 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2966 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2968 if (FrameView* view = m_frame->view())
2969 view->resetDeferredRepaintDelay();
2971 // FIXME (bug 68185): this call should be made at another abstraction layer
2972 m_frame->loader()->resetMultipleFormSubmissionProtection();
2974 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2975 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2976 // with access keys. Then we dispatch keydown, but suppress its default handling.
2977 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2978 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2979 bool matchedAnAccessKey = false;
2980 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2981 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2983 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2984 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2985 return !node->dispatchKeyEvent(initialKeyEvent);
2987 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2990 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2991 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2992 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
2993 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2994 if (matchedAnAccessKey)
2995 keydown->setDefaultPrevented(true);
2996 keydown->setTarget(node);
2998 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2999 node->dispatchEvent(keydown, ec);
3000 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3001 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3002 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3005 // Run input method in advance of DOM event handling. This may result in the IM
3006 // modifying the page prior the keydown event, but this behaviour is necessary
3007 // in order to match IE:
3008 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3009 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3010 m_frame->editor()->handleInputMethodKeydown(keydown.get());
3012 bool handledByInputMethod = keydown->defaultHandled();
3014 if (handledByInputMethod) {
3015 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3016 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
3017 keydown->setTarget(node);
3018 keydown->setDefaultHandled();
3021 node->dispatchEvent(keydown, ec);
3022 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3023 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3024 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3025 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3026 return keydownResult;
3028 // Focus may have changed during keydown handling, so refetch node.
3029 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3030 if (!keydownResult) {
3031 node = eventTargetNodeForDocument(m_frame->document());
3036 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3037 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3038 if (keyPressEvent.text().isEmpty())
3039 return keydownResult;
3040 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
3041 keypress->setTarget(node);
3043 keypress->setDefaultPrevented(true);
3045 keypress->keypressCommands() = keydown->keypressCommands();
3047 node->dispatchEvent(keypress, ec);
3049 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3052 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3054 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
3055 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
3056 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
3057 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
3059 FocusDirection retVal = FocusDirectionNone;
3061 if (keyIdentifier == Down)
3062 retVal = FocusDirectionDown;
3063 else if (keyIdentifier == Up)
3064 retVal = FocusDirectionUp;
3065 else if (keyIdentifier == Left)
3066 retVal = FocusDirectionLeft;
3067 else if (keyIdentifier == Right)
3068 retVal = FocusDirectionRight;
3073 static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardEvent* event)
3078 bool isOptioned = event->getModifierState("Alt");
3079 bool isCommanded = event->getModifierState("Meta");
3081 SelectionDirection direction = DirectionForward;
3082 TextGranularity granularity = CharacterGranularity;
3084 switch (focusDirectionForKey(event->keyIdentifier())) {
3085 case FocusDirectionNone:
3087 case FocusDirectionForward:
3088 case FocusDirectionBackward:
3089 ASSERT_NOT_REACHED();
3091 case FocusDirectionUp:
3092 direction = DirectionBackward;
3093 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3095 case FocusDirectionDown:
3096 direction = DirectionForward;
3097 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3099 case FocusDirectionLeft:
3100 direction = DirectionLeft;
3101 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3103 case FocusDirectionRight:
3104 direction = DirectionRight;
3105 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3109 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3110 selection->modify(alternation, direction, granularity, UserTriggered);
3111 event->setDefaultHandled();
3114 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3116 if (event->type() == eventNames().keydownEvent) {
3117 m_frame->editor()->handleKeyboardEvent(event);
3118 if (event->defaultHandled())
3120 if (event->keyIdentifier() == "U+0009")
3121 defaultTabEventHandler(event);
3122 else if (event->keyIdentifier() == "U+0008")
3123 defaultBackspaceEventHandler(event);
3125 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3126 if (direction != FocusDirectionNone)
3127 defaultArrowEventHandler(direction, event);
3130 // provides KB navigation and selection for enhanced accessibility users
3131 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3132 handleKeyboardSelectionMovement(m_frame->selection(), event);
3134 if (event->type() == eventNames().keypressEvent) {
3135 m_frame->editor()->handleKeyboardEvent(event);
3136 if (event->defaultHandled())
3138 if (event->charCode() == ' ')
3139 defaultSpaceEventHandler(event);
3143 #if ENABLE(DRAG_SUPPORT)
3144 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3146 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3147 return dragHysteresisExceeded(dragViewportLocation);
3150 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3152 FrameView* view = m_frame->view();
3155 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3156 IntSize delta = dragLocation - m_mouseDownPos;
3158 int threshold = GeneralDragHysteresis;
3159 switch (dragState().m_dragType) {
3160 case DragSourceActionSelection:
3161 threshold = TextDragHysteresis;
3163 case DragSourceActionImage:
3164 threshold = ImageDragHysteresis;
3166 case DragSourceActionLink:
3167 threshold = LinkDragHysteresis;
3169 case DragSourceActionDHTML:
3171 case DragSourceActionNone:
3172 case DragSourceActionAny:
3173 ASSERT_NOT_REACHED();
3176 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3179 void EventHandler::freeClipboard()
3181 if (dragState().m_dragClipboard)
3182 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3185 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3187 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3188 HitTestRequest request(HitTestRequest::Release);
3189 prepareMouseEvent(request, event);
3191 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
3192 dragState().m_dragClipboard->setDestinationOperation(operation);
3193 // for now we don't care if event handler cancels default behavior, since there is none
3194 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3197 dragState().m_dragSrc = 0;
3198 // In case the drag was ended due to an escape key press we need to ensure
3199 // that consecutive mousemove events don't reinitiate the drag and drop.
3200 m_mouseDownMayStartDrag = false;
3203 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3205 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3206 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3207 dragState().m_dragSrc = rootEditableElement;
3210 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3211 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3213 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3216 static bool ExactlyOneBitSet(DragSourceAction n)
3218 return n && !(n & (n - 1));
3221 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
3223 #if ENABLE(TIZEN_DRAG_SUPPORT)
3224 if (!m_frame->page()->dragController()->dragState())
3227 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3228 // If we allowed the other side of the bridge to handle a drag
3229 // last time, then m_mousePressed might still be set. So we
3230 // clear it now to make sure the next move after a drag
3231 // doesn't look like a drag.
3232 m_mousePressed = false;
3237 if (eventLoopHandleMouseDragged(event))
3240 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3242 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
3243 dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents;
3245 // try to find an element that wants to be dragged
3246 HitTestRequest request(HitTestRequest::ReadOnly);
3247 HitTestResult result(m_mouseDownPos);
3248 m_frame->contentRenderer()->hitTest(request, result);
3249 Node* node = result.innerNode();
3250 if (node && m_frame->page())
3251 dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState());
3253 dragState().m_dragSrc = 0;
3255 if (!dragState().m_dragSrc)
3256 m_mouseDownMayStartDrag = false; // no element is draggable
3258 m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection);
3261 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3262 // or else we bail on the dragging stuff and allow selection to occur
3263 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3264 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3265 if ((dragState().m_dragType & DragSourceActionImage)) {
3266 // ... unless the mouse is over an image, then we start dragging just the image
3267 dragState().m_dragType = DragSourceActionImage;
3268 } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) {
3269 // ... but only bail if we're not over an unselectable element.
3270 m_mouseDownMayStartDrag = false;
3271 dragState().m_dragSrc = 0;
3272 // ... but if this was the first click in the window, we don't even want to start selection
3273 if (eventActivatedView(event.event()))
3274 m_mouseDownMayStartSelect = false;
3276 // Prevent the following case from occuring:
3277 // 1. User starts a drag immediately after mouse down over an unselectable element.
3278 // 2. We enter this block and decided that since we're over an unselectable element,
3279 // don't cancel the drag.
3280 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't
3281 // exceeded the drag hysteresis yet.
3282 // 4. We enter this block again, and since it's now marked as a selection drag, we
3284 m_dragMayStartSelectionInstead = false;
3288 if (!m_mouseDownMayStartDrag)
3289 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3291 if (!ExactlyOneBitSet(dragState().m_dragType)) {
3292 ASSERT((dragState().m_dragType & DragSourceActionSelection));
3293 ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML
3294 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage
3295 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink);
3296 dragState().m_dragType = DragSourceActionSelection;
3299 // We are starting a text/image/url drag, so the cursor should be an arrow
3300 if (FrameView* view = m_frame->view()) {
3301 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3302 view->setCursor(pointerCursor());
3305 if (!dragHysteresisExceeded(event.event().position()))
3308 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3311 DragOperation srcOp = DragOperationNone;
3313 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3314 // to make sure it gets numbified
3315 dragState().m_dragClipboard = createDraggingClipboard();
3317 if (dragState().shouldDispatchEvents()) {
3318 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
3320 if (dragState().m_dragType == DragSourceActionDHTML) {
3321 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3322 // FIXME: This doesn't work correctly with transforms.
3323 FloatPoint absPos = renderer->localToAbsolute();
3324 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3325 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
3327 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3328 // the element in some way. In this case we just kill the drag.
3329 m_mouseDownMayStartDrag = false;
3334 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3335 && !m_frame->selection()->isInPasswordField();
3337 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3338 // image can still be changed as we drag, but not the pasteboard data.
3339 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3341 if (m_mouseDownMayStartDrag) {
3342 // gather values from DHTML element, if it set any
3343 srcOp = dragState().m_dragClipboard->sourceOperation();
3345 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3346 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3347 // started the drag when that happens. So we have to assume it's started before we
3349 dragState().m_dragClipboard->setDragHasStarted();
3353 if (m_mouseDownMayStartDrag) {
3354 Page* page = m_frame->page();
3355 DragController* dragController = page ? page->dragController() : 0;
3356 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3357 // In WebKit2 we could reenter this code and start another drag.
3358 // On OS X this causes problems with the ownership of the pasteboard
3359 // and the promised types.
3361 m_mouseDownMayStartDrag = false;
3364 if (dragState().shouldDispatchEvents()) {
3365 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3366 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3367 m_mouseDownMayStartDrag = false;
3372 if (!m_mouseDownMayStartDrag) {
3373 // something failed to start the drag, cleanup
3375 dragState().m_dragSrc = 0;
3378 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3381 #endif // ENABLE(DRAG_SUPPORT)
3383 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3385 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3386 // and avoid dispatching text input events from keydown default handlers.
3387 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
3392 EventTarget* target;
3393 if (underlyingEvent)
3394 target = underlyingEvent->target();
3396 target = eventTargetNodeForDocument(m_frame->document());
3400 if (FrameView* view = m_frame->view())
3401 view->resetDeferredRepaintDelay();
3403 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3404 event->setUnderlyingEvent(underlyingEvent);
3407 target->dispatchEvent(event, ec);
3408 return event->defaultHandled();
3411 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3414 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3416 && event->keyIdentifier() == "U+0009";
3419 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3421 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(EFL)
3422 return EventHandler::isKeyboardOptionTab(event);
3428 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3430 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3432 Page* page = m_frame->page();
3436 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
3437 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3440 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3442 if (m_frame->editor()->handleTextEvent(event))
3443 event->setDefaultHandled();
3447 // Qt handles the space event in platform-specific WebKit code.
3448 // Eventually it would be good to eliminate that and use the code here instead.
3449 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
3454 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3456 ASSERT(event->type() == eventNames().keypressEvent);
3458 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3461 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3462 if (logicalScrollOverflow(direction, ScrollByPage)) {
3463 event->setDefaultHandled();
3467 FrameView* view = m_frame->view();
3471 if (view->logicalScroll(direction, ScrollByPage))
3472 event->setDefaultHandled();
3477 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3479 ASSERT(event->type() == eventNames().keydownEvent);
3481 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3484 if (!m_frame->editor()->behavior().shouldNavigateBackOnBackspace())
3487 Page* page = m_frame->page();
3491 if (!m_frame->settings()->backspaceKeyNavigationEnabled())
3494 bool handledEvent = false;
3496 if (event->shiftKey())
3497 handledEvent = page->goForward();
3499 handledEvent = page->goBack();
3502 event->setDefaultHandled();
3506 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3508 ASSERT(event->type() == eventNames().keydownEvent);
3510 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3513 Page* page = m_frame->page();
3517 if (!isSpatialNavigationEnabled(m_frame))
3520 // Arrows and other possible directional navigation keys can be used in design
3522 if (m_frame->document()->inDesignMode())
3525 if (page->focusController()->advanceFocus(focusDirection, event))
3526 event->setDefaultHandled();
3529 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3531 ASSERT(event->type() == eventNames().keydownEvent);
3533 // We should only advance focus on tabs if no special modifier keys are held down.
3534 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3537 Page* page = m_frame->page();
3540 if (!page->tabKeyCyclesThroughElements())
3543 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3545 // Tabs can be used in design mode editing.
3546 if (m_frame->document()->inDesignMode())
3549 if (page->focusController()->advanceFocus(focusDirection, event))
3550 event->setDefaultHandled();
3553 void EventHandler::capsLockStateMayHaveChanged()
3555 Document* d = m_frame->document();
3556 if (Node* node = d->focusedNode()) {
3557 if (RenderObject* r = node->renderer()) {
3558 if (r->isTextField())
3559 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3564 void EventHandler::sendResizeEvent()
3566 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
3569 void EventHandler::sendScrollEvent()
3571 setFrameWasScrolledByUser();
3572 if (m_frame->view() && m_frame->document())
3573 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), DocumentEventQueue::ScrollEventDocumentTarget);
3576 void EventHandler::setFrameWasScrolledByUser()
3578 FrameView* v = m_frame->view();
3580 v->setWasScrolledByUser(true);
3583 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3585 if (!scrollbar || !scrollbar->enabled())
3587 setFrameWasScrolledByUser();
3588 return scrollbar->mouseDown(mev.event());
3591 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3592 // last to scrollbar if setLast is true; else set last to 0.
3593 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3595 if (m_lastScrollbarUnderMouse != scrollbar) {
3596 // Send mouse exited to the old scrollbar.
3597 if (m_lastScrollbarUnderMouse)
3598 m_lastScrollbarUnderMouse->mouseExited();
3600 // Send mouse entered if we're setting a new scrollbar.
3601 if (scrollbar && setLast)
3602 scrollbar->mouseEntered();
3604 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3608 #if ENABLE(TOUCH_EVENTS)
3610 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3613 case PlatformTouchPoint::TouchReleased:
3614 return eventNames().touchendEvent;
3615 case PlatformTouchPoint::TouchCancelled:
3616 return eventNames().touchcancelEvent;
3617 case PlatformTouchPoint::TouchPressed:
3618 return eventNames().touchstartEvent;
3619 case PlatformTouchPoint::TouchMoved:
3620 return eventNames().touchmoveEvent;
3621 case PlatformTouchPoint::TouchStationary:
3622 // TouchStationary state is not converted to touch events, so fall through to assert.
3624 ASSERT_NOT_REACHED();
3629 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3631 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3632 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3633 // for an overview of how these lists fit together.
3635 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3636 RefPtr<TouchList> touches = TouchList::create();
3638 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3639 // 'targetTouches' list in the JS event.
3640 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3641 TargetTouchesMap touchesByTarget;
3643 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3644 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3646 // The touches corresponding to the particular change state this struct instance represents.
3647 RefPtr<TouchList> m_touches;
3648 // Set of targets involved in m_touches.
3649 EventTargetSet m_targets;
3650 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3652 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3654 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3656 for (unsigned i = 0; i < points.size(); ++i) {
3657 const PlatformTouchPoint& point = points[i];
3658 PlatformTouchPoint::State pointState = point.state();
3659 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3661 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3662 // The HitTestRequest types used for mouse events map quite adequately
3663 // to touch events. Note that in addition to meaning that the hit test
3664 // should affect the active state of the current node if necessary,
3665 // HitTestRequest::Active signifies that the hit test is taking place
3666 // with the mouse (or finger in this case) being pressed.
3667 switch (pointState) {
3668 case PlatformTouchPoint::TouchPressed:
3669 hitType |= HitTestRequest::Active;
3671 case PlatformTouchPoint::TouchMoved:
3672 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3674 case PlatformTouchPoint::TouchReleased:
3675 case PlatformTouchPoint::TouchCancelled:
3676 hitType |= HitTestRequest::Release;
3678 case PlatformTouchPoint::TouchStationary:
3679 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3682 ASSERT_NOT_REACHED();
3686 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3687 unsigned touchPointTargetKey = point.id() + 1;
3688 RefPtr<EventTarget> touchTarget;
3689 if (pointState == PlatformTouchPoint::TouchPressed) {
3690 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3691 Node* node = result.innerNode();
3694 #if ENABLE(TIZEN_PREVENT_CRASH_OF_TOUCH_EVENTS)
3699 // Touch events should not go to text nodes
3700 if (node->isTextNode())
3701 node = node->parentNode();
3703 Document* doc = node->document();
3707 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3710 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3712 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3713 // We only perform a hittest on release or cancel to unset :active or :hover state.
3714 hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3715 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3716 // we also remove it from the map.
3717 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3719 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3720 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3722 if (!touchTarget.get())
3724 Document* doc = touchTarget->toNode()->document();
3727 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3729 Frame* targetFrame = doc->frame();
3733 if (m_frame != targetFrame) {
3734 // pagePoint should always be relative to the target elements containing frame.
3735 pagePoint = documentPointForWindowPoint(targetFrame, point.pos());
3738 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor();
3740 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3741 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3743 RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3744 point.screenPos().x(), point.screenPos().y(),
3745 adjustedPageX, adjustedPageY,
3746 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3748 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3749 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3750 if (targetTouchesIterator == touchesByTarget.end())
3751 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3753 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3754 // released or cancelled it will only appear in the changedTouches list.
3755 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3756 touches->append(touch);
3757 targetTouchesIterator->second->append(touch);
3760 // Now build up the correct list for changedTouches.
3761 // Note that any touches that are in the TouchStationary state (e.g. if
3762 // the user had several points touched but did not move them all) should
3763 // never be in the changedTouches list so we do not handle them explicitly here.
3764 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3765 // about the TouchStationary state.
3766 if (pointState != PlatformTouchPoint::TouchStationary) {
3767 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3768 if (!changedTouches[pointState].m_touches)
3769 changedTouches[pointState].m_touches = TouchList::create();
3770 changedTouches[pointState].m_touches->append(touch);
3771 changedTouches[pointState].m_targets.add(touchTarget);
3774 m_touchPressed = touches->length() > 0;
3776 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3777 bool swallowedEvent = false;
3778 RefPtr<TouchList> emptyList = TouchList::create();
3779 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3780 if (!changedTouches[state].m_touches)
3783 // When sending a touch cancel event, use empty touches and targetTouches lists.
3784 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3785 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3786 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3787 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3789 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3790 EventTarget* touchEventTarget = it->get();
3791 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3792 ASSERT(targetTouches);
3794 RefPtr<TouchEvent> touchEvent =
3795 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3796 stateName, touchEventTarget->toNode()->document()->defaultView(),
3797 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3798 ExceptionCode ec = 0;
3799 touchEventTarget->dispatchEvent(touchEvent.get(), ec);
3800 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3804 return swallowedEvent;
3807 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
3809 if (!m_frame || !m_frame->settings() || !m_frame->settings()->isTouchEventEmulationEnabled())
3812 PlatformEvent::Type eventType = event.type();
3813 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
3816 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
3819 SyntheticSingleTouchEvent touchEvent(event);
3820 return handleTouchEvent(touchEvent);