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"
116 #if ENABLE(TIZEN_ISF_PORT)
117 #include "EditorClient.h"
122 using namespace HTMLNames;
124 #if ENABLE(DRAG_SUPPORT)
125 // The link drag hysteresis is much larger than the others because there
126 // needs to be enough space to cancel the link press without starting a link drag,
127 // and because dragging links is rare.
128 const int LinkDragHysteresis = 40;
129 const int ImageDragHysteresis = 5;
130 const int TextDragHysteresis = 3;
131 const int GeneralDragHysteresis = 3;
132 #endif // ENABLE(DRAG_SUPPORT)
134 // Match key code of composition keydown event on windows.
135 // IE sends VK_PROCESSKEY which has value 229;
136 const int CompositionEventKeyCode = 229;
139 using namespace SVGNames;
142 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
143 const double autoscrollInterval = 0.05;
145 // The amount of time to wait before sending a fake mouse event, triggered
146 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
147 // otherwise the long interval is used.
148 const double fakeMouseMoveShortInterval = 0.1;
149 const double fakeMouseMoveLongInterval = 0.250;
151 enum NoCursorChangeType { NoCursorChange };
153 class OptionalCursor {
155 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
156 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
158 bool isCursorChange() const { return m_isCursorChange; }
159 const Cursor& cursor() const { return m_cursor; }
162 bool m_isCursorChange;
166 class MaximumDurationTracker {
168 explicit MaximumDurationTracker(double *maxDuration)
169 : m_maxDuration(maxDuration)
170 , m_start(monotonicallyIncreasingTime())
174 ~MaximumDurationTracker()
176 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
180 double* m_maxDuration;
184 #if ENABLE(TOUCH_EVENTS)
185 class SyntheticTouchPoint : public PlatformTouchPoint {
188 // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
189 explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
191 const static int idDefaultValue = 0;
192 const static int radiusYDefaultValue = 1;
193 const static int radiusXDefaultValue = 1;
194 const static float rotationAngleDefaultValue = 0.0f;
195 const static float forceDefaultValue = 1.0f;
197 m_id = idDefaultValue; // There is only one active TouchPoint.
198 m_screenPos = event.globalPosition();
199 m_pos = event.position();
200 m_radiusY = radiusYDefaultValue;
201 m_radiusX = radiusXDefaultValue;
202 m_rotationAngle = rotationAngleDefaultValue;
203 m_force = forceDefaultValue;
205 PlatformEvent::Type type = event.type();
206 ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
209 case PlatformEvent::MouseMoved:
210 m_state = TouchMoved;
212 case PlatformEvent::MousePressed:
213 m_state = TouchPressed;
215 case PlatformEvent::MouseReleased:
216 m_state = TouchReleased;
219 ASSERT_NOT_REACHED();
225 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
227 explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
229 switch (event.type()) {
230 case PlatformEvent::MouseMoved:
233 case PlatformEvent::MousePressed:
236 case PlatformEvent::MouseReleased:
240 ASSERT_NOT_REACHED();
244 m_timestamp = event.timestamp();
245 m_modifiers = event.modifiers();
246 m_touchPoints.append(SyntheticTouchPoint(event));
251 static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent::Granularity granularity)
253 switch (granularity) {
254 case WheelEvent::Page:
256 case WheelEvent::Line:
258 case WheelEvent::Pixel:
259 return ScrollByPixel;
261 return ScrollByPixel;
264 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
268 if (!node->renderer())
270 RenderBox* enclosingBox = node->renderer()->enclosingBox();
271 float absDelta = delta > 0 ? delta : -delta;
272 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode);
277 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
282 #if ENABLE(DRAG_SUPPORT)
283 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
291 EventHandler::EventHandler(Frame* frame)
293 , m_mousePressed(false)
294 , m_capturesDragging(false)
295 , m_mouseDownMayStartSelect(false)
296 #if ENABLE(DRAG_SUPPORT)
297 , m_mouseDownMayStartDrag(false)
298 , m_dragMayStartSelectionInstead(false)
300 , m_mouseDownWasSingleClickInSelection(false)
301 , m_selectionInitiationState(HaveNotStartedSelection)
302 , m_panScrollInProgress(false)
303 , m_panScrollButtonPressed(false)
304 , m_springLoadedPanScrollInProgress(false)
305 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
306 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
307 , m_autoscrollRenderer(0)
308 , m_autoscrollInProgress(false)
309 , m_mouseDownMayStartAutoscroll(false)
310 , m_mouseDownWasInSubframe(false)
311 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
316 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
318 , m_mouseDownTimestamp(0)
319 , m_useLatchedWheelEventNode(false)
320 , m_widgetIsLatched(false)
322 , m_mouseDownView(nil)
323 , m_sendingEventToSubview(false)
324 , m_activationEventNumber(-1)
326 #if ENABLE(TOUCH_EVENTS)
327 , m_touchPressed(false)
329 , m_maxMouseMovedDuration(0)
330 , m_baseEventType(PlatformEvent::NoType)
334 EventHandler::~EventHandler()
336 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
339 #if ENABLE(DRAG_SUPPORT)
340 DragState& EventHandler::dragState()
342 DEFINE_STATIC_LOCAL(DragState, state, ());
345 #endif // ENABLE(DRAG_SUPPORT)
347 void EventHandler::clear()
350 m_fakeMouseMoveEventTimer.stop();
352 m_nodeUnderMouse = 0;
353 m_lastNodeUnderMouse = 0;
355 m_instanceUnderMouse = 0;
356 m_lastInstanceUnderMouse = 0;
358 m_lastMouseMoveEventSubframe = 0;
359 m_lastScrollbarUnderMouse = 0;
362 m_frameSetBeingResized = 0;
363 #if ENABLE(DRAG_SUPPORT)
365 m_shouldOnlyFireDragOverEvent = false;
367 m_currentMousePosition = IntPoint();
368 m_currentMouseGlobalPosition = IntPoint();
369 m_mousePressNode = 0;
370 m_mousePressed = false;
371 m_capturesDragging = false;
372 m_capturingMouseEventsNode = 0;
373 m_latchedWheelEventNode = 0;
374 m_previousWheelScrolledNode = 0;
375 #if ENABLE(TOUCH_EVENTS)
376 m_originatingTouchPointTargets.clear();
378 m_maxMouseMovedDuration = 0;
379 #if ENABLE(GESTURE_EVENTS)
380 m_baseEventType = PlatformEvent::NoType;
384 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
386 if (nodeToBeRemoved->contains(m_clickNode.get()))
390 static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
393 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
394 selection->setSelection(newSelection);
397 static inline bool dispatchSelectStart(Node* node)
399 if (!node || !node->renderer())
402 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
405 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity)
407 if (Position::nodeIsUserSelectNone(targetNode))
410 if (!dispatchSelectStart(targetNode))
413 if (newSelection.isRange())
414 m_selectionInitiationState = ExtendedSelection;
416 granularity = CharacterGranularity;
417 m_selectionInitiationState = PlacedCaret;
420 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, granularity);
425 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
427 Node* innerNode = targetNode(result);
428 VisibleSelection newSelection;
430 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
431 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
432 if (pos.isNotNull()) {
433 newSelection = VisibleSelection(pos);
434 newSelection.expandUsingGranularity(WordGranularity);
437 if (newSelection.isRange() && result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
438 newSelection.appendTrailingWhitespace();
440 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
444 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
446 if (!result.hitTestResult().isLiveLink())
447 return selectClosestWordFromMouseEvent(result);
449 Node* innerNode = targetNode(result);
451 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
452 VisibleSelection newSelection;
453 Element* URLElement = result.hitTestResult().URLElement();
454 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
455 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
456 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
458 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
462 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
464 if (event.event().button() != LeftButton)
467 if (m_frame->selection()->isRange())
468 // A double-click when range is already selected
469 // should not change the selection. So, do not call
470 // selectClosestWordFromMouseEvent, but do set
471 // m_beganSelectingText to prevent handleMouseReleaseEvent
472 // from setting caret selection.
473 m_selectionInitiationState = ExtendedSelection;
475 selectClosestWordFromMouseEvent(event);
480 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
482 if (event.event().button() != LeftButton)
485 Node* innerNode = targetNode(event);
486 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
489 VisibleSelection newSelection;
490 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
491 if (pos.isNotNull()) {
492 newSelection = VisibleSelection(pos);
493 newSelection.expandUsingGranularity(ParagraphGranularity);
496 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity);
499 static int textDistance(const Position& start, const Position& end)
501 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
502 return TextIterator::rangeLength(range.get(), true);
505 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
507 m_frame->document()->updateLayoutIgnorePendingStylesheets();
508 Node* innerNode = targetNode(event);
510 #if ENABLE(TIZEN_LINK_EFFECT)
511 Node* node = innerNode;
512 RenderObject* renderer;
514 && (renderer = node->renderer())
515 && (!renderer->isRoot())) {
517 || node->hasTagName(HTMLNames::aTag)
518 || node->hasTagName(HTMLNames::inputTag)
519 || (!node->hasTagName(HTMLNames::bodyTag) && node->isHTMLElement() && toHTMLElement(node)->hasAttribute(onclickAttr))) {
520 TizenLinkEffect::playLinkEffect();
523 node = node->parentNode();
527 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
530 // Extend the selection if the Shift key is down, unless the click is in a link.
531 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
533 // Don't restart the selection when the mouse is pressed on an
534 // existing selection so we can allow for text dragging.
535 if (FrameView* view = m_frame->view()) {
536 LayoutPoint vPoint = view->windowToContents(event.event().position());
537 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
538 m_mouseDownWasSingleClickInSelection = true;
543 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
544 if (visiblePos.isNull())
545 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
546 Position pos = visiblePos.deepEquivalent();
548 VisibleSelection newSelection = m_frame->selection()->selection();
549 TextGranularity granularity = CharacterGranularity;
551 if (extendSelection && newSelection.isCaretOrRange()) {
552 ASSERT(m_frame->settings());
553 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
554 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
555 // was created right-to-left
556 Position start = newSelection.start();
557 Position end = newSelection.end();
558 int distanceToStart = textDistance(start, pos);
559 int distanceToEnd = textDistance(pos, end);
560 if (distanceToStart <= distanceToEnd)
561 newSelection = VisibleSelection(end, pos);
563 newSelection = VisibleSelection(start, pos);
565 newSelection.setExtent(pos);
567 if (m_frame->selection()->granularity() != CharacterGranularity) {
568 granularity = m_frame->selection()->granularity();
569 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
572 newSelection = VisibleSelection(visiblePos);
574 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
577 static inline bool canMouseDownStartSelect(Node* node)
579 if (!node || !node->renderer())
582 if (!node->canStartSelection())
588 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
590 #if ENABLE(DRAG_SUPPORT)
592 #if ENABLE(TIZEN_DRAG_SUPPORT)
593 if(m_frame->page()->dragController()->dragState())
595 dragState().m_dragSrc = 0;
598 cancelFakeMouseMoveEvent();
600 m_frame->document()->updateLayoutIgnorePendingStylesheets();
602 if (ScrollView* scrollView = m_frame->view()) {
603 if (scrollView->isPointInScrollbarCorner(event.event().position()))
607 bool singleClick = event.event().clickCount() <= 1;
609 // If we got the event back, that must mean it wasn't prevented,
610 // so it's allowed to start a drag or selection.
611 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
613 #if ENABLE(DRAG_SUPPORT)
614 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
615 #if ENABLE(TIZEN_DRAG_SUPPORT)
616 if(m_frame->page()->dragController()->dragState())
618 m_mouseDownMayStartDrag = singleClick;
621 m_mouseDownWasSingleClickInSelection = false;
623 m_mouseDown = event.event();
625 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
629 if (m_frame->document()->isSVGDocument()
630 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
631 if (event.event().shiftKey() && singleClick) {
633 static_cast<SVGDocument*>(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
639 // We don't do this at the start of mouse down handling,
640 // because we don't want to do it until we know we didn't hit a widget.
644 Node* innerNode = targetNode(event);
646 m_mousePressNode = innerNode;
647 #if ENABLE(DRAG_SUPPORT)
648 #if ENABLE(TIZEN_DRAG_SUPPORT)
649 if(m_frame->page()->dragController()->dragState())
651 m_dragStartPos = event.event().position();
654 bool swallowEvent = false;
655 m_mousePressed = true;
656 m_selectionInitiationState = HaveNotStartedSelection;
658 if (event.event().clickCount() == 2)
659 swallowEvent = handleMousePressEventDoubleClick(event);
660 else if (event.event().clickCount() >= 3)
661 swallowEvent = handleMousePressEventTripleClick(event);
663 swallowEvent = handleMousePressEventSingleClick(event);
665 #if ENABLE(TIZEN_ISF_PORT)
666 m_frame->editor()->client()->respondToChangedSelection(m_frame);
669 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
670 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
672 #if ENABLE(TIZEN_DRAG_SUPPORT)
673 if(m_frame->page()->dragController()->dragState()) {
674 IntPoint fakePoint(0,0);
675 PlatformMouseEvent fakeMouseEvent(fakePoint, fakePoint, NoButton, PlatformEvent::NoType, 0, false, false, false, false, currentTime());
676 mouseMoved(fakeMouseEvent);
683 // There are two kinds of renderer that can autoscroll.
684 static bool canAutoscroll(RenderObject* renderer)
686 if (!renderer->isBox())
689 // Check for a box that can be scrolled in its own right.
690 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
693 // Check for a box that represents the top level of a web page.
694 // This can be scrolled by calling Chrome::scrollRectIntoView.
695 // This only has an effect on the Mac platform in applications
696 // that put web views into scrolling containers, such as Mac OS X Mail.
697 // The code for this is in RenderLayer::scrollRectToVisible.
698 if (renderer->node() != renderer->document())
700 Frame* frame = renderer->frame();
703 Page* page = frame->page();
704 return page && page->mainFrame() == frame;
707 #if ENABLE(DRAG_SUPPORT)
708 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
710 if (handleDrag(event))
716 Node* targetNode = EventHandler::targetNode(event);
717 if (event.event().button() != LeftButton || !targetNode)
720 RenderObject* renderer = targetNode->renderer();
722 renderer = targetNode->parentNode() ? targetNode->parentNode()->renderer() : 0;
723 if (!renderer || !renderer->isListBox())
727 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
728 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
731 m_mouseDownMayStartDrag = false;
733 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
734 // Find a renderer that can autoscroll.
735 while (renderer && !canAutoscroll(renderer)) {
736 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
737 renderer = renderer->document()->ownerElement()->renderer();
739 renderer = renderer->parent();
743 m_autoscrollInProgress = true;
744 handleAutoscroll(renderer);
747 m_mouseDownMayStartAutoscroll = false;
750 if (m_selectionInitiationState != ExtendedSelection) {
751 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
752 HitTestResult result(m_mouseDownPos);
753 m_frame->document()->renderView()->hitTest(request, result);
755 updateSelectionForMouseDrag(result);
757 updateSelectionForMouseDrag(event.hitTestResult());
761 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
763 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
764 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
765 // in handleMousePressEvent
767 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
770 if (event.button() != LeftButton || event.clickCount() != 1)
773 FrameView* view = m_frame->view();
777 Page* page = m_frame->page();
781 updateDragSourceActionsAllowed();
782 HitTestRequest request(HitTestRequest::ReadOnly);
783 HitTestResult result(view->windowToContents(event.position()));
784 m_frame->contentRenderer()->hitTest(request, result);
786 return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), roundedIntPoint(result.point()), state);
789 void EventHandler::updateSelectionForMouseDrag()
791 FrameView* view = m_frame->view();
794 RenderView* renderer = m_frame->contentRenderer();
798 HitTestRequest request(HitTestRequest::ReadOnly |
799 HitTestRequest::Active |
800 HitTestRequest::Move);
801 HitTestResult result(view->windowToContents(m_currentMousePosition));
802 renderer->hitTest(request, result);
803 updateSelectionForMouseDrag(result);
806 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
808 LayoutPoint selectionEndPoint = localPoint;
809 Element* editableElement = selection.rootEditableElement();
811 if (!targetNode->renderer())
812 return VisiblePosition();
814 if (editableElement && !editableElement->contains(targetNode)) {
815 if (!editableElement->renderer())
816 return VisiblePosition();
818 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
819 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
820 targetNode = editableElement;
823 return targetNode->renderer()->positionForPoint(selectionEndPoint);
826 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
828 if (!m_mouseDownMayStartSelect)
831 Node* target = targetNode(hitTestResult);
835 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
837 // Don't modify the selection if we're not on a node.
838 if (targetPosition.isNull())
841 // Restart the selection if this is the first mouse move. This work is usually
842 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
843 VisibleSelection newSelection = m_frame->selection()->selection();
846 // Special case to limit selection to the containing block for SVG text.
847 // FIXME: Isn't there a better non-SVG-specific way to do this?
848 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
849 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
850 if (selectionBaseRenderer->isSVGText())
851 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
855 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
858 if (m_selectionInitiationState != ExtendedSelection) {
859 // Always extend selection here because it's caused by a mouse drag
860 m_selectionInitiationState = ExtendedSelection;
861 newSelection = VisibleSelection(targetPosition);
864 newSelection.setExtent(targetPosition);
865 if (m_frame->selection()->granularity() != CharacterGranularity)
866 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
868 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection()->granularity(),
869 FrameSelection::AdjustEndpointsAtBidiBoundary);
871 #endif // ENABLE(DRAG_SUPPORT)
873 void EventHandler::lostMouseCapture()
875 m_frame->selection()->setCaretBlinkingSuspended(false);
878 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
880 if (eventLoopHandleMouseUp(event))
883 // If this was the first click in the window, we don't even want to clear the selection.
884 // This case occurs when the user clicks on a draggable element, since we have to process
885 // the mouse down and drag events to see if we might start a drag. For other first clicks
886 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
887 // ignored upstream of this layer.
888 return eventActivatedView(event.event());
891 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
893 if (m_autoscrollInProgress)
894 stopAutoscrollTimer();
896 if (handleMouseUp(event))
899 // Used to prevent mouseMoveEvent from initiating a drag before
900 // the mouse is pressed again.
901 m_frame->selection()->setCaretBlinkingSuspended(false);
902 m_mousePressed = false;
903 m_capturesDragging = false;
904 #if ENABLE(DRAG_SUPPORT)
905 m_mouseDownMayStartDrag = false;
907 m_mouseDownMayStartSelect = false;
908 m_mouseDownMayStartAutoscroll = false;
909 m_mouseDownWasInSubframe = false;
911 bool handled = false;
913 // Clear the selection if the mouse didn't move after the last mouse
914 // press and it's not a context menu click. We do this so when clicking
915 // on the selection, the selection goes away. However, if we are
916 // editing, place the caret.
917 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
918 #if ENABLE(DRAG_SUPPORT)
919 #if ENABLE(TIZEN_DRAG_SUPPORT)
920 // When the dragState is true, only check the dragStart's Position
921 && (!m_frame->page()->dragController()->dragState() || m_dragStartPos == event.event().position())
923 && m_dragStartPos == event.event().position()
926 && m_frame->selection()->isRange()
927 && event.event().button() != RightButton) {
928 VisibleSelection newSelection;
929 Node* node = targetNode(event);
930 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
931 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
932 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
933 newSelection = VisibleSelection(pos);
936 setSelectionIfNeeded(m_frame->selection(), newSelection);
941 m_frame->selection()->notifyRendererOfSelectionChange(UserTriggered);
943 m_frame->selection()->selectFrameElementInParentIfFullySelected();
948 void EventHandler::handleAutoscroll(RenderObject* renderer)
950 // We don't want to trigger the autoscroll or the panScroll if it's already active
951 if (m_autoscrollTimer.isActive())
954 setAutoscrollRenderer(renderer);
956 #if ENABLE(PAN_SCROLLING)
957 if (m_panScrollInProgress) {
958 m_panScrollStartPos = currentMousePosition();
959 if (FrameView* view = m_frame->view())
960 view->addPanScrollIcon(m_panScrollStartPos);
961 // If we're not in the top frame we notify it that we doing a panScroll.
962 if (Page* page = m_frame->page()) {
963 Frame* mainFrame = page->mainFrame();
964 if (m_frame != mainFrame)
965 mainFrame->eventHandler()->m_panScrollInProgress = true;
970 startAutoscrollTimer();
973 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
975 RenderObject* r = autoscrollRenderer();
976 if (!r || !r->isBox()) {
977 stopAutoscrollTimer();
981 if (m_autoscrollInProgress) {
982 if (!m_mousePressed) {
983 stopAutoscrollTimer();
986 toRenderBox(r)->autoscroll();
988 // we verify that the main frame hasn't received the order to stop the panScroll
989 if (Page* page = m_frame->page()) {
990 if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) {
991 stopAutoscrollTimer();
995 #if ENABLE(PAN_SCROLLING)
996 updatePanScrollState();
997 toRenderBox(r)->panScroll(m_panScrollStartPos);
1002 #if ENABLE(PAN_SCROLLING)
1004 void EventHandler::startPanScrolling(RenderObject* renderer)
1006 m_panScrollInProgress = true;
1007 m_panScrollButtonPressed = true;
1008 handleAutoscroll(renderer);
1012 void EventHandler::updatePanScrollState()
1014 FrameView* view = m_frame->view();
1018 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
1019 // So we don't want to change the cursor over this area
1020 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
1021 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
1022 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
1023 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
1025 if ((east || west || north || south) && m_panScrollButtonPressed)
1026 m_springLoadedPanScrollInProgress = true;
1030 view->setCursor(northEastPanningCursor());
1032 view->setCursor(northWestPanningCursor());
1034 view->setCursor(northPanningCursor());
1037 view->setCursor(southEastPanningCursor());
1039 view->setCursor(southWestPanningCursor());
1041 view->setCursor(southPanningCursor());
1043 view->setCursor(eastPanningCursor());
1045 view->setCursor(westPanningCursor());
1047 view->setCursor(middlePanningCursor());
1050 #endif // ENABLE(PAN_SCROLLING)
1052 RenderObject* EventHandler::autoscrollRenderer() const
1054 return m_autoscrollRenderer;
1057 void EventHandler::updateAutoscrollRenderer()
1059 if (!m_autoscrollRenderer)
1062 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
1064 if (Node* nodeAtPoint = hitTest.innerNode())
1065 m_autoscrollRenderer = nodeAtPoint->renderer();
1067 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
1068 m_autoscrollRenderer = m_autoscrollRenderer->parent();
1071 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
1073 m_autoscrollRenderer = renderer;
1076 #if ENABLE(DRAG_SUPPORT)
1077 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
1080 return DragSourceActionNone;
1082 Page* page = m_frame->page();
1084 return DragSourceActionNone;
1086 FrameView* view = m_frame->view();
1088 return DragSourceActionNone;
1090 return page->dragController()->delegateDragSourceAction(view->contentsToRootView(m_mouseDownPos));
1092 #endif // ENABLE(DRAG_SUPPORT)
1094 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
1096 enum ShadowContentFilterPolicy shadowContentFilterPolicy = allowShadowContent ? AllowShadowContent : DoNotAllowShadowContent;
1097 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1099 if (!m_frame->contentRenderer())
1102 hitType |= HitTestRequest::IgnoreClipping;
1103 m_frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
1106 Node* n = result.innerNode();
1107 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
1109 RenderWidget* renderWidget = toRenderWidget(n->renderer());
1110 Widget* widget = renderWidget->widget();
1111 if (!widget || !widget->isFrameView())
1113 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
1114 if (!frame || !frame->contentRenderer())
1116 FrameView* view = static_cast<FrameView*>(widget);
1117 LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
1118 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
1119 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width(), shadowContentFilterPolicy);
1120 frame->contentRenderer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
1121 result = widgetHitTestResult;
1123 if (testScrollbars == ShouldHitTestScrollbars) {
1124 Scrollbar* eventScrollbar = view->scrollbarAtPoint(roundedIntPoint(point));
1126 result.setScrollbar(eventScrollbar);
1130 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
1131 // Another hit test at the main frame level should get us the correct visible result.
1132 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
1133 if (Page* page = m_frame->page()) {
1134 Frame* mainFrame = page->mainFrame();
1135 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame) {
1136 FrameView* resultView = resultFrame->view();
1137 FrameView* mainView = mainFrame->view();
1138 if (resultView && mainView) {
1139 IntPoint mainFramePoint = mainView->rootViewToContents(resultView->contentsToRootView(roundedIntPoint(result.point())));
1140 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
1145 if (!allowShadowContent)
1146 result.setToNonShadowAncestor();
1152 void EventHandler::startAutoscrollTimer()
1154 m_autoscrollTimer.startRepeating(autoscrollInterval);
1157 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1159 if (m_autoscrollInProgress) {
1160 if (m_mouseDownWasInSubframe) {
1161 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
1162 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
1167 if (autoscrollRenderer()) {
1168 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
1169 toRenderBox(autoscrollRenderer())->stopAutoscroll();
1170 #if ENABLE(PAN_SCROLLING)
1171 if (m_panScrollInProgress) {
1172 if (FrameView* view = m_frame->view()) {
1173 view->removePanScrollIcon();
1174 view->setCursor(pointerCursor());
1179 setAutoscrollRenderer(0);
1182 m_autoscrollTimer.stop();
1184 m_panScrollInProgress = false;
1185 m_springLoadedPanScrollInProgress = false;
1187 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1188 if (Page* page = m_frame->page()) {
1189 Frame* mainFrame = page->mainFrame();
1190 if (m_frame != mainFrame)
1191 mainFrame->eventHandler()->m_panScrollInProgress = false;
1194 m_autoscrollInProgress = false;
1197 Node* EventHandler::mousePressNode() const
1199 return m_mousePressNode.get();
1202 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1204 m_mousePressNode = node;
1207 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1209 Node* node = startingNode;
1212 node = m_frame->document()->focusedNode();
1215 node = m_mousePressNode.get();
1218 RenderObject* r = node->renderer();
1219 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1220 setFrameWasScrolledByUser();
1228 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
1229 bool EventHandler::scrollOverflow(const FloatPoint& trajectoryVector)
1231 bool scrolled = false;
1232 if (m_mousePressNode) {
1233 RenderObject* r = m_mousePressNode->renderer();
1234 if (r && !r->isListBox()) {
1235 float multiplier = 0;
1236 ScrollDirection direction;
1238 float delta = trajectoryVector.y();
1240 multiplier = (delta < 0) ? -delta : delta;
1241 direction = (delta < 0) ? ScrollUp : ScrollDown;
1242 scrolled |= r->enclosingBox()->scroll(direction, ScrollByPixel, multiplier);
1244 delta = trajectoryVector.x();
1246 multiplier = (delta < 0) ? -delta : delta;
1247 direction = (delta < 0) ? ScrollLeft : ScrollRight;
1248 scrolled |= r->enclosingBox()->scroll(direction, ScrollByPixel, multiplier);
1252 setFrameWasScrolledByUser();
1254 #if ENABLE(TIZEN_INPUT_BOX_SCROLL)
1256 if (r && r->isTextField()) {
1257 WebCore::RenderTextControl* renderText = toRenderTextControl(r);
1258 int leftScrollOffset = renderText->scrollLeft();
1259 m_mousePressNode->document()->frame()->selection()->setCaretVisible(false);
1260 leftScrollOffset += trajectoryVector.x();
1261 renderText->setScrollLeft(leftScrollOffset);
1262 renderText->setScrollTop((int)trajectoryVector.y());
1263 m_mousePressNode->document()->frame()->selection()->setCaretVisible(true);
1273 bool EventHandler::setMousePressNodeAtPoint(const IntPoint& point, bool checkOverflowLayer, RenderObject*& overflowRenderer)
1275 HitTestResult result = hitTestResultAtPoint(point, false);
1276 Node* node = result.innerNode();
1278 changeFocusedFrameAndNode(0);
1283 RenderObject* renderer = node->renderer();
1285 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION_ON_UI_SIDE)
1286 if (checkOverflowLayer) {
1287 // Find overflow layer.
1288 if (renderer->isBoxModelObject() && renderer->hasLayer()
1289 && renderer->enclosingLayer()->hasAcceleratedTouchScrolling()
1290 && renderer->enclosingLayer()->layerForScrollingContents()) {
1291 overflowRenderer = renderer;
1292 changeFocusedFrameAndNode(node);
1297 // Find overflow node.
1298 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow()
1299 && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
1300 changeFocusedFrameAndNode(node);
1303 #if ENABLE(TIZEN_INPUT_BOX_SCROLL)
1304 // Setting mouse press for inline text box
1305 if (renderer->isBox() && renderer->isTextField()) {
1306 changeFocusedFrameAndNode(node);
1310 renderer = renderer->parent();
1313 if (node->document()->frame())
1314 node = static_cast<Node*>(node->document()->frame()->ownerElement());
1319 changeFocusedFrameAndNode(0);
1323 void EventHandler::changeFocusedFrameAndNode(PassRefPtr<Node> targetNode)
1325 if (!m_frame->page())
1329 m_frame->page()->focusController()->setFocusedFrame(m_frame->page()->mainFrame());
1330 setMousePressNode(0);
1334 setMousePressNode(0);
1335 Frame* targetFrame = targetNode->document()->frame();
1336 m_frame->page()->focusController()->setFocusedFrame(targetFrame);
1337 targetFrame->eventHandler()->setMousePressNode(targetNode);
1341 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1343 Node* node = startingNode;
1346 node = m_frame->document()->focusedNode();
1349 node = m_mousePressNode.get();
1352 RenderObject* r = node->renderer();
1353 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1354 setFrameWasScrolledByUser();
1362 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1364 // The layout needs to be up to date to determine if we can scroll. We may be
1365 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1366 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1367 if (scrollOverflow(direction, granularity, startingNode))
1369 Frame* frame = m_frame;
1370 FrameView* view = frame->view();
1371 if (view && view->scroll(direction, granularity))
1373 frame = frame->tree()->parent();
1376 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1379 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1381 // The layout needs to be up to date to determine if we can scroll. We may be
1382 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1383 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1384 if (logicalScrollOverflow(direction, granularity, startingNode))
1386 Frame* frame = m_frame;
1387 FrameView* view = frame->view();
1389 bool scrolled = false;
1391 // Mac also resets the scroll position in the inline direction.
1392 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1395 if (view && view->logicalScroll(direction, granularity))
1401 frame = frame->tree()->parent();
1405 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1408 IntPoint EventHandler::currentMousePosition() const
1410 return m_currentMousePosition;
1413 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1415 if (!hitTestResult.isOverWidget())
1417 return subframeForTargetNode(targetNode(hitTestResult));
1420 Frame* EventHandler::subframeForTargetNode(Node* node)
1425 RenderObject* renderer = node->renderer();
1426 if (!renderer || !renderer->isWidget())
1429 Widget* widget = toRenderWidget(renderer)->widget();
1430 if (!widget || !widget->isFrameView())
1433 return static_cast<FrameView*>(widget)->frame();
1436 static bool isSubmitImage(Node* node)
1438 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1441 // Returns true if the node's editable block is not current focused for editing
1442 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1444 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1447 OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1449 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1450 return NoCursorChange;
1452 Page* page = m_frame->page();
1454 return NoCursorChange;
1455 if (page->mainFrame()->eventHandler()->m_panScrollInProgress)
1456 return NoCursorChange;
1458 Node* node = targetNode(event);
1459 RenderObject* renderer = node ? node->renderer() : 0;
1460 RenderStyle* style = renderer ? renderer->style() : 0;
1461 bool horizontalText = !style || style->isHorizontalWritingMode();
1462 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1464 // During selection, use an I-beam no matter what we're over.
1465 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1466 if (m_mousePressed && m_mouseDownMayStartSelect
1467 #if ENABLE(DRAG_SUPPORT)
1468 && !m_mouseDownMayStartDrag
1470 && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1474 Cursor overrideCursor;
1475 switch (renderer->getCursor(roundedIntPoint(event.localPoint()), overrideCursor)) {
1476 case SetCursorBasedOnStyle:
1479 return overrideCursor;
1480 case DoNotSetCursor:
1481 return NoCursorChange;
1485 if (style && style->cursors()) {
1486 const CursorList* cursors = style->cursors();
1487 for (unsigned i = 0; i < cursors->size(); ++i) {
1488 CachedImage* cimage = 0;
1489 StyleImage* image = (*cursors)[i].image();
1490 if (image && image->isCachedImage())
1491 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1494 IntPoint hotSpot = (*cursors)[i].hotSpot();
1495 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1496 IntSize size = cimage->imageForRenderer(renderer)->size();
1497 if (size.width() > 128 || size.height() > 128)
1499 if (!cimage->errorOccurred())
1500 return Cursor(cimage->imageForRenderer(renderer), hotSpot);
1504 switch (style ? style->cursor() : CURSOR_AUTO) {
1506 bool editable = (node && node->rendererIsEditable());
1507 bool editableLinkEnabled = false;
1509 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1511 ASSERT(m_frame->settings());
1512 switch (m_frame->settings()->editableLinkBehavior()) {
1514 case EditableLinkDefaultBehavior:
1515 case EditableLinkAlwaysLive:
1516 editableLinkEnabled = true;
1519 case EditableLinkNeverLive:
1520 editableLinkEnabled = false;
1523 case EditableLinkLiveWhenNotFocused:
1524 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1527 case EditableLinkOnlyLiveWithShiftKey:
1528 editableLinkEnabled = event.event().shiftKey();
1533 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1534 return handCursor();
1535 bool inResizer = false;
1537 if (RenderLayer* layer = renderer->enclosingLayer()) {
1538 if (FrameView* view = m_frame->view())
1539 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().position()));
1542 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1544 return pointerCursor();
1547 return crossCursor();
1548 case CURSOR_POINTER:
1549 return handCursor();
1551 return moveCursor();
1552 case CURSOR_ALL_SCROLL:
1553 return moveCursor();
1554 case CURSOR_E_RESIZE:
1555 return eastResizeCursor();
1556 case CURSOR_W_RESIZE:
1557 return westResizeCursor();
1558 case CURSOR_N_RESIZE:
1559 return northResizeCursor();
1560 case CURSOR_S_RESIZE:
1561 return southResizeCursor();
1562 case CURSOR_NE_RESIZE:
1563 return northEastResizeCursor();
1564 case CURSOR_SW_RESIZE:
1565 return southWestResizeCursor();
1566 case CURSOR_NW_RESIZE:
1567 return northWestResizeCursor();
1568 case CURSOR_SE_RESIZE:
1569 return southEastResizeCursor();
1570 case CURSOR_NS_RESIZE:
1571 return northSouthResizeCursor();
1572 case CURSOR_EW_RESIZE:
1573 return eastWestResizeCursor();
1574 case CURSOR_NESW_RESIZE:
1575 return northEastSouthWestResizeCursor();
1576 case CURSOR_NWSE_RESIZE:
1577 return northWestSouthEastResizeCursor();
1578 case CURSOR_COL_RESIZE:
1579 return columnResizeCursor();
1580 case CURSOR_ROW_RESIZE:
1581 return rowResizeCursor();
1583 return iBeamCursor();
1585 return waitCursor();
1587 return helpCursor();
1588 case CURSOR_VERTICAL_TEXT:
1589 return verticalTextCursor();
1591 return cellCursor();
1592 case CURSOR_CONTEXT_MENU:
1593 return contextMenuCursor();
1594 case CURSOR_PROGRESS:
1595 return progressCursor();
1596 case CURSOR_NO_DROP:
1597 return noDropCursor();
1599 return aliasCursor();
1601 return copyCursor();
1603 return noneCursor();
1604 case CURSOR_NOT_ALLOWED:
1605 return notAllowedCursor();
1606 case CURSOR_DEFAULT:
1607 return pointerCursor();
1608 case CURSOR_WEBKIT_ZOOM_IN:
1609 return zoomInCursor();
1610 case CURSOR_WEBKIT_ZOOM_OUT:
1611 return zoomOutCursor();
1612 case CURSOR_WEBKIT_GRAB:
1613 return grabCursor();
1614 case CURSOR_WEBKIT_GRABBING:
1615 return grabbingCursor();
1617 return pointerCursor();
1620 static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1622 FrameView* view = frame->view();
1623 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1624 // Historically the code would just crash; this is clearly no worse than that.
1625 return view ? view->windowToContents(windowPoint) : windowPoint;
1628 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1630 return targetNode(event.hitTestResult());
1633 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1635 Node* node = hitTestResult.innerNode();
1638 if (node->inDocument())
1641 Element* element = node->parentElement();
1642 if (element && element->inDocument())
1649 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1651 RefPtr<FrameView> protector(m_frame->view());
1653 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1658 #if ENABLE(TOUCH_EVENTS)
1659 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1660 if (defaultPrevented)
1664 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1666 // FIXME (bug 68185): this call should be made at another abstraction layer
1667 m_frame->loader()->resetMultipleFormSubmissionProtection();
1669 cancelFakeMouseMoveEvent();
1670 m_mousePressed = true;
1671 m_capturesDragging = true;
1672 m_currentMousePosition = mouseEvent.position();
1673 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1674 m_mouseDownTimestamp = mouseEvent.timestamp();
1675 #if ENABLE(DRAG_SUPPORT)
1676 m_mouseDownMayStartDrag = false;
1678 m_mouseDownMayStartSelect = false;
1679 m_mouseDownMayStartAutoscroll = false;
1680 if (FrameView* view = m_frame->view())
1681 #if ENABLE(TIZEN_DRAG_SUPPORT)
1682 m_mouseDownPos = mouseEvent.position();
1684 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1687 #if ENABLE(TIZEN_DAILY_UPVERSIONING)
1693 m_mouseDownWasInSubframe = false;
1695 HitTestRequest request(HitTestRequest::Active);
1696 // Save the document point we generate in case the window coordinate is invalidated by what happens
1697 // when we dispatch the event.
1698 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1699 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1701 if (!targetNode(mev)) {
1706 m_mousePressNode = targetNode(mev);
1708 Frame* subframe = subframeForHitTestResult(mev);
1709 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1710 // Start capturing future events for this frame. We only do this if we didn't clear
1711 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1712 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1713 if (m_mousePressed && m_capturesDragging) {
1714 m_capturingMouseEventsNode = targetNode(mev);
1715 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1721 #if ENABLE(PAN_SCROLLING)
1722 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1723 // because it will set m_panScrollInProgress to false on return.
1724 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress;
1725 if (isPanScrollInProgress || m_autoscrollInProgress)
1726 stopAutoscrollTimer();
1727 if (isPanScrollInProgress) {
1728 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1729 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1735 m_clickCount = mouseEvent.clickCount();
1736 m_clickNode = targetNode(mev);
1738 if (FrameView* view = m_frame->view()) {
1739 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1740 IntPoint p = view->windowToContents(mouseEvent.position());
1741 if (layer && layer->isPointInResizeControl(p)) {
1742 layer->setInResizeMode(true);
1743 m_resizeLayer = layer;
1744 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1750 m_frame->selection()->setCaretBlinkingSuspended(true);
1752 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1753 m_capturesDragging = !swallowEvent || mev.scrollbar();
1755 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1756 // in case the scrollbar widget was destroyed when the mouse event was handled.
1757 if (mev.scrollbar()) {
1758 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1759 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1760 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1761 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1762 m_lastScrollbarUnderMouse = 0;
1766 // scrollbars should get events anyway, even disabled controls might be scrollable
1767 Scrollbar* scrollbar = mev.scrollbar();
1769 updateLastScrollbarUnderMouse(scrollbar, true);
1772 passMousePressEventToScrollbar(mev, scrollbar);
1774 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1775 // If a mouse event handler changes the input element type to one that has a widget associated,
1776 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1777 // event target node can't still be the shadow node.
1778 if (targetNode(mev)->isShadowRoot() && toShadowRoot(targetNode(mev))->host()->hasTagName(inputTag)) {
1779 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1780 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1783 FrameView* view = m_frame->view();
1784 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1786 scrollbar = mev.scrollbar();
1788 updateLastScrollbarUnderMouse(scrollbar, true);
1790 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1791 swallowEvent = true;
1793 swallowEvent = handleMousePressEvent(mev);
1796 return swallowEvent;
1799 // This method only exists for platforms that don't know how to deliver
1800 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1802 RefPtr<FrameView> protector(m_frame->view());
1804 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1806 // We get this instead of a second mouse-up
1807 m_mousePressed = false;
1808 m_currentMousePosition = mouseEvent.position();
1809 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1811 HitTestRequest request(HitTestRequest::Active);
1812 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1813 Frame* subframe = subframeForHitTestResult(mev);
1814 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1815 m_capturingMouseEventsNode = 0;
1816 if (subframe && passMousePressEventToSubframe(mev, subframe))
1819 m_clickCount = mouseEvent.clickCount();
1820 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1822 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1824 if (m_lastScrollbarUnderMouse)
1825 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1827 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1831 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1834 static RenderLayer* layerForNode(Node* node)
1839 RenderObject* renderer = node->renderer();
1843 RenderLayer* layer = renderer->enclosingLayer();
1850 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1852 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1853 RefPtr<FrameView> protector(m_frame->view());
1856 #if ENABLE(TOUCH_EVENTS)
1857 // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events.
1858 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event);
1859 if (defaultPrevented)
1863 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1864 bool result = handleMouseMoveEvent(event, &hoveredNode);
1866 Page* page = m_frame->page();
1870 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1871 if (FrameView* frameView = m_frame->view()) {
1872 if (frameView->containsScrollableArea(layer))
1873 layer->mouseMovedInContentArea();
1877 if (FrameView* frameView = m_frame->view())
1878 frameView->mouseMovedInContentArea();
1880 hoveredNode.setToNonShadowAncestor();
1881 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1882 page->chrome()->setToolTip(hoveredNode);
1886 bool EventHandler::passMouseMovedEventToScrollbars(const PlatformMouseEvent& event)
1888 HitTestResult hoveredNode;
1889 return handleMouseMoveEvent(event, &hoveredNode, true);
1892 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1894 // in Radar 3703768 we saw frequent crashes apparently due to the
1895 // part being null here, which seems impossible, so check for nil
1896 // but also assert so that we can try to figure this out in debug
1897 // builds, if it happens.
1902 RefPtr<FrameView> protector(m_frame->view());
1903 m_currentMousePosition = mouseEvent.position();
1904 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
1906 if (m_hoverTimer.isActive())
1907 m_hoverTimer.stop();
1909 cancelFakeMouseMoveEvent();
1913 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1918 if (m_frameSetBeingResized)
1919 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1921 // Send events right to a scrollbar if the mouse is pressed.
1922 if (m_lastScrollbarUnderMouse && m_mousePressed)
1923 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1925 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move;
1927 hitType |= HitTestRequest::Active;
1928 else if (onlyUpdateScrollbars) {
1929 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1930 // means that :hover and :active freeze in the state they were in, rather than updating
1931 // for nodes the mouse moves while the window is not key (which will be the case if
1932 // onlyUpdateScrollbars is true).
1933 hitType |= HitTestRequest::ReadOnly;
1936 #if ENABLE(TOUCH_EVENTS)
1937 // Treat any mouse move events as readonly if the user is currently touching the screen.
1939 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1941 HitTestRequest request(hitType);
1942 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1944 *hoveredNode = mev.hitTestResult();
1946 Scrollbar* scrollbar = 0;
1948 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1949 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1951 if (FrameView* view = m_frame->view())
1952 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1955 scrollbar = mev.scrollbar();
1957 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1958 if (onlyUpdateScrollbars)
1962 bool swallowEvent = false;
1963 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1965 // 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.
1966 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1967 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1970 // Update over/out state before passing the event to the subframe.
1971 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1973 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1974 // node to be detached from its FrameView, in which case the event should not be passed.
1975 if (newSubframe->view())
1976 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1978 if (scrollbar && !m_mousePressed)
1979 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1980 if (FrameView* view = m_frame->view()) {
1981 OptionalCursor optionalCursor = selectCursor(mev, scrollbar);
1982 if (optionalCursor.isCursorChange())
1983 view->setCursor(optionalCursor.cursor());
1987 m_lastMouseMoveEventSubframe = newSubframe;
1992 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1993 #if ENABLE(DRAG_SUPPORT)
1994 #if ENABLE(TIZEN_DRAG_SUPPORT)
1995 if (!swallowEvent && m_frame->page()->dragController()->dragState())
1999 swallowEvent = handleMouseDraggedEvent(mev);
2000 #endif // ENABLE(DRAG_SUPPORT)
2002 return swallowEvent;
2005 void EventHandler::invalidateClick()
2011 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
2013 RefPtr<FrameView> protector(m_frame->view());
2015 #if ENABLE(TOUCH_EVENTS)
2016 bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
2017 if (defaultPrevented)
2021 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2023 #if ENABLE(PAN_SCROLLING)
2024 if (mouseEvent.button() == MiddleButton)
2025 m_panScrollButtonPressed = false;
2026 if (m_springLoadedPanScrollInProgress)
2027 stopAutoscrollTimer();
2030 m_mousePressed = false;
2031 m_currentMousePosition = mouseEvent.position();
2032 m_currentMouseGlobalPosition = mouseEvent.globalPosition();
2037 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
2042 if (m_frameSetBeingResized)
2043 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
2045 if (m_lastScrollbarUnderMouse) {
2047 return m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
2050 HitTestRequest request(HitTestRequest::Release);
2051 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
2052 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
2053 if (m_eventHandlerWillResetCapturingMouseEventsNode)
2054 m_capturingMouseEventsNode = 0;
2055 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
2058 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
2060 Node* clickTarget = targetNode(mev);
2062 clickTarget = clickTarget->shadowAncestorNode();
2063 Node* adjustedClickNode = m_clickNode ? m_clickNode->shadowAncestorNode() : 0;
2065 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && clickTarget == adjustedClickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
2067 if (m_resizeLayer) {
2068 m_resizeLayer->setInResizeMode(false);
2072 bool swallowMouseReleaseEvent = false;
2073 if (!swallowMouseUpEvent)
2074 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
2078 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
2081 #if ENABLE(DRAG_SUPPORT)
2082 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
2084 FrameView* view = m_frame->view();
2086 // FIXME: We might want to dispatch a dragleave even if the view is gone.
2090 view->resetDeferredRepaintDelay();
2091 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
2092 true, true, m_frame->document()->defaultView(),
2093 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
2094 #if ENABLE(POINTER_LOCK)
2095 event.movementDelta().x(), event.movementDelta().y(),
2097 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
2101 dragTarget->dispatchEvent(me.get(), ec);
2102 return me->defaultPrevented();
2105 static bool targetIsFrame(Node* target, Frame*& frame)
2110 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
2113 frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
2118 static bool findDropZone(Node* target, Clipboard* clipboard)
2120 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
2121 for (; element; element = element->parentElement()) {
2122 bool matched = false;
2123 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
2125 if (dropZoneStr.isEmpty())
2128 dropZoneStr.makeLower();
2130 SpaceSplitString keywords(dropZoneStr, false);
2131 if (keywords.isNull())
2134 DragOperation dragOperation = DragOperationNone;
2135 for (unsigned int i = 0; i < keywords.size(); i++) {
2136 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
2137 if (op != DragOperationNone) {
2138 if (dragOperation == DragOperationNone)
2141 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
2143 if (matched && dragOperation != DragOperationNone)
2147 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
2154 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2156 bool accept = false;
2158 if (!m_frame->view())
2161 HitTestRequest request(HitTestRequest::ReadOnly);
2162 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
2164 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
2165 RefPtr<Node> newTarget = targetNode(mev);
2166 if (newTarget && newTarget->isTextNode())
2167 newTarget = newTarget->parentNode();
2169 if (m_dragTarget != newTarget) {
2170 // FIXME: this ordering was explicitly chosen to match WinIE. However,
2171 // it is sometimes incorrect when dragging within subframes, as seen with
2172 // LayoutTests/fast/events/drag-in-frames.html.
2174 // 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>.
2176 if (targetIsFrame(newTarget.get(), targetFrame)) {
2178 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2179 } else if (newTarget) {
2180 // 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.
2181 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2182 // for now we don't care if event handler cancels default behavior, since there is none
2183 dispatchDragSrcEvent(eventNames().dragEvent, event);
2185 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget.get(), event, clipboard);
2187 accept = findDropZone(newTarget.get(), clipboard);
2190 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2192 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2193 } else if (m_dragTarget)
2194 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2197 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
2198 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
2199 m_shouldOnlyFireDragOverEvent = true;
2203 if (targetIsFrame(newTarget.get(), targetFrame)) {
2205 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
2206 } else if (newTarget) {
2207 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
2208 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2209 // for now we don't care if event handler cancels default behavior, since there is none
2210 dispatchDragSrcEvent(eventNames().dragEvent, event);
2212 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget.get(), event, clipboard);
2214 accept = findDropZone(newTarget.get(), clipboard);
2215 m_shouldOnlyFireDragOverEvent = false;
2218 m_dragTarget = newTarget;
2223 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2226 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2228 targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard);
2229 } else if (m_dragTarget.get()) {
2230 if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
2231 dispatchDragSrcEvent(eventNames().dragEvent, event);
2232 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
2237 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
2240 bool preventedDefault = false;
2241 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
2243 preventedDefault = targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
2244 } else if (m_dragTarget.get())
2245 preventedDefault = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
2247 return preventedDefault;
2250 void EventHandler::clearDragState()
2253 m_capturingMouseEventsNode = 0;
2254 m_shouldOnlyFireDragOverEvent = false;
2256 m_sendingEventToSubview = false;
2259 #endif // ENABLE(DRAG_SUPPORT)
2261 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
2263 m_capturingMouseEventsNode = n;
2264 m_eventHandlerWillResetCapturingMouseEventsNode = false;
2267 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
2270 ASSERT(m_frame->document());
2272 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
2276 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
2278 if (!referenceNode || !referenceNode->isSVGElement())
2281 ShadowRoot* shadowRoot = referenceNode->shadowRoot();
2285 Element* shadowTreeParentElement = shadowRoot->host();
2286 if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag))
2289 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
2293 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
2295 Node* result = targetNode;
2297 // If we're capturing, we always go right to that node.
2298 if (m_capturingMouseEventsNode)
2299 result = m_capturingMouseEventsNode.get();
2301 // If the target node is a text node, dispatch on the parent node - rdar://4196646
2302 if (result && result->isTextNode()) {
2303 ComposedShadowTreeParentWalker walker(result);
2304 walker.parentIncludingInsertionPointAndShadowRoot();
2305 result = walker.get();
2308 m_nodeUnderMouse = result;
2310 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
2312 // <use> shadow tree elements may have been recloned, update node under mouse in any case
2313 if (m_lastInstanceUnderMouse) {
2314 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
2315 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
2317 if (lastCorrespondingElement && lastCorrespondingUseElement) {
2318 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
2320 // Locate the recloned shadow tree element for our corresponding instance
2321 HashSet<SVGElementInstance*>::iterator end = instances.end();
2322 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
2323 SVGElementInstance* instance = (*it);
2324 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
2326 if (instance == m_lastInstanceUnderMouse)
2329 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
2332 SVGElement* shadowTreeElement = instance->shadowTreeElement();
2333 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
2336 m_lastNodeUnderMouse = shadowTreeElement;
2337 m_lastInstanceUnderMouse = instance;
2344 // Fire mouseout/mouseover if the mouse has shifted to a different node.
2345 if (fireMouseOverOut) {
2346 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
2347 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
2348 Page* page = m_frame->page();
2350 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
2351 // The mouse has moved between frames.
2352 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2353 if (FrameView* frameView = frame->view())
2354 frameView->mouseExitedContentArea();
2356 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2357 // The mouse has moved between layers.
2358 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
2359 if (FrameView* frameView = frame->view()) {
2360 if (frameView->containsScrollableArea(layerForLastNode))
2361 layerForLastNode->mouseExitedContentArea();
2366 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2367 // The mouse has moved between frames.
2368 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2369 if (FrameView* frameView = frame->view())
2370 frameView->mouseEnteredContentArea();
2372 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2373 // The mouse has moved between layers.
2374 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2375 if (FrameView* frameView = frame->view()) {
2376 if (frameView->containsScrollableArea(layerForNodeUnderMouse))
2377 layerForNodeUnderMouse->mouseEnteredContentArea();
2382 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2383 m_lastNodeUnderMouse = 0;
2384 m_lastScrollbarUnderMouse = 0;
2386 m_lastInstanceUnderMouse = 0;
2390 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2391 // send mouseout event to the old node
2392 if (m_lastNodeUnderMouse)
2393 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2394 // send mouseover event to the new node
2395 if (m_nodeUnderMouse)
2396 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2398 m_lastNodeUnderMouse = m_nodeUnderMouse;
2400 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2405 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2407 if (FrameView* view = m_frame->view())
2408 view->resetDeferredRepaintDelay();
2410 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2412 bool swallowEvent = false;
2414 if (m_nodeUnderMouse)
2415 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2417 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2419 // If clicking on a frame scrollbar, do not mess up with content focus.
2420 if (FrameView* view = m_frame->view()) {
2421 if (view->scrollbarAtPoint(mouseEvent.position()))
2425 // The layout needs to be up to date to determine if an element is focusable.
2426 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2428 // Blur current focus node when a link/button is clicked; this
2429 // is expected by some sites that rely on onChange handlers running
2430 // from form fields before the button click is processed.
2431 Node* node = m_nodeUnderMouse.get();
2433 // Walk up the DOM tree to search for a node to focus.
2435 if (node->isMouseFocusable()) {
2436 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2437 // node on mouse down if it's selected and inside a focused node. It will be
2438 // focused if the user does a mouseup over it, however, because the mouseup
2439 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2440 ExceptionCode ec = 0;
2441 Node* n = node->isShadowRoot() ? toShadowRoot(node)->host() : node;
2442 if (m_frame->selection()->isRange()
2443 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2444 && n->isDescendantOf(m_frame->document()->focusedNode()))
2449 node = node->parentOrHostNode();
2452 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2453 // if the page already set it (e.g., by canceling default behavior).
2454 if (Page* page = m_frame->page()) {
2455 if (node && node->isMouseFocusable()) {
2456 if (!page->focusController()->setFocusedNode(node, m_frame))
2457 swallowEvent = true;
2458 } else if (!node || !node->focused()) {
2459 if (!page->focusController()->setFocusedNode(0, m_frame))
2460 swallowEvent = true;
2465 return swallowEvent;
2468 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
2469 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const
2475 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2477 Document* doc = m_frame->document();
2479 RenderObject* docRenderer = doc->renderer();
2483 RefPtr<FrameView> protector(m_frame->view());
2485 FrameView* view = m_frame->view();
2488 setFrameWasScrolledByUser();
2489 LayoutPoint vPoint = view->windowToContents(e.position());
2494 HitTestRequest request(HitTestRequest::ReadOnly);
2495 HitTestResult result(vPoint);
2496 doc->renderView()->hitTest(request, result);
2499 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2502 if (m_useLatchedWheelEventNode) {
2503 if (!m_latchedWheelEventNode) {
2504 m_latchedWheelEventNode = result.innerNode();
2505 m_widgetIsLatched = result.isOverWidget();
2508 node = m_latchedWheelEventNode.get();
2509 isOverWidget = m_widgetIsLatched;
2511 if (m_latchedWheelEventNode)
2512 m_latchedWheelEventNode = 0;
2513 if (m_previousWheelScrolledNode)
2514 m_previousWheelScrolledNode = 0;
2516 node = result.innerNode();
2517 isOverWidget = result.isOverWidget();
2520 // FIXME: It should not be necessary to do this mutation here.
2521 // Instead, the handlers should know convert vertical scrolls
2523 PlatformWheelEvent event = e;
2524 if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2525 event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2528 // Figure out which view to send the event to.
2529 RenderObject* target = node->renderer();
2531 if (isOverWidget && target && target->isWidget()) {
2532 Widget* widget = toRenderWidget(target)->widget();
2533 if (widget && passWheelEventToWidget(e, widget))
2537 if (node && !node->dispatchWheelEvent(event))
2542 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2543 view = m_frame->view();
2547 return view->wheelEvent(event);
2550 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2552 if (!startNode || !wheelEvent)
2555 Node* stopNode = m_previousWheelScrolledNode.get();
2556 ScrollGranularity granularity = m_baseEventType == PlatformEvent::GestureScrollEnd ? ScrollByPixelVelocity : wheelGranularityToScrollGranularity(wheelEvent->granularity());
2558 // Break up into two scrolls if we need to. Diagonal movement on
2559 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2560 if (scrollNode(wheelEvent->rawDeltaX(), granularity, ScrollLeft, ScrollRight, startNode, &stopNode))
2561 wheelEvent->setDefaultHandled();
2563 if (scrollNode(wheelEvent->rawDeltaY(), granularity, ScrollUp, ScrollDown, startNode, &stopNode))
2564 wheelEvent->setDefaultHandled();
2566 if (!m_useLatchedWheelEventNode)
2567 m_previousWheelScrolledNode = stopNode;
2570 #if ENABLE(GESTURE_EVENTS)
2571 bool EventHandler::handleGestureTapDown()
2573 FrameView* view = m_frame->view();
2576 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2577 scrollAnimator->cancelAnimations();
2578 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2581 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2582 ScrollableArea* sa = *it;
2583 ScrollAnimator* animator = sa->scrollAnimator();
2585 animator->cancelAnimations();
2590 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2592 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2593 // eliminate the need for this.
2594 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2596 switch (gestureEvent.type()) {
2597 case PlatformEvent::GestureScrollBegin:
2598 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, false);
2599 case PlatformEvent::GestureScrollEnd:
2600 return handleGestureScrollCore(gestureEvent, ScrollByPixelVelocityWheelEvent, true);
2601 case PlatformEvent::GestureScrollUpdate:
2602 return handleGestureScrollUpdate(gestureEvent);
2603 case PlatformEvent::GestureTap:
2604 return handleGestureTap(gestureEvent);
2605 case PlatformEvent::GestureTapDown:
2606 return handleGestureTapDown();
2607 case PlatformEvent::GestureDoubleTap:
2608 case PlatformEvent::GestureLongPress:
2609 case PlatformEvent::GesturePinchBegin:
2610 case PlatformEvent::GesturePinchEnd:
2611 case PlatformEvent::GesturePinchUpdate:
2614 ASSERT_NOT_REACHED();
2620 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent)
2622 // 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.
2623 IntPoint adjustedPoint = gestureEvent.position();
2624 #if ENABLE(TOUCH_ADJUSTMENT)
2625 if (!gestureEvent.area().isEmpty())
2626 adjustGesturePosition(gestureEvent, adjustedPoint);
2629 bool defaultPrevented = false;
2630 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2631 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2632 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2633 mouseMoved(fakeMouseMove);
2634 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2635 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2636 return defaultPrevented;
2639 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2641 return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, true);
2644 bool EventHandler::handleGestureScrollCore(const PlatformGestureEvent& gestureEvent, PlatformWheelEventGranularity granularity, bool latchedWheel)
2646 TemporaryChange<bool> latched(m_useLatchedWheelEventNode, latchedWheel);
2647 const float tickDivisor = (float)WheelEvent::tickMultiplier;
2648 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2649 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2650 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2651 gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor,
2653 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2654 return handleWheelEvent(syntheticWheelEvent);
2658 #if ENABLE(TOUCH_ADJUSTMENT)
2659 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2661 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2662 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2663 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2665 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2666 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2668 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2669 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2670 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2671 // handle targetNode being a shadow DOM node.
2672 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2673 if (success && targetNode)
2674 targetNode = targetNode->shadowAncestorNode();
2678 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2680 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2681 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2682 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ true, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2684 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2685 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2686 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, *nodeList.get());
2689 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2691 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
2692 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2693 HitTestResult result = hitTestResultAtPoint(hitTestPoint, /*allowShadowContent*/ false, /*ignoreClipping*/ false, DontHitTestScrollbars, hitType, touchRadius);
2695 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2696 RefPtr<StaticHashSetNodeList> nodeList = StaticHashSetNodeList::adopt(result.rectBasedTestResult());
2697 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, *nodeList.get());
2700 bool EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2702 Node* targetNode = 0;
2703 switch (gestureEvent.type()) {
2704 case PlatformEvent::GestureTap:
2705 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2707 case PlatformEvent::GestureLongPress:
2708 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2711 // FIXME: Implement handling for other types as needed.
2712 ASSERT_NOT_REACHED();
2718 #if ENABLE(CONTEXT_MENUS)
2719 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2721 Document* doc = m_frame->document();
2722 FrameView* v = m_frame->view();
2727 LayoutPoint viewportPos = v->windowToContents(event.position());
2728 HitTestRequest request(HitTestRequest::Active);
2729 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2731 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2732 && !m_frame->selection()->contains(viewportPos)
2733 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2734 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2735 // available for text selections. But only if we're above text.
2736 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2737 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2738 selectClosestWordOrLinkFromMouseEvent(mev);
2741 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2743 return swallowEvent;
2746 bool EventHandler::sendContextMenuEventForKey()
2748 FrameView* view = m_frame->view();
2752 Document* doc = m_frame->document();
2756 static const int kContextMenuMargin = 1;
2758 #if OS(WINDOWS) && !OS(WINCE)
2759 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2761 int rightAligned = 0;
2765 Node* focusedNode = doc->focusedNode();
2766 FrameSelection* selection = m_frame->selection();
2767 Position start = selection->selection().start();
2769 if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) {
2770 RefPtr<Range> selectionRange = selection->toNormalizedRange();
2771 IntRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get());
2773 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2774 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2775 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2776 location = IntPoint(x, y);
2777 } else if (focusedNode) {
2778 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2781 IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2782 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2784 location = IntPoint(
2785 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2786 kContextMenuMargin);
2789 m_frame->view()->setCursor(pointerCursor());
2791 IntPoint position = view->contentsToRootView(location);
2792 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2794 Node* targetNode = doc->focusedNode();
2798 // Use the focused node as the target for hover and active.
2799 HitTestResult result(position);
2800 result.setInnerNode(targetNode);
2801 HitTestRequest request(HitTestRequest::Active);
2802 doc->renderView()->layer()->updateHoverActiveState(request, result);
2803 doc->updateStyleIfNeeded();
2805 // The contextmenu event is a mouse event even when invoked using the keyboard.
2806 // This is required for web compatibility.
2809 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2811 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2814 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2816 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2819 #if ENABLE(GESTURE_EVENTS)
2820 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2823 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2825 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2828 IntPoint adjustedPoint = event.position();
2829 #if ENABLE(TOUCH_ADJUSTMENT)
2830 if (!event.area().isEmpty())
2831 adjustGesturePosition(event, adjustedPoint);
2833 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2834 return sendContextMenuEvent(mouseEvent);
2836 #endif // ENABLE(GESTURE_EVENTS)
2837 #endif // ENABLE(CONTEXT_MENUS)
2839 void EventHandler::scheduleHoverStateUpdate()
2841 if (!m_hoverTimer.isActive())
2842 m_hoverTimer.startOneShot(0);
2845 void EventHandler::dispatchFakeMouseMoveEventSoon()
2850 Settings* settings = m_frame->settings();
2851 if (settings && !settings->deviceSupportsMouse())
2854 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2855 // reschedule the timer and use a longer time. This will cause the content
2856 // to receive these moves only after the user is done scrolling, reducing
2857 // pauses during the scroll.
2858 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2859 if (m_fakeMouseMoveEventTimer.isActive())
2860 m_fakeMouseMoveEventTimer.stop();
2861 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2863 if (!m_fakeMouseMoveEventTimer.isActive())
2864 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2868 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2870 FrameView* view = m_frame->view();
2874 if (!quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2877 dispatchFakeMouseMoveEventSoon();
2880 void EventHandler::cancelFakeMouseMoveEvent()
2882 m_fakeMouseMoveEventTimer.stop();
2885 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2887 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2888 ASSERT(!m_mousePressed);
2890 Settings* settings = m_frame->settings();
2891 if (settings && !settings->deviceSupportsMouse())
2894 FrameView* view = m_frame->view();
2902 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2903 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, m_currentMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2904 mouseMoved(fakeMouseMoveEvent);
2907 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2909 m_frameSetBeingResized = frameSet;
2912 void EventHandler::resizeLayerDestroyed()
2914 ASSERT(m_resizeLayer);
2918 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2920 m_hoverTimer.stop();
2923 ASSERT(m_frame->document());
2925 if (RenderView* renderer = m_frame->contentRenderer()) {
2926 if (FrameView* view = m_frame->view()) {
2927 HitTestRequest request(HitTestRequest::Move);
2928 HitTestResult result(view->windowToContents(m_currentMousePosition));
2929 renderer->hitTest(request, result);
2930 m_frame->document()->updateStyleIfNeeded();
2935 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2937 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2938 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2939 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2940 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2941 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2942 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2944 String key = evt.unmodifiedText();
2945 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2948 elem->accessKeyAction(false);
2953 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2959 #if ENABLE(FULLSCREEN_API)
2960 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2962 Document* document = m_frame->document();
2963 if (document->webkitFullScreenKeyboardInputAllowed())
2966 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2967 if (keyEvent.text().length() != 1)
2969 UChar character = keyEvent.text()[0];
2970 return character == ' ';
2973 int keyCode = keyEvent.windowsVirtualKeyCode();
2974 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2975 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2976 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2977 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2981 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2983 RefPtr<FrameView> protector(m_frame->view());
2985 #if ENABLE(FULLSCREEN_API)
2986 if (m_frame->document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
2990 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2991 capsLockStateMayHaveChanged();
2993 #if ENABLE(PAN_SCROLLING)
2994 if (Page* page = m_frame->page()) {
2995 if (page->mainFrame()->eventHandler()->m_panScrollInProgress) {
2996 // If a key is pressed while the panScroll is in progress then we want to stop
2997 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2998 stopAutoscrollTimer();
3000 // If we were in panscroll mode, we swallow the key event
3006 // Check for cases where we are too early for events -- possible unmatched key up
3007 // from pressing return in the location bar.
3008 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
3012 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3013 UserTypingGestureIndicator typingGestureIndicator(m_frame);
3015 if (FrameView* view = m_frame->view())
3016 view->resetDeferredRepaintDelay();
3018 // FIXME (bug 68185): this call should be made at another abstraction layer
3019 m_frame->loader()->resetMultipleFormSubmissionProtection();
3021 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3022 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3023 // with access keys. Then we dispatch keydown, but suppress its default handling.
3024 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3025 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3026 bool matchedAnAccessKey = false;
3027 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3028 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3030 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3031 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3032 return !node->dispatchKeyEvent(initialKeyEvent);
3034 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
3037 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3038 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3039 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown, backwardCompatibilityMode);
3040 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
3041 if (matchedAnAccessKey)
3042 keydown->setDefaultPrevented(true);
3043 keydown->setTarget(node);
3045 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3046 node->dispatchEvent(keydown, ec);
3047 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3048 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3049 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3052 // Run input method in advance of DOM event handling. This may result in the IM
3053 // modifying the page prior the keydown event, but this behaviour is necessary
3054 // in order to match IE:
3055 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
3056 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
3057 m_frame->editor()->handleInputMethodKeydown(keydown.get());
3059 bool handledByInputMethod = keydown->defaultHandled();
3061 if (handledByInputMethod) {
3062 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
3063 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
3064 keydown->setTarget(node);
3065 keydown->setDefaultHandled();
3068 node->dispatchEvent(keydown, ec);
3069 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3070 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
3071 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3072 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
3073 return keydownResult;
3075 // Focus may have changed during keydown handling, so refetch node.
3076 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3077 if (!keydownResult) {
3078 node = eventTargetNodeForDocument(m_frame->document());
3083 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3084 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char, backwardCompatibilityMode);
3085 if (keyPressEvent.text().isEmpty())
3086 return keydownResult;
3087 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
3088 keypress->setTarget(node);
3090 keypress->setDefaultPrevented(true);
3092 keypress->keypressCommands() = keydown->keypressCommands();
3094 node->dispatchEvent(keypress, ec);
3096 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3099 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3101 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
3102 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
3103 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
3104 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
3106 FocusDirection retVal = FocusDirectionNone;
3108 if (keyIdentifier == Down)
3109 retVal = FocusDirectionDown;
3110 else if (keyIdentifier == Up)
3111 retVal = FocusDirectionUp;
3112 else if (keyIdentifier == Left)
3113 retVal = FocusDirectionLeft;
3114 else if (keyIdentifier == Right)
3115 retVal = FocusDirectionRight;
3120 static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardEvent* event)
3125 bool isOptioned = event->getModifierState("Alt");
3126 bool isCommanded = event->getModifierState("Meta");
3128 SelectionDirection direction = DirectionForward;
3129 TextGranularity granularity = CharacterGranularity;
3131 switch (focusDirectionForKey(event->keyIdentifier())) {
3132 case FocusDirectionNone:
3134 case FocusDirectionForward:
3135 case FocusDirectionBackward:
3136 ASSERT_NOT_REACHED();
3138 case FocusDirectionUp:
3139 direction = DirectionBackward;
3140 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3142 case FocusDirectionDown:
3143 direction = DirectionForward;
3144 granularity = isCommanded ? DocumentBoundary : LineGranularity;
3146 case FocusDirectionLeft:
3147 direction = DirectionLeft;
3148 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3150 case FocusDirectionRight:
3151 direction = DirectionRight;
3152 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
3156 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
3157 selection->modify(alternation, direction, granularity, UserTriggered);
3158 event->setDefaultHandled();
3161 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3163 if (event->type() == eventNames().keydownEvent) {
3164 m_frame->editor()->handleKeyboardEvent(event);
3165 if (event->defaultHandled())
3167 if (event->keyIdentifier() == "U+0009")
3168 defaultTabEventHandler(event);
3169 else if (event->keyIdentifier() == "U+0008")
3170 defaultBackspaceEventHandler(event);
3172 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3173 if (direction != FocusDirectionNone)
3174 defaultArrowEventHandler(direction, event);
3177 // provides KB navigation and selection for enhanced accessibility users
3178 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
3179 handleKeyboardSelectionMovement(m_frame->selection(), event);
3181 if (event->type() == eventNames().keypressEvent) {
3182 m_frame->editor()->handleKeyboardEvent(event);
3183 if (event->defaultHandled())
3185 if (event->charCode() == ' ')
3186 defaultSpaceEventHandler(event);
3190 #if ENABLE(DRAG_SUPPORT)
3191 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3193 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3194 return dragHysteresisExceeded(dragViewportLocation);
3197 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3199 FrameView* view = m_frame->view();
3202 IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3203 IntSize delta = dragLocation - m_mouseDownPos;
3205 int threshold = GeneralDragHysteresis;
3206 switch (dragState().m_dragType) {
3207 case DragSourceActionSelection:
3208 threshold = TextDragHysteresis;
3210 case DragSourceActionImage:
3211 threshold = ImageDragHysteresis;
3213 case DragSourceActionLink:
3214 threshold = LinkDragHysteresis;
3216 case DragSourceActionDHTML:
3218 case DragSourceActionNone:
3219 case DragSourceActionAny:
3220 ASSERT_NOT_REACHED();
3223 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3226 void EventHandler::freeClipboard()
3228 if (dragState().m_dragClipboard)
3229 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3232 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3234 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3235 HitTestRequest request(HitTestRequest::Release);
3236 prepareMouseEvent(request, event);
3238 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
3239 dragState().m_dragClipboard->setDestinationOperation(operation);
3240 // for now we don't care if event handler cancels default behavior, since there is none
3241 dispatchDragSrcEvent(eventNames().dragendEvent, event);
3244 dragState().m_dragSrc = 0;
3245 // In case the drag was ended due to an escape key press we need to ensure
3246 // that consecutive mousemove events don't reinitiate the drag and drop.
3247 m_mouseDownMayStartDrag = false;
3250 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3252 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3253 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3254 dragState().m_dragSrc = rootEditableElement;
3257 // returns if we should continue "default processing", i.e., whether eventhandler canceled
3258 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3260 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3263 static bool ExactlyOneBitSet(DragSourceAction n)
3265 return n && !(n & (n - 1));
3268 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
3270 #if ENABLE(TIZEN_DRAG_SUPPORT)
3271 if (!m_frame->page()->dragController()->dragState())
3274 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3275 // If we allowed the other side of the bridge to handle a drag
3276 // last time, then m_mousePressed might still be set. So we
3277 // clear it now to make sure the next move after a drag
3278 // doesn't look like a drag.
3279 m_mousePressed = false;
3284 if (eventLoopHandleMouseDragged(event))
3287 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
3289 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
3290 dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents;
3292 // try to find an element that wants to be dragged
3293 HitTestRequest request(HitTestRequest::ReadOnly);
3294 HitTestResult result(m_mouseDownPos);
3295 m_frame->contentRenderer()->hitTest(request, result);
3296 Node* node = result.innerNode();
3297 if (node && m_frame->page())
3298 dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState());
3300 dragState().m_dragSrc = 0;
3302 if (!dragState().m_dragSrc)
3303 m_mouseDownMayStartDrag = false; // no element is draggable
3305 m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection);
3308 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
3309 // or else we bail on the dragging stuff and allow selection to occur
3310 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
3311 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3312 if ((dragState().m_dragType & DragSourceActionImage)) {
3313 // ... unless the mouse is over an image, then we start dragging just the image
3314 dragState().m_dragType = DragSourceActionImage;
3315 } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) {
3316 // ... but only bail if we're not over an unselectable element.
3317 m_mouseDownMayStartDrag = false;
3318 dragState().m_dragSrc = 0;
3319 // ... but if this was the first click in the window, we don't even want to start selection
3320 if (eventActivatedView(event.event()))
3321 m_mouseDownMayStartSelect = false;
3323 // Prevent the following case from occuring:
3324 // 1. User starts a drag immediately after mouse down over an unselectable element.
3325 // 2. We enter this block and decided that since we're over an unselectable element,
3326 // don't cancel the drag.
3327 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't
3328 // exceeded the drag hysteresis yet.
3329 // 4. We enter this block again, and since it's now marked as a selection drag, we
3331 m_dragMayStartSelectionInstead = false;
3335 if (!m_mouseDownMayStartDrag)
3336 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3338 if (!ExactlyOneBitSet(dragState().m_dragType)) {
3339 ASSERT((dragState().m_dragType & DragSourceActionSelection));
3340 ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML
3341 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage
3342 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink);
3343 dragState().m_dragType = DragSourceActionSelection;
3346 // We are starting a text/image/url drag, so the cursor should be an arrow
3347 if (FrameView* view = m_frame->view()) {
3348 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3349 view->setCursor(pointerCursor());
3352 if (!dragHysteresisExceeded(event.event().position()))
3355 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3358 DragOperation srcOp = DragOperationNone;
3360 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3361 // to make sure it gets numbified
3362 dragState().m_dragClipboard = createDraggingClipboard();
3364 if (dragState().shouldDispatchEvents()) {
3365 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
3367 if (dragState().m_dragType == DragSourceActionDHTML) {
3368 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3369 // FIXME: This doesn't work correctly with transforms.
3370 FloatPoint absPos = renderer->localToAbsolute();
3371 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3372 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
3374 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3375 // the element in some way. In this case we just kill the drag.
3376 m_mouseDownMayStartDrag = false;
3381 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
3382 && !m_frame->selection()->isInPasswordField();
3384 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3385 // image can still be changed as we drag, but not the pasteboard data.
3386 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3388 if (m_mouseDownMayStartDrag) {
3389 // gather values from DHTML element, if it set any
3390 srcOp = dragState().m_dragClipboard->sourceOperation();
3392 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
3393 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
3394 // started the drag when that happens. So we have to assume it's started before we
3396 dragState().m_dragClipboard->setDragHasStarted();
3400 if (m_mouseDownMayStartDrag) {
3401 Page* page = m_frame->page();
3402 DragController* dragController = page ? page->dragController() : 0;
3403 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
3404 // In WebKit2 we could reenter this code and start another drag.
3405 // On OS X this causes problems with the ownership of the pasteboard
3406 // and the promised types.
3408 m_mouseDownMayStartDrag = false;
3411 if (dragState().shouldDispatchEvents()) {
3412 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3413 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
3414 m_mouseDownMayStartDrag = false;
3419 if (!m_mouseDownMayStartDrag) {
3420 // something failed to start the drag, cleanup
3422 dragState().m_dragSrc = 0;
3425 // No more default handling (like selection), whether we're past the hysteresis bounds or not
3428 #endif // ENABLE(DRAG_SUPPORT)
3430 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3432 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3433 // and avoid dispatching text input events from keydown default handlers.
3434 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
3439 EventTarget* target;
3440 if (underlyingEvent)
3441 target = underlyingEvent->target();
3443 target = eventTargetNodeForDocument(m_frame->document());
3447 if (FrameView* view = m_frame->view())
3448 view->resetDeferredRepaintDelay();
3450 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3451 event->setUnderlyingEvent(underlyingEvent);
3454 target->dispatchEvent(event, ec);
3455 return event->defaultHandled();
3458 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
3461 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
3463 && event->keyIdentifier() == "U+0009";
3466 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
3468 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(EFL)
3469 return EventHandler::isKeyboardOptionTab(event);
3475 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
3477 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
3479 Page* page = m_frame->page();
3483 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
3484 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
3487 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3489 if (m_frame->editor()->handleTextEvent(event))
3490 event->setDefaultHandled();
3494 // Qt handles the space event in platform-specific WebKit code.
3495 // Eventually it would be good to eliminate that and use the code here instead.
3496 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
3501 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3503 ASSERT(event->type() == eventNames().keypressEvent);
3505 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3508 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3509 if (logicalScrollOverflow(direction, ScrollByPage)) {
3510 event->setDefaultHandled();
3514 FrameView* view = m_frame->view();
3518 if (view->logicalScroll(direction, ScrollByPage))
3519 event->setDefaultHandled();
3524 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3526 ASSERT(event->type() == eventNames().keydownEvent);
3528 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3531 if (!m_frame->editor()->behavior().shouldNavigateBackOnBackspace())
3534 Page* page = m_frame->page();
3538 if (!m_frame->settings()->backspaceKeyNavigationEnabled())
3541 bool handledEvent = false;
3543 if (event->shiftKey())
3544 handledEvent = page->goForward();
3546 handledEvent = page->goBack();
3549 event->setDefaultHandled();
3553 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3555 ASSERT(event->type() == eventNames().keydownEvent);
3557 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3560 Page* page = m_frame->page();
3564 if (!isSpatialNavigationEnabled(m_frame))
3567 // Arrows and other possible directional navigation keys can be used in design
3569 if (m_frame->document()->inDesignMode())
3572 if (page->focusController()->advanceFocus(focusDirection, event))
3573 event->setDefaultHandled();
3576 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3578 ASSERT(event->type() == eventNames().keydownEvent);
3580 // We should only advance focus on tabs if no special modifier keys are held down.
3581 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3584 Page* page = m_frame->page();
3587 if (!page->tabKeyCyclesThroughElements())
3590 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3592 // Tabs can be used in design mode editing.
3593 if (m_frame->document()->inDesignMode())
3596 if (page->focusController()->advanceFocus(focusDirection, event))
3597 event->setDefaultHandled();
3600 void EventHandler::capsLockStateMayHaveChanged()
3602 Document* d = m_frame->document();
3603 if (Node* node = d->focusedNode()) {
3604 if (RenderObject* r = node->renderer()) {
3605 if (r->isTextField())
3606 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3611 void EventHandler::sendResizeEvent()
3613 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
3616 void EventHandler::sendScrollEvent()
3618 setFrameWasScrolledByUser();
3619 if (m_frame->view() && m_frame->document())
3620 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), DocumentEventQueue::ScrollEventDocumentTarget);
3623 void EventHandler::setFrameWasScrolledByUser()
3625 FrameView* v = m_frame->view();
3627 v->setWasScrolledByUser(true);
3630 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3632 if (!scrollbar || !scrollbar->enabled())
3634 setFrameWasScrolledByUser();
3635 return scrollbar->mouseDown(mev.event());
3638 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3639 // last to scrollbar if setLast is true; else set last to 0.
3640 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3642 if (m_lastScrollbarUnderMouse != scrollbar) {
3643 // Send mouse exited to the old scrollbar.
3644 if (m_lastScrollbarUnderMouse)
3645 m_lastScrollbarUnderMouse->mouseExited();
3647 // Send mouse entered if we're setting a new scrollbar.
3648 if (scrollbar && setLast)
3649 scrollbar->mouseEntered();
3651 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3655 #if ENABLE(TOUCH_EVENTS)
3657 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3660 case PlatformTouchPoint::TouchReleased:
3661 return eventNames().touchendEvent;
3662 case PlatformTouchPoint::TouchCancelled:
3663 return eventNames().touchcancelEvent;
3664 case PlatformTouchPoint::TouchPressed:
3665 return eventNames().touchstartEvent;
3666 case PlatformTouchPoint::TouchMoved:
3667 return eventNames().touchmoveEvent;
3668 case PlatformTouchPoint::TouchStationary:
3669 // TouchStationary state is not converted to touch events, so fall through to assert.
3671 ASSERT_NOT_REACHED();
3676 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3678 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3679 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3680 // for an overview of how these lists fit together.
3682 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3683 RefPtr<TouchList> touches = TouchList::create();
3685 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3686 // 'targetTouches' list in the JS event.
3687 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3688 TargetTouchesMap touchesByTarget;
3690 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3691 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3693 // The touches corresponding to the particular change state this struct instance represents.
3694 RefPtr<TouchList> m_touches;
3695 // Set of targets involved in m_touches.
3696 EventTargetSet m_targets;
3697 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3699 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3701 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3703 for (unsigned i = 0; i < points.size(); ++i) {
3704 const PlatformTouchPoint& point = points[i];
3705 PlatformTouchPoint::State pointState = point.state();
3706 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3708 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
3709 // The HitTestRequest types used for mouse events map quite adequately
3710 // to touch events. Note that in addition to meaning that the hit test
3711 // should affect the active state of the current node if necessary,
3712 // HitTestRequest::Active signifies that the hit test is taking place
3713 // with the mouse (or finger in this case) being pressed.
3714 switch (pointState) {
3715 case PlatformTouchPoint::TouchPressed:
3716 hitType |= HitTestRequest::Active;
3718 case PlatformTouchPoint::TouchMoved:
3719 hitType |= HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ReadOnly;
3721 case PlatformTouchPoint::TouchReleased:
3722 case PlatformTouchPoint::TouchCancelled:
3723 hitType |= HitTestRequest::Release;
3725 case PlatformTouchPoint::TouchStationary:
3726 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
3729 ASSERT_NOT_REACHED();
3733 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3734 unsigned touchPointTargetKey = point.id() + 1;
3735 RefPtr<EventTarget> touchTarget;
3736 if (pointState == PlatformTouchPoint::TouchPressed) {
3737 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3738 Node* node = result.innerNode();
3741 #if ENABLE(TIZEN_PREVENT_CRASH_OF_TOUCH_EVENTS)
3746 // Touch events should not go to text nodes
3747 if (node->isTextNode())
3748 node = node->parentNode();
3750 Document* doc = node->document();
3754 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3757 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3759 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3760 // We only perform a hittest on release or cancel to unset :active or :hover state.
3761 hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3762 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3763 // we also remove it from the map.
3764 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3766 // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3767 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3769 if (!touchTarget.get())
3771 Document* doc = touchTarget->toNode()->document();
3774 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3776 Frame* targetFrame = doc->frame();
3780 if (m_frame != targetFrame) {
3781 // pagePoint should always be relative to the target elements containing frame.
3782 pagePoint = documentPointForWindowPoint(targetFrame, point.pos());
3785 float scaleFactor = targetFrame->pageZoomFactor() * targetFrame->frameScaleFactor();
3787 int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3788 int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3790 RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3791 point.screenPos().x(), point.screenPos().y(),
3792 adjustedPageX, adjustedPageY,
3793 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3795 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3796 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3797 if (targetTouchesIterator == touchesByTarget.end())
3798 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3800 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3801 // released or cancelled it will only appear in the changedTouches list.
3802 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3803 touches->append(touch);
3804 targetTouchesIterator->second->append(touch);
3807 // Now build up the correct list for changedTouches.
3808 // Note that any touches that are in the TouchStationary state (e.g. if
3809 // the user had several points touched but did not move them all) should
3810 // never be in the changedTouches list so we do not handle them explicitly here.
3811 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3812 // about the TouchStationary state.
3813 if (pointState != PlatformTouchPoint::TouchStationary) {
3814 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3815 if (!changedTouches[pointState].m_touches)
3816 changedTouches[pointState].m_touches = TouchList::create();
3817 changedTouches[pointState].m_touches->append(touch);
3818 changedTouches[pointState].m_targets.add(touchTarget);
3821 m_touchPressed = touches->length() > 0;
3823 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3824 bool swallowedEvent = false;
3825 RefPtr<TouchList> emptyList = TouchList::create();
3826 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3827 if (!changedTouches[state].m_touches)
3830 // When sending a touch cancel event, use empty touches and targetTouches lists.
3831 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3832 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3833 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3834 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3836 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3837 EventTarget* touchEventTarget = it->get();
3838 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3839 ASSERT(targetTouches);
3841 RefPtr<TouchEvent> touchEvent =
3842 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3843 stateName, touchEventTarget->toNode()->document()->defaultView(),
3844 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3845 ExceptionCode ec = 0;
3846 touchEventTarget->dispatchEvent(touchEvent.get(), ec);
3847 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3851 return swallowedEvent;
3854 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
3856 if (!m_frame || !m_frame->settings() || !m_frame->settings()->isTouchEventEmulationEnabled())
3859 PlatformEvent::Type eventType = event.type();
3860 if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
3863 if (eventType == PlatformEvent::MouseMoved && !m_touchPressed)
3866 SyntheticSingleTouchEvent touchEvent(event);
3867 return handleTouchEvent(touchEvent);