2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "EventHandler.h"
30 #include "AXObjectCache.h"
31 #include "CachedImage.h"
33 #include "ChromeClient.h"
35 #include "CursorList.h"
37 #include "DragController.h"
38 #include "DragState.h"
40 #include "EventNames.h"
41 #include "EventQueue.h"
42 #include "FloatPoint.h"
43 #include "FloatRect.h"
44 #include "FocusController.h"
46 #include "FrameLoader.h"
47 #include "FrameSelection.h"
48 #include "FrameTree.h"
49 #include "FrameView.h"
50 #include "htmlediting.h"
51 #include "HTMLFrameElementBase.h"
52 #include "HTMLFrameSetElement.h"
53 #include "HTMLInputElement.h"
54 #include "HTMLNames.h"
55 #include "HitTestRequest.h"
56 #include "HitTestResult.h"
58 #include "InspectorInstrumentation.h"
59 #include "KeyboardEvent.h"
60 #include "MouseEvent.h"
61 #include "MouseEventWithHitTestResults.h"
63 #include "PlatformKeyboardEvent.h"
64 #include "PlatformWheelEvent.h"
65 #include "PluginDocument.h"
66 #include "RenderFrameSet.h"
67 #include "RenderLayer.h"
68 #include "RenderTextControlSingleLine.h"
69 #include "RenderView.h"
70 #include "RenderWidget.h"
71 #include "ScrollAnimator.h"
72 #include "Scrollbar.h"
74 #include "SpatialNavigation.h"
75 #include "StyleCachedImage.h"
76 #include "TextEvent.h"
77 #include "TextIterator.h"
78 #include "UserGestureIndicator.h"
79 #include "UserTypingGestureIndicator.h"
80 #include "WheelEvent.h"
81 #include "WindowsKeyboardCodes.h"
82 #include <wtf/Assertions.h>
83 #include <wtf/CurrentTime.h>
84 #include <wtf/StdLibExtras.h>
86 #if ENABLE(GESTURE_EVENTS)
87 #include "PlatformGestureEvent.h"
91 #include "SVGDocument.h"
92 #include "SVGElementInstance.h"
94 #include "SVGUseElement.h"
97 #if ENABLE(TOUCH_EVENTS)
98 #include "PlatformTouchEvent.h"
99 #include "TouchEvent.h"
100 #include "TouchList.h"
105 using namespace HTMLNames;
107 #if ENABLE(DRAG_SUPPORT)
108 // The link drag hysteresis is much larger than the others because there
109 // needs to be enough space to cancel the link press without starting a link drag,
110 // and because dragging links is rare.
111 const int LinkDragHysteresis = 40;
112 const int ImageDragHysteresis = 5;
113 const int TextDragHysteresis = 3;
114 const int GeneralDragHysteresis = 3;
115 #endif // ENABLE(DRAG_SUPPORT)
117 // Match key code of composition keydown event on windows.
118 // IE sends VK_PROCESSKEY which has value 229;
119 const int CompositionEventKeyCode = 229;
122 using namespace SVGNames;
125 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
126 const double autoscrollInterval = 0.05;
128 const double fakeMouseMoveInterval = 0.1;
130 static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
135 if (!node->renderer())
138 // Find the nearest enclosing box.
139 RenderBox* enclosingBox = node->renderer()->enclosingBox();
141 float absDelta = delta > 0 ? delta : -delta;
143 if (granularity == WheelEvent::Page)
144 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode);
146 if (granularity == WheelEvent::Line)
147 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode);
149 if (granularity == WheelEvent::Pixel)
150 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode);
157 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
162 #if ENABLE(DRAG_SUPPORT)
163 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
171 EventHandler::EventHandler(Frame* frame)
173 , m_mousePressed(false)
174 , m_capturesDragging(false)
175 , m_mouseDownMayStartSelect(false)
176 #if ENABLE(DRAG_SUPPORT)
177 , m_mouseDownMayStartDrag(false)
178 , m_dragMayStartSelectionInstead(false)
180 , m_mouseDownWasSingleClickInSelection(false)
181 , m_selectionInitiationState(HaveNotStartedSelection)
182 , m_panScrollInProgress(false)
183 , m_panScrollButtonPressed(false)
184 , m_springLoadedPanScrollInProgress(false)
185 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
186 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
187 , m_autoscrollRenderer(0)
188 , m_autoscrollInProgress(false)
189 , m_mouseDownMayStartAutoscroll(false)
190 , m_mouseDownWasInSubframe(false)
191 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
196 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
198 , m_mouseDownTimestamp(0)
199 , m_useLatchedWheelEventNode(false)
200 , m_widgetIsLatched(false)
202 , m_mouseDownView(nil)
203 , m_sendingEventToSubview(false)
204 , m_activationEventNumber(-1)
206 #if ENABLE(TOUCH_EVENTS)
207 , m_touchPressed(false)
212 EventHandler::~EventHandler()
214 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
217 #if ENABLE(DRAG_SUPPORT)
218 DragState& EventHandler::dragState()
220 DEFINE_STATIC_LOCAL(DragState, state, ());
223 #endif // ENABLE(DRAG_SUPPORT)
225 void EventHandler::clear()
228 m_fakeMouseMoveEventTimer.stop();
230 m_nodeUnderMouse = 0;
231 m_lastNodeUnderMouse = 0;
233 m_instanceUnderMouse = 0;
234 m_lastInstanceUnderMouse = 0;
236 m_lastMouseMoveEventSubframe = 0;
237 m_lastScrollbarUnderMouse = 0;
240 m_frameSetBeingResized = 0;
241 #if ENABLE(DRAG_SUPPORT)
243 m_shouldOnlyFireDragOverEvent = false;
245 m_currentMousePosition = LayoutPoint();
246 m_mousePressNode = 0;
247 m_mousePressed = false;
248 m_capturesDragging = false;
249 m_capturingMouseEventsNode = 0;
250 m_latchedWheelEventNode = 0;
251 m_previousWheelScrolledNode = 0;
252 #if ENABLE(TOUCH_EVENTS)
253 m_originatingTouchPointTargets.clear();
257 void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved)
259 if (nodeToBeRemoved->contains(m_clickNode.get()))
263 static void setSelectionIfNeeded(FrameSelection* selection, const VisibleSelection& newSelection)
266 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
267 selection->setSelection(newSelection);
270 static inline bool dispatchSelectStart(Node* node)
272 if (!node || !node->renderer())
275 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
278 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& newSelection, TextGranularity granularity)
280 if (!dispatchSelectStart(targetNode))
283 if (newSelection.isRange())
284 m_selectionInitiationState = ExtendedSelection;
286 granularity = CharacterGranularity;
287 m_selectionInitiationState = PlacedCaret;
290 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, granularity);
295 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
297 Node* innerNode = targetNode(result);
298 VisibleSelection newSelection;
300 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
301 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
302 if (pos.isNotNull()) {
303 newSelection = VisibleSelection(pos);
304 newSelection.expandUsingGranularity(WordGranularity);
307 if (newSelection.isRange() && result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
308 newSelection.appendTrailingWhitespace();
310 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
314 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
316 if (!result.hitTestResult().isLiveLink())
317 return selectClosestWordFromMouseEvent(result);
319 Node* innerNode = targetNode(result);
321 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
322 VisibleSelection newSelection;
323 Element* URLElement = result.hitTestResult().URLElement();
324 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
325 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
326 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
328 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, WordGranularity);
332 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
334 if (event.event().button() != LeftButton)
337 if (m_frame->selection()->isRange())
338 // A double-click when range is already selected
339 // should not change the selection. So, do not call
340 // selectClosestWordFromMouseEvent, but do set
341 // m_beganSelectingText to prevent handleMouseReleaseEvent
342 // from setting caret selection.
343 m_selectionInitiationState = ExtendedSelection;
345 selectClosestWordFromMouseEvent(event);
350 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
352 if (event.event().button() != LeftButton)
355 Node* innerNode = targetNode(event);
356 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
359 VisibleSelection newSelection;
360 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
361 if (pos.isNotNull()) {
362 newSelection = VisibleSelection(pos);
363 newSelection.expandUsingGranularity(ParagraphGranularity);
366 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, ParagraphGranularity);
369 static int textDistance(const Position& start, const Position& end)
371 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
372 return TextIterator::rangeLength(range.get(), true);
375 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
377 Node* innerNode = targetNode(event);
378 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
381 // Extend the selection if the Shift key is down, unless the click is in a link.
382 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
384 // Don't restart the selection when the mouse is pressed on an
385 // existing selection so we can allow for text dragging.
386 if (FrameView* view = m_frame->view()) {
387 LayoutPoint vPoint = view->windowToContents(event.event().pos());
388 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
389 m_mouseDownWasSingleClickInSelection = true;
394 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
395 if (visiblePos.isNull())
396 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
397 Position pos = visiblePos.deepEquivalent();
399 VisibleSelection newSelection = m_frame->selection()->selection();
400 TextGranularity granularity = CharacterGranularity;
402 if (extendSelection && newSelection.isCaretOrRange()) {
403 ASSERT(m_frame->settings());
404 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
405 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
406 // was created right-to-left
407 Position start = newSelection.start();
408 Position end = newSelection.end();
409 int distanceToStart = textDistance(start, pos);
410 int distanceToEnd = textDistance(pos, end);
411 if (distanceToStart <= distanceToEnd)
412 newSelection = VisibleSelection(end, pos);
414 newSelection = VisibleSelection(start, pos);
416 newSelection.setExtent(pos);
418 if (m_frame->selection()->granularity() != CharacterGranularity) {
419 granularity = m_frame->selection()->granularity();
420 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
423 newSelection = VisibleSelection(visiblePos);
425 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
428 static inline bool canMouseDownStartSelect(Node* node)
430 if (!node || !node->renderer())
433 if (!node->canStartSelection())
439 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
441 #if ENABLE(DRAG_SUPPORT)
443 dragState().m_dragSrc = 0;
446 cancelFakeMouseMoveEvent();
448 if (ScrollView* scrollView = m_frame->view()) {
449 if (scrollView->isPointInScrollbarCorner(event.event().pos()))
453 bool singleClick = event.event().clickCount() <= 1;
455 // If we got the event back, that must mean it wasn't prevented,
456 // so it's allowed to start a drag or selection.
457 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
459 #if ENABLE(DRAG_SUPPORT)
460 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
461 m_mouseDownMayStartDrag = singleClick;
464 m_mouseDownWasSingleClickInSelection = false;
466 m_mouseDown = event.event();
468 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
472 if (m_frame->document()->isSVGDocument()
473 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
474 if (event.event().shiftKey() && singleClick) {
476 static_cast<SVGDocument*>(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().pos()));
482 // We don't do this at the start of mouse down handling,
483 // because we don't want to do it until we know we didn't hit a widget.
487 Node* innerNode = targetNode(event);
489 m_mousePressNode = innerNode;
490 #if ENABLE(DRAG_SUPPORT)
491 m_dragStartPos = event.event().pos();
494 bool swallowEvent = false;
495 m_mousePressed = true;
496 m_selectionInitiationState = HaveNotStartedSelection;
498 if (event.event().clickCount() == 2)
499 swallowEvent = handleMousePressEventDoubleClick(event);
500 else if (event.event().clickCount() >= 3)
501 swallowEvent = handleMousePressEventTripleClick(event);
503 swallowEvent = handleMousePressEventSingleClick(event);
505 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
506 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
511 // There are two kinds of renderer that can autoscroll.
512 static bool canAutoscroll(RenderObject* renderer)
514 if (!renderer->isBox())
517 // Check for a box that can be scrolled in its own right.
518 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
521 // Check for a box that represents the top level of a web page.
522 // This can be scrolled by calling Chrome::scrollRectIntoView.
523 // This only has an effect on the Mac platform in applications
524 // that put web views into scrolling containers, such as Mac OS X Mail.
525 // The code for this is in RenderLayer::scrollRectToVisible.
526 if (renderer->node() != renderer->document())
528 Frame* frame = renderer->frame();
531 Page* page = frame->page();
532 return page && page->mainFrame() == frame;
535 #if ENABLE(DRAG_SUPPORT)
536 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
538 if (handleDrag(event))
544 Node* targetNode = EventHandler::targetNode(event);
545 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
548 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
549 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
552 m_mouseDownMayStartDrag = false;
554 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
555 // Find a renderer that can autoscroll.
556 RenderObject* renderer = targetNode->renderer();
557 while (renderer && !canAutoscroll(renderer)) {
558 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
559 renderer = renderer->document()->ownerElement()->renderer();
561 renderer = renderer->parent();
565 m_autoscrollInProgress = true;
566 handleAutoscroll(renderer);
569 m_mouseDownMayStartAutoscroll = false;
572 if (m_selectionInitiationState != ExtendedSelection) {
573 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
574 HitTestResult result(m_mouseDownPos);
575 m_frame->document()->renderView()->layer()->hitTest(request, result);
577 updateSelectionForMouseDrag(result);
579 updateSelectionForMouseDrag(event.hitTestResult());
583 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
585 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
586 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
587 // in handleMousePressEvent
589 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
592 if (event.button() != LeftButton || event.clickCount() != 1)
595 FrameView* view = m_frame->view();
599 Page* page = m_frame->page();
603 updateDragSourceActionsAllowed();
604 HitTestRequest request(HitTestRequest::ReadOnly);
605 HitTestResult result(view->windowToContents(event.pos()));
606 m_frame->contentRenderer()->layer()->hitTest(request, result);
608 return result.innerNode() && page->dragController()->draggableNode(m_frame, result.innerNode(), result.point(), state);
611 void EventHandler::updateSelectionForMouseDrag()
613 FrameView* view = m_frame->view();
616 RenderView* renderer = m_frame->contentRenderer();
619 RenderLayer* layer = renderer->layer();
623 HitTestRequest request(HitTestRequest::ReadOnly |
624 HitTestRequest::Active |
625 HitTestRequest::MouseMove);
626 HitTestResult result(view->windowToContents(m_currentMousePosition));
627 layer->hitTest(request, result);
628 updateSelectionForMouseDrag(result);
631 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const LayoutPoint& localPoint, Node* targetNode)
633 LayoutPoint selectionEndPoint = localPoint;
634 Element* editableElement = selection.rootEditableElement();
636 if (!targetNode->renderer())
637 return VisiblePosition();
639 if (editableElement && !editableElement->contains(targetNode)) {
640 if (!editableElement->renderer())
641 return VisiblePosition();
643 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
644 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
645 targetNode = editableElement;
648 return targetNode->renderer()->positionForPoint(selectionEndPoint);
651 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
653 if (!m_mouseDownMayStartSelect)
656 Node* target = targetNode(hitTestResult);
660 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
662 // Don't modify the selection if we're not on a node.
663 if (targetPosition.isNull())
666 // Restart the selection if this is the first mouse move. This work is usually
667 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
668 VisibleSelection newSelection = m_frame->selection()->selection();
671 // Special case to limit selection to the containing block for SVG text.
672 // FIXME: Isn't there a better non-SVG-specific way to do this?
673 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
674 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
675 if (selectionBaseRenderer->isSVGText())
676 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
680 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
683 if (m_selectionInitiationState != ExtendedSelection) {
684 // Always extend selection here because it's caused by a mouse drag
685 m_selectionInitiationState = ExtendedSelection;
686 newSelection = VisibleSelection(targetPosition);
689 newSelection.setExtent(targetPosition);
690 if (m_frame->selection()->granularity() != CharacterGranularity)
691 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
693 m_frame->selection()->setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection()->granularity());
695 #endif // ENABLE(DRAG_SUPPORT)
697 void EventHandler::lostMouseCapture()
699 m_frame->selection()->setCaretBlinkingSuspended(false);
702 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
704 if (eventLoopHandleMouseUp(event))
707 // If this was the first click in the window, we don't even want to clear the selection.
708 // This case occurs when the user clicks on a draggable element, since we have to process
709 // the mouse down and drag events to see if we might start a drag. For other first clicks
710 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
711 // ignored upstream of this layer.
712 return eventActivatedView(event.event());
715 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
717 if (m_autoscrollInProgress)
718 stopAutoscrollTimer();
720 if (handleMouseUp(event))
723 // Used to prevent mouseMoveEvent from initiating a drag before
724 // the mouse is pressed again.
725 m_frame->selection()->setCaretBlinkingSuspended(false);
726 m_mousePressed = false;
727 m_capturesDragging = false;
728 #if ENABLE(DRAG_SUPPORT)
729 m_mouseDownMayStartDrag = false;
731 m_mouseDownMayStartSelect = false;
732 m_mouseDownMayStartAutoscroll = false;
733 m_mouseDownWasInSubframe = false;
735 bool handled = false;
737 // Clear the selection if the mouse didn't move after the last mouse
738 // press and it's not a context menu click. We do this so when clicking
739 // on the selection, the selection goes away. However, if we are
740 // editing, place the caret.
741 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
742 #if ENABLE(DRAG_SUPPORT)
743 && m_dragStartPos == event.event().pos()
745 && m_frame->selection()->isRange()
746 && event.event().button() != RightButton) {
747 VisibleSelection newSelection;
748 Node* node = targetNode(event);
749 bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
750 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
751 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
752 newSelection = VisibleSelection(pos);
755 setSelectionIfNeeded(m_frame->selection(), newSelection);
760 m_frame->selection()->notifyRendererOfSelectionChange(UserTriggered);
762 m_frame->selection()->selectFrameElementInParentIfFullySelected();
767 void EventHandler::handleAutoscroll(RenderObject* renderer)
769 // We don't want to trigger the autoscroll or the panScroll if it's already active
770 if (m_autoscrollTimer.isActive())
773 setAutoscrollRenderer(renderer);
775 #if ENABLE(PAN_SCROLLING)
776 if (m_panScrollInProgress) {
777 m_panScrollStartPos = currentMousePosition();
778 if (FrameView* view = m_frame->view())
779 view->addPanScrollIcon(m_panScrollStartPos);
780 // If we're not in the top frame we notify it that we doing a panScroll.
781 if (Page* page = m_frame->page()) {
782 Frame* mainFrame = page->mainFrame();
783 if (m_frame != mainFrame)
784 mainFrame->eventHandler()->m_panScrollInProgress = true;
789 startAutoscrollTimer();
792 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
794 RenderObject* r = autoscrollRenderer();
795 if (!r || !r->isBox()) {
796 stopAutoscrollTimer();
800 if (m_autoscrollInProgress) {
801 if (!m_mousePressed) {
802 stopAutoscrollTimer();
805 toRenderBox(r)->autoscroll();
807 // we verify that the main frame hasn't received the order to stop the panScroll
808 if (Page* page = m_frame->page()) {
809 if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) {
810 stopAutoscrollTimer();
814 #if ENABLE(PAN_SCROLLING)
815 updatePanScrollState();
816 toRenderBox(r)->panScroll(m_panScrollStartPos);
821 #if ENABLE(PAN_SCROLLING)
823 void EventHandler::startPanScrolling(RenderObject* renderer)
825 m_panScrollInProgress = true;
826 m_panScrollButtonPressed = true;
827 handleAutoscroll(renderer);
831 void EventHandler::updatePanScrollState()
833 FrameView* view = m_frame->view();
837 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
838 // So we don't want to change the cursor over this area
839 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
840 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
841 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
842 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
844 if ((east || west || north || south) && m_panScrollButtonPressed)
845 m_springLoadedPanScrollInProgress = true;
849 view->setCursor(northEastPanningCursor());
851 view->setCursor(northWestPanningCursor());
853 view->setCursor(northPanningCursor());
856 view->setCursor(southEastPanningCursor());
858 view->setCursor(southWestPanningCursor());
860 view->setCursor(southPanningCursor());
862 view->setCursor(eastPanningCursor());
864 view->setCursor(westPanningCursor());
866 view->setCursor(middlePanningCursor());
869 #endif // ENABLE(PAN_SCROLLING)
871 RenderObject* EventHandler::autoscrollRenderer() const
873 return m_autoscrollRenderer;
876 void EventHandler::updateAutoscrollRenderer()
878 if (!m_autoscrollRenderer)
881 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
883 if (Node* nodeAtPoint = hitTest.innerNode())
884 m_autoscrollRenderer = nodeAtPoint->renderer();
886 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
887 m_autoscrollRenderer = m_autoscrollRenderer->parent();
890 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
892 m_autoscrollRenderer = renderer;
895 #if ENABLE(DRAG_SUPPORT)
896 DragSourceAction EventHandler::updateDragSourceActionsAllowed() const
899 return DragSourceActionNone;
901 Page* page = m_frame->page();
903 return DragSourceActionNone;
905 FrameView* view = m_frame->view();
907 return DragSourceActionNone;
909 return page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
911 #endif // ENABLE(DRAG_SUPPORT)
913 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
915 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
916 if (!m_frame->contentRenderer())
919 hitType |= HitTestRequest::IgnoreClipping;
920 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
923 Node* n = result.innerNode();
924 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
926 RenderWidget* renderWidget = toRenderWidget(n->renderer());
927 Widget* widget = renderWidget->widget();
928 if (!widget || !widget->isFrameView())
930 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
931 if (!frame || !frame->contentRenderer())
933 FrameView* view = static_cast<FrameView*>(widget);
934 LayoutPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
935 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
936 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width());
937 frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
938 result = widgetHitTestResult;
940 if (testScrollbars == ShouldHitTestScrollbars) {
941 Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
943 result.setScrollbar(eventScrollbar);
947 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
948 // Another hit test at the main frame level should get us the correct visible result.
949 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
950 if (Page* page = m_frame->page()) {
951 Frame* mainFrame = page->mainFrame();
952 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
953 FrameView* resultView = resultFrame->view();
954 FrameView* mainView = mainFrame->view();
955 if (resultView && mainView) {
956 LayoutPoint windowPoint = resultView->contentsToWindow(result.point());
957 LayoutPoint mainFramePoint = mainView->windowToContents(windowPoint);
958 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
963 if (!allowShadowContent)
964 result.setToNonShadowAncestor();
970 void EventHandler::startAutoscrollTimer()
972 m_autoscrollTimer.startRepeating(autoscrollInterval);
975 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
977 if (m_autoscrollInProgress) {
978 if (m_mouseDownWasInSubframe) {
979 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
980 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
985 if (autoscrollRenderer()) {
986 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
987 toRenderBox(autoscrollRenderer())->stopAutoscroll();
988 #if ENABLE(PAN_SCROLLING)
989 if (m_panScrollInProgress) {
990 if (FrameView* view = m_frame->view()) {
991 view->removePanScrollIcon();
992 view->setCursor(pointerCursor());
997 setAutoscrollRenderer(0);
1000 m_autoscrollTimer.stop();
1002 m_panScrollInProgress = false;
1003 m_springLoadedPanScrollInProgress = false;
1005 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1006 if (Page* page = m_frame->page()) {
1007 Frame* mainFrame = page->mainFrame();
1008 if (m_frame != mainFrame)
1009 mainFrame->eventHandler()->m_panScrollInProgress = false;
1012 m_autoscrollInProgress = false;
1015 Node* EventHandler::mousePressNode() const
1017 return m_mousePressNode.get();
1020 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1022 m_mousePressNode = node;
1025 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1027 Node* node = startingNode;
1030 node = m_frame->document()->focusedNode();
1033 node = m_mousePressNode.get();
1036 RenderObject* r = node->renderer();
1037 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1038 setFrameWasScrolledByUser();
1046 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1048 Node* node = startingNode;
1051 node = m_frame->document()->focusedNode();
1054 node = m_mousePressNode.get();
1057 RenderObject* r = node->renderer();
1058 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1059 setFrameWasScrolledByUser();
1067 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1069 // The layout needs to be up to date to determine if we can scroll. We may be
1070 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1071 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1072 if (scrollOverflow(direction, granularity, startingNode))
1074 Frame* frame = m_frame;
1075 FrameView* view = frame->view();
1076 if (view && view->scroll(direction, granularity))
1078 frame = frame->tree()->parent();
1081 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1084 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1086 // The layout needs to be up to date to determine if we can scroll. We may be
1087 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1088 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1089 if (logicalScrollOverflow(direction, granularity, startingNode))
1091 Frame* frame = m_frame;
1092 FrameView* view = frame->view();
1094 bool scrolled = false;
1096 // Mac also resets the scroll position in the inline direction.
1097 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1100 if (view && view->logicalScroll(direction, granularity))
1106 frame = frame->tree()->parent();
1110 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1113 LayoutPoint EventHandler::currentMousePosition() const
1115 return m_currentMousePosition;
1118 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1120 if (!hitTestResult.isOverWidget())
1122 return subframeForTargetNode(targetNode(hitTestResult));
1125 Frame* EventHandler::subframeForTargetNode(Node* node)
1130 RenderObject* renderer = node->renderer();
1131 if (!renderer || !renderer->isWidget())
1134 Widget* widget = toRenderWidget(renderer)->widget();
1135 if (!widget || !widget->isFrameView())
1138 return static_cast<FrameView*>(widget)->frame();
1141 static bool isSubmitImage(Node* node)
1143 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1146 // Returns true if the node's editable block is not current focused for editing
1147 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1149 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1152 Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1154 Node* node = targetNode(event);
1155 RenderObject* renderer = node ? node->renderer() : 0;
1156 RenderStyle* style = renderer ? renderer->style() : 0;
1158 bool horizontalText = !style || style->isHorizontalWritingMode();
1159 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1161 // During selection, use an I-beam no matter what we're over.
1162 // If you're capturing mouse events for a particular node, don't treat this as a selection.
1163 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1166 if (renderer && renderer->isFrameSet()) {
1167 RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer);
1168 if (frameSetRenderer->canResizeRow(event.localPoint()))
1169 return rowResizeCursor();
1170 if (frameSetRenderer->canResizeColumn(event.localPoint()))
1171 return columnResizeCursor();
1174 if (style && style->cursors()) {
1175 const CursorList* cursors = style->cursors();
1176 for (unsigned i = 0; i < cursors->size(); ++i) {
1177 const CachedImage* cimage = 0;
1178 StyleImage* image = (*cursors)[i].image();
1179 if (image && image->isCachedImage())
1180 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1183 IntPoint hotSpot = (*cursors)[i].hotSpot();
1184 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1185 IntSize size = cimage->image()->size();
1186 if (size.width() > 128 || size.height() > 128)
1188 if (!cimage->errorOccurred())
1189 return Cursor(cimage->image(), hotSpot);
1193 switch (style ? style->cursor() : CURSOR_AUTO) {
1195 bool editable = (node && node->rendererIsEditable());
1196 bool editableLinkEnabled = false;
1198 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1200 ASSERT(m_frame->settings());
1201 switch (m_frame->settings()->editableLinkBehavior()) {
1203 case EditableLinkDefaultBehavior:
1204 case EditableLinkAlwaysLive:
1205 editableLinkEnabled = true;
1208 case EditableLinkNeverLive:
1209 editableLinkEnabled = false;
1212 case EditableLinkLiveWhenNotFocused:
1213 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1216 case EditableLinkOnlyLiveWithShiftKey:
1217 editableLinkEnabled = event.event().shiftKey();
1222 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1223 return handCursor();
1224 bool inResizer = false;
1226 if (RenderLayer* layer = renderer->enclosingLayer()) {
1227 if (FrameView* view = m_frame->view())
1228 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos()));
1231 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1233 return pointerCursor();
1236 return crossCursor();
1237 case CURSOR_POINTER:
1238 return handCursor();
1240 return moveCursor();
1241 case CURSOR_ALL_SCROLL:
1242 return moveCursor();
1243 case CURSOR_E_RESIZE:
1244 return eastResizeCursor();
1245 case CURSOR_W_RESIZE:
1246 return westResizeCursor();
1247 case CURSOR_N_RESIZE:
1248 return northResizeCursor();
1249 case CURSOR_S_RESIZE:
1250 return southResizeCursor();
1251 case CURSOR_NE_RESIZE:
1252 return northEastResizeCursor();
1253 case CURSOR_SW_RESIZE:
1254 return southWestResizeCursor();
1255 case CURSOR_NW_RESIZE:
1256 return northWestResizeCursor();
1257 case CURSOR_SE_RESIZE:
1258 return southEastResizeCursor();
1259 case CURSOR_NS_RESIZE:
1260 return northSouthResizeCursor();
1261 case CURSOR_EW_RESIZE:
1262 return eastWestResizeCursor();
1263 case CURSOR_NESW_RESIZE:
1264 return northEastSouthWestResizeCursor();
1265 case CURSOR_NWSE_RESIZE:
1266 return northWestSouthEastResizeCursor();
1267 case CURSOR_COL_RESIZE:
1268 return columnResizeCursor();
1269 case CURSOR_ROW_RESIZE:
1270 return rowResizeCursor();
1272 return iBeamCursor();
1274 return waitCursor();
1276 return helpCursor();
1277 case CURSOR_VERTICAL_TEXT:
1278 return verticalTextCursor();
1280 return cellCursor();
1281 case CURSOR_CONTEXT_MENU:
1282 return contextMenuCursor();
1283 case CURSOR_PROGRESS:
1284 return progressCursor();
1285 case CURSOR_NO_DROP:
1286 return noDropCursor();
1288 return aliasCursor();
1290 return copyCursor();
1292 return noneCursor();
1293 case CURSOR_NOT_ALLOWED:
1294 return notAllowedCursor();
1295 case CURSOR_DEFAULT:
1296 return pointerCursor();
1297 case CURSOR_WEBKIT_ZOOM_IN:
1298 return zoomInCursor();
1299 case CURSOR_WEBKIT_ZOOM_OUT:
1300 return zoomOutCursor();
1301 case CURSOR_WEBKIT_GRAB:
1302 return grabCursor();
1303 case CURSOR_WEBKIT_GRABBING:
1304 return grabbingCursor();
1306 return pointerCursor();
1309 static LayoutPoint documentPointForWindowPoint(Frame* frame, const LayoutPoint& windowPoint)
1311 FrameView* view = frame->view();
1312 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1313 // Historically the code would just crash; this is clearly no worse than that.
1314 return view ? view->windowToContents(windowPoint) : windowPoint;
1317 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1319 return targetNode(event.hitTestResult());
1322 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1324 Node* node = hitTestResult.innerNode();
1327 if (node->inDocument())
1330 Element* element = node->parentElement();
1331 if (element && element->inDocument())
1338 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1340 RefPtr<FrameView> protector(m_frame->view());
1342 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1344 cancelFakeMouseMoveEvent();
1345 m_mousePressed = true;
1346 m_capturesDragging = true;
1347 m_currentMousePosition = mouseEvent.pos();
1348 m_mouseDownTimestamp = mouseEvent.timestamp();
1349 #if ENABLE(DRAG_SUPPORT)
1350 m_mouseDownMayStartDrag = false;
1352 m_mouseDownMayStartSelect = false;
1353 m_mouseDownMayStartAutoscroll = false;
1354 if (FrameView* view = m_frame->view())
1355 m_mouseDownPos = view->windowToContents(mouseEvent.pos());
1360 m_mouseDownWasInSubframe = false;
1362 HitTestRequest request(HitTestRequest::Active);
1363 // Save the document point we generate in case the window coordinate is invalidated by what happens
1364 // when we dispatch the event.
1365 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos());
1366 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1368 if (!targetNode(mev)) {
1373 m_mousePressNode = targetNode(mev);
1375 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1380 Frame* subframe = subframeForHitTestResult(mev);
1381 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1382 // Start capturing future events for this frame. We only do this if we didn't clear
1383 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1384 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1385 if (m_mousePressed && m_capturesDragging) {
1386 m_capturingMouseEventsNode = targetNode(mev);
1387 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1393 #if ENABLE(PAN_SCROLLING)
1394 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1395 // because it will set m_panScrollInProgress to false on return.
1396 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress;
1397 if (isPanScrollInProgress || m_autoscrollInProgress)
1398 stopAutoscrollTimer();
1399 if (isPanScrollInProgress) {
1400 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1401 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1407 m_clickCount = mouseEvent.clickCount();
1408 m_clickNode = targetNode(mev);
1410 if (FrameView* view = m_frame->view()) {
1411 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1412 LayoutPoint p = view->windowToContents(mouseEvent.pos());
1413 if (layer && layer->isPointInResizeControl(p)) {
1414 layer->setInResizeMode(true);
1415 m_resizeLayer = layer;
1416 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1422 m_frame->selection()->setCaretBlinkingSuspended(true);
1424 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1425 m_capturesDragging = !swallowEvent;
1427 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1428 // in case the scrollbar widget was destroyed when the mouse event was handled.
1429 if (mev.scrollbar()) {
1430 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1431 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1432 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1433 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1434 m_lastScrollbarUnderMouse = 0;
1438 // scrollbars should get events anyway, even disabled controls might be scrollable
1439 Scrollbar* scrollbar = mev.scrollbar();
1441 updateLastScrollbarUnderMouse(scrollbar, true);
1444 passMousePressEventToScrollbar(mev, scrollbar);
1446 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1447 // If a mouse event handler changes the input element type to one that has a widget associated,
1448 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1449 // event target node can't still be the shadow node.
1450 if (targetNode(mev)->isShadowRoot() && targetNode(mev)->shadowHost()->hasTagName(inputTag)) {
1451 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1452 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1455 FrameView* view = m_frame->view();
1456 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0;
1458 scrollbar = mev.scrollbar();
1460 updateLastScrollbarUnderMouse(scrollbar, true);
1462 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1463 swallowEvent = true;
1465 swallowEvent = handleMousePressEvent(mev);
1468 return swallowEvent;
1471 // This method only exists for platforms that don't know how to deliver
1472 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1474 RefPtr<FrameView> protector(m_frame->view());
1476 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1478 // We get this instead of a second mouse-up
1479 m_mousePressed = false;
1480 m_currentMousePosition = mouseEvent.pos();
1482 HitTestRequest request(HitTestRequest::Active);
1483 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1484 Frame* subframe = subframeForHitTestResult(mev);
1485 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1486 m_capturingMouseEventsNode = 0;
1487 if (subframe && passMousePressEventToSubframe(mev, subframe))
1490 m_clickCount = mouseEvent.clickCount();
1491 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1493 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1495 if (m_lastScrollbarUnderMouse)
1496 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
1498 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1502 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1505 static RenderLayer* layerForNode(Node* node)
1510 RenderObject* renderer = node->renderer();
1514 RenderLayer* layer = renderer->enclosingLayer();
1521 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1523 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1524 bool result = handleMouseMoveEvent(event, &hoveredNode);
1526 Page* page = m_frame->page();
1530 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1531 if (page->containsScrollableArea(layer))
1532 layer->scrollAnimator()->mouseMovedInContentArea();
1535 if (FrameView* frameView = m_frame->view())
1536 frameView->scrollAnimator()->mouseMovedInContentArea();
1538 hoveredNode.setToNonShadowAncestor();
1539 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1540 page->chrome()->setToolTip(hoveredNode);
1544 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode)
1546 // in Radar 3703768 we saw frequent crashes apparently due to the
1547 // part being null here, which seems impossible, so check for nil
1548 // but also assert so that we can try to figure this out in debug
1549 // builds, if it happens.
1554 RefPtr<FrameView> protector(m_frame->view());
1555 m_currentMousePosition = mouseEvent.pos();
1557 if (m_hoverTimer.isActive())
1558 m_hoverTimer.stop();
1560 cancelFakeMouseMoveEvent();
1564 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1569 if (m_frameSetBeingResized)
1570 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1572 // Send events right to a scrollbar if the mouse is pressed.
1573 if (m_lastScrollbarUnderMouse && m_mousePressed)
1574 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1576 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
1577 // if we are allowed to select.
1578 // This means that :hover and :active freeze in the state they were in when the mouse
1579 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
1580 HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove;
1581 if (m_mousePressed && m_mouseDownMayStartSelect)
1582 hitType |= HitTestRequest::ReadOnly;
1584 hitType |= HitTestRequest::Active;
1586 #if ENABLE(TOUCH_EVENTS)
1587 // Treat any mouse move events as readonly if the user is currently touching the screen.
1589 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1591 HitTestRequest request(hitType);
1592 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1594 *hoveredNode = mev.hitTestResult();
1596 Scrollbar* scrollbar = 0;
1598 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1599 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1601 if (FrameView* view = m_frame->view())
1602 scrollbar = view->scrollbarAtPoint(mouseEvent.pos());
1605 scrollbar = mev.scrollbar();
1607 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1610 bool swallowEvent = false;
1611 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1613 // 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.
1614 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1615 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1618 // Update over/out state before passing the event to the subframe.
1619 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1621 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1622 // node to be detached from its FrameView, in which case the event should not be passed.
1623 if (newSubframe->view())
1624 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1626 if (scrollbar && !m_mousePressed)
1627 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1628 if (Page* page = m_frame->page()) {
1629 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->m_panScrollInProgress) {
1630 // Plugins set cursor on their own. The only case WebKit intervenes is resetting cursor to arrow on mouse enter,
1631 // in case the particular plugin doesn't manipulate cursor at all. Thus, even a CSS cursor set on body has no
1632 // effect on plugins (which matches Firefox).
1633 bool overPluginElement = false;
1634 if (targetNode(mev) && targetNode(mev)->isHTMLElement()) {
1635 HTMLElement* el = toHTMLElement(targetNode(mev));
1636 overPluginElement = el->hasTagName(appletTag) || el->hasTagName(objectTag) || el->hasTagName(embedTag);
1638 if (!overPluginElement) {
1639 if (FrameView* view = m_frame->view())
1640 view->setCursor(selectCursor(mev, scrollbar));
1646 m_lastMouseMoveEventSubframe = newSubframe;
1651 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1652 #if ENABLE(DRAG_SUPPORT)
1654 swallowEvent = handleMouseDraggedEvent(mev);
1655 #endif // ENABLE(DRAG_SUPPORT)
1657 return swallowEvent;
1660 void EventHandler::invalidateClick()
1666 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1668 RefPtr<FrameView> protector(m_frame->view());
1670 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1672 #if ENABLE(PAN_SCROLLING)
1673 if (mouseEvent.button() == MiddleButton)
1674 m_panScrollButtonPressed = false;
1675 if (m_springLoadedPanScrollInProgress)
1676 stopAutoscrollTimer();
1679 m_mousePressed = false;
1680 m_currentMousePosition = mouseEvent.pos();
1685 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_currentMousePosition));
1690 if (m_frameSetBeingResized)
1691 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1693 if (m_lastScrollbarUnderMouse) {
1695 return m_lastScrollbarUnderMouse->mouseUp();
1698 HitTestRequest request(HitTestRequest::MouseUp);
1699 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1700 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1701 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1702 m_capturingMouseEventsNode = 0;
1703 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1706 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1708 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1710 if (m_resizeLayer) {
1711 m_resizeLayer->setInResizeMode(false);
1715 bool swallowMouseReleaseEvent = false;
1716 if (!swallowMouseUpEvent)
1717 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1721 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1724 #if ENABLE(DRAG_SUPPORT)
1725 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1727 FrameView* view = m_frame->view();
1729 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1733 view->resetDeferredRepaintDelay();
1734 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1735 true, true, m_frame->document()->defaultView(),
1736 0, event.globalX(), event.globalY(), event.x(), event.y(),
1737 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1741 dragTarget->dispatchEvent(me.get(), ec);
1742 return me->defaultPrevented();
1745 static bool targetIsFrame(Node* target, Frame*& frame)
1750 if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
1753 frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
1758 static bool findDropZone(Node* target, Clipboard* clipboard)
1760 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1761 for (; element; element = element->parentElement()) {
1762 bool matched = false;
1763 String dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1765 if (dropZoneStr.isEmpty())
1768 dropZoneStr.makeLower();
1770 SpaceSplitString keywords(dropZoneStr, false);
1771 if (keywords.isNull())
1774 DragOperation dragOperation = DragOperationNone;
1775 for (unsigned int i = 0; i < keywords.size(); i++) {
1776 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1777 if (op != DragOperationNone) {
1778 if (dragOperation == DragOperationNone)
1781 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1783 if (matched && dragOperation != DragOperationNone)
1787 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1794 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1796 bool accept = false;
1798 if (!m_frame->view())
1801 HitTestRequest request(HitTestRequest::ReadOnly);
1802 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1804 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1805 Node* newTarget = targetNode(mev);
1806 if (newTarget && newTarget->isTextNode())
1807 newTarget = newTarget->parentNode();
1809 newTarget = newTarget->shadowAncestorNode();
1811 if (m_dragTarget != newTarget) {
1812 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1813 // it is sometimes incorrect when dragging within subframes, as seen with
1814 // LayoutTests/fast/events/drag-in-frames.html.
1816 // 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>.
1818 if (targetIsFrame(newTarget, targetFrame)) {
1820 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
1821 } else if (newTarget) {
1822 // 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.
1823 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
1824 // for now we don't care if event handler cancels default behavior, since there is none
1825 dispatchDragSrcEvent(eventNames().dragEvent, event);
1827 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
1829 accept = findDropZone(newTarget, clipboard);
1832 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1834 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
1835 } else if (m_dragTarget)
1836 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1839 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1840 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1841 m_shouldOnlyFireDragOverEvent = true;
1845 if (targetIsFrame(newTarget, targetFrame)) {
1847 accept = targetFrame->eventHandler()->updateDragAndDrop(event, clipboard);
1848 } else if (newTarget) {
1849 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1850 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
1851 // for now we don't care if event handler cancels default behavior, since there is none
1852 dispatchDragSrcEvent(eventNames().dragEvent, event);
1854 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
1856 accept = findDropZone(newTarget, clipboard);
1857 m_shouldOnlyFireDragOverEvent = false;
1860 m_dragTarget = newTarget;
1865 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1868 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1870 targetFrame->eventHandler()->cancelDragAndDrop(event, clipboard);
1871 } else if (m_dragTarget.get()) {
1872 if (dragState().m_dragSrc && dragState().shouldDispatchEvents())
1873 dispatchDragSrcEvent(eventNames().dragEvent, event);
1874 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1879 void EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1882 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1884 targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
1885 } else if (m_dragTarget.get())
1886 dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
1890 void EventHandler::clearDragState()
1893 m_capturingMouseEventsNode = 0;
1894 m_shouldOnlyFireDragOverEvent = false;
1896 m_sendingEventToSubview = false;
1899 #endif // ENABLE(DRAG_SUPPORT)
1901 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1903 m_capturingMouseEventsNode = n;
1904 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1907 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1910 ASSERT(m_frame->document());
1912 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
1916 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1918 if (!referenceNode || !referenceNode->isSVGElement())
1921 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
1922 if (!shadowTreeElement)
1925 Element* shadowTreeParentElement = shadowTreeElement->shadowHost();
1926 if (!shadowTreeParentElement)
1929 ASSERT(shadowTreeParentElement->hasTagName(useTag));
1930 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1934 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1936 Node* result = targetNode;
1938 // If we're capturing, we always go right to that node.
1939 if (m_capturingMouseEventsNode)
1940 result = m_capturingMouseEventsNode.get();
1942 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1943 if (result && result->isTextNode())
1944 result = result->parentNode();
1946 m_nodeUnderMouse = result;
1948 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1950 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1951 if (m_lastInstanceUnderMouse) {
1952 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1953 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1955 if (lastCorrespondingElement && lastCorrespondingUseElement) {
1956 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1958 // Locate the recloned shadow tree element for our corresponding instance
1959 HashSet<SVGElementInstance*>::iterator end = instances.end();
1960 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1961 SVGElementInstance* instance = (*it);
1962 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1964 if (instance == m_lastInstanceUnderMouse)
1967 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1970 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1971 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1974 m_lastNodeUnderMouse = shadowTreeElement;
1975 m_lastInstanceUnderMouse = instance;
1982 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1983 if (fireMouseOverOut) {
1984 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1985 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1986 Page* page = m_frame->page();
1988 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1989 // The mouse has moved between frames.
1990 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
1991 if (FrameView* frameView = frame->view())
1992 frameView->scrollAnimator()->mouseExitedContentArea();
1994 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1995 // The mouse has moved between layers.
1996 if (page->containsScrollableArea(layerForLastNode))
1997 layerForLastNode->scrollAnimator()->mouseExitedContentArea();
2000 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2001 // The mouse has moved between frames.
2002 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
2003 if (FrameView* frameView = frame->view())
2004 frameView->scrollAnimator()->mouseEnteredContentArea();
2006 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2007 // The mouse has moved between layers.
2008 if (page->containsScrollableArea(layerForNodeUnderMouse))
2009 layerForNodeUnderMouse->scrollAnimator()->mouseEnteredContentArea();
2012 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2013 m_lastNodeUnderMouse = 0;
2014 m_lastScrollbarUnderMouse = 0;
2016 m_lastInstanceUnderMouse = 0;
2020 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2021 // send mouseout event to the old node
2022 if (m_lastNodeUnderMouse)
2023 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2024 // send mouseover event to the new node
2025 if (m_nodeUnderMouse)
2026 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2028 m_lastNodeUnderMouse = m_nodeUnderMouse;
2030 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2035 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2037 if (FrameView* view = m_frame->view())
2038 view->resetDeferredRepaintDelay();
2040 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2042 bool swallowEvent = false;
2044 if (m_nodeUnderMouse)
2045 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2047 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2049 // If clicking on a frame scrollbar, do not mess up with content focus.
2050 if (FrameView* view = m_frame->view()) {
2051 if (view->scrollbarAtPoint(mouseEvent.pos()))
2055 // The layout needs to be up to date to determine if an element is focusable.
2056 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2058 // Blur current focus node when a link/button is clicked; this
2059 // is expected by some sites that rely on onChange handlers running
2060 // from form fields before the button click is processed.
2061 Node* node = m_nodeUnderMouse.get();
2063 // Walk up the DOM tree to search for a node to focus.
2065 if (node->isMouseFocusable()) {
2066 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2067 // node on mouse down if it's selected and inside a focused node. It will be
2068 // focused if the user does a mouseup over it, however, because the mouseup
2069 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2070 ExceptionCode ec = 0;
2071 Node* n = node->isShadowRoot() ? node->shadowHost() : node;
2072 if (m_frame->selection()->isRange()
2073 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2074 && n->isDescendantOf(m_frame->document()->focusedNode()))
2079 node = node->parentOrHostNode();
2082 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2083 // if the page already set it (e.g., by canceling default behavior).
2084 if (Page* page = m_frame->page()) {
2085 if (node && node->isMouseFocusable()) {
2086 if (!page->focusController()->setFocusedNode(node, m_frame))
2087 swallowEvent = true;
2088 } else if (!node || !node->focused()) {
2089 if (!page->focusController()->setFocusedNode(0, m_frame))
2090 swallowEvent = true;
2095 return swallowEvent;
2098 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
2099 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const
2105 bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
2107 Document* doc = m_frame->document();
2109 RenderObject* docRenderer = doc->renderer();
2113 RefPtr<FrameView> protector(m_frame->view());
2115 FrameView* view = m_frame->view();
2118 setFrameWasScrolledByUser();
2119 LayoutPoint vPoint = view->windowToContents(e.pos());
2124 HitTestRequest request(HitTestRequest::ReadOnly);
2125 HitTestResult result(vPoint);
2126 doc->renderView()->layer()->hitTest(request, result);
2129 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2132 if (m_useLatchedWheelEventNode) {
2133 if (!m_latchedWheelEventNode) {
2134 m_latchedWheelEventNode = result.innerNode();
2135 m_widgetIsLatched = result.isOverWidget();
2138 node = m_latchedWheelEventNode.get();
2139 isOverWidget = m_widgetIsLatched;
2141 if (m_latchedWheelEventNode)
2142 m_latchedWheelEventNode = 0;
2143 if (m_previousWheelScrolledNode)
2144 m_previousWheelScrolledNode = 0;
2146 node = result.innerNode();
2147 isOverWidget = result.isOverWidget();
2150 if (shouldTurnVerticalTicksIntoHorizontal(result))
2151 e.turnVerticalTicksIntoHorizontal();
2154 // Figure out which view to send the event to.
2155 RenderObject* target = node->renderer();
2157 if (isOverWidget && target && target->isWidget()) {
2158 Widget* widget = toRenderWidget(target)->widget();
2159 if (widget && passWheelEventToWidget(e, widget)) {
2165 node = node->shadowAncestorNode();
2166 if (node && !node->dispatchWheelEvent(e)) {
2175 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2176 view = m_frame->view();
2180 view->wheelEvent(e);
2181 return e.isAccepted();
2184 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2186 if (!startNode || !wheelEvent)
2189 Node* stopNode = m_previousWheelScrolledNode.get();
2191 // Break up into two scrolls if we need to. Diagonal movement on
2192 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2193 if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode))
2194 wheelEvent->setDefaultHandled();
2196 if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode))
2197 wheelEvent->setDefaultHandled();
2199 if (!m_useLatchedWheelEventNode)
2200 m_previousWheelScrolledNode = stopNode;
2203 #if ENABLE(GESTURE_EVENTS)
2204 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2206 // FIXME: This should hit test and go to the correct subframe rather than
2207 // always sending gestures to the main frame only. We should also ensure
2208 // that if a frame gets a gesture begin gesture, it gets the corresponding
2209 // end gesture as well.
2211 switch (gestureEvent.type()) {
2212 case PlatformGestureEvent::TapDownType:
2214 case PlatformGestureEvent::TapType: {
2215 // FIXME: Refactor this code to not hit test multiple times once hit testing has been corrected as suggested above.
2216 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, MouseEventMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2217 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventPressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2218 PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, MouseEventReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2219 mouseMoved(fakeMouseMove);
2220 handleMousePressEvent(fakeMouseDown);
2221 handleMouseReleaseEvent(fakeMouseUp);
2224 case PlatformGestureEvent::DoubleTapType:
2226 case PlatformGestureEvent::ScrollUpdateType: {
2227 const float tickDivisor = (float)WheelEvent::tickMultiplier;
2228 // FIXME: Replace this interim implementation once the above fixme has been addressed.
2229 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2230 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2231 PlatformWheelEvent syntheticWheelEvent(point, globalPoint, gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor, ScrollByPixelWheelEvent, /* isAccepted */ false, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2232 handleWheelEvent(syntheticWheelEvent);
2235 case PlatformGestureEvent::ScrollBeginType:
2236 case PlatformGestureEvent::ScrollEndType:
2237 FrameView* view = m_frame->view();
2241 view->handleGestureEvent(gestureEvent);
2248 #if ENABLE(CONTEXT_MENUS)
2249 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2251 Document* doc = m_frame->document();
2252 FrameView* v = m_frame->view();
2257 LayoutPoint viewportPos = v->windowToContents(event.pos());
2258 HitTestRequest request(HitTestRequest::Active);
2259 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2261 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2262 && !m_frame->selection()->contains(viewportPos)
2263 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2264 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2265 // available for text selections. But only if we're above text.
2266 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2267 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2268 selectClosestWordOrLinkFromMouseEvent(mev);
2271 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2273 return swallowEvent;
2276 bool EventHandler::sendContextMenuEventForKey()
2278 FrameView* view = m_frame->view();
2282 Document* doc = m_frame->document();
2286 static const int kContextMenuMargin = 1;
2288 #if OS(WINDOWS) && !OS(WINCE)
2289 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2291 int rightAligned = 0;
2293 LayoutPoint location;
2295 Node* focusedNode = doc->focusedNode();
2296 FrameSelection* selection = m_frame->selection();
2297 Position start = selection->selection().start();
2299 if (start.deprecatedNode() && (selection->rootEditableElement() || selection->isRange())) {
2300 RefPtr<Range> selectionRange = selection->toNormalizedRange();
2301 LayoutRect firstRect = m_frame->editor()->firstRectForRange(selectionRange.get());
2303 LayoutUnit x = rightAligned ? firstRect.maxX() : firstRect.x();
2304 location = LayoutPoint(x, firstRect.maxY());
2305 } else if (focusedNode) {
2306 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2309 LayoutRect clippedRect = box->absoluteClippedOverflowRect();
2310 location = LayoutPoint(clippedRect.x(), clippedRect.maxY() - 1);
2312 location = LayoutPoint(
2313 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2314 kContextMenuMargin);
2317 m_frame->view()->setCursor(pointerCursor());
2319 LayoutPoint position = view->contentsToWindow(location);
2320 LayoutPoint globalPosition = view->contentsToScreen(LayoutRect(location, LayoutSize())).location();
2322 Node* targetNode = doc->focusedNode();
2326 // Use the focused node as the target for hover and active.
2327 HitTestResult result(position);
2328 result.setInnerNode(targetNode);
2329 HitTestRequest request(HitTestRequest::Active);
2330 doc->renderView()->layer()->updateHoverActiveState(request, result);
2331 doc->updateStyleIfNeeded();
2333 // The contextmenu event is a mouse event even when invoked using the keyboard.
2334 // This is required for web compatibility.
2337 MouseEventType eventType = MouseEventReleased;
2339 MouseEventType eventType = MouseEventPressed;
2342 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2344 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2347 #endif // ENABLE(CONTEXT_MENUS)
2349 void EventHandler::scheduleHoverStateUpdate()
2351 if (!m_hoverTimer.isActive())
2352 m_hoverTimer.startOneShot(0);
2355 void EventHandler::dispatchFakeMouseMoveEventSoon()
2360 if (!m_fakeMouseMoveEventTimer.isActive())
2361 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2364 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2366 FrameView* view = m_frame->view();
2370 if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2373 if (!m_fakeMouseMoveEventTimer.isActive())
2374 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2377 void EventHandler::cancelFakeMouseMoveEvent()
2379 m_fakeMouseMoveEventTimer.stop();
2382 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2384 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2385 ASSERT(!m_mousePressed);
2387 FrameView* view = m_frame->view();
2395 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2396 LayoutPoint globalPoint = view->contentsToScreen(LayoutRect(view->windowToContents(m_currentMousePosition), LayoutSize())).location();
2397 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2398 mouseMoved(fakeMouseMoveEvent);
2401 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2403 m_frameSetBeingResized = frameSet;
2406 void EventHandler::resizeLayerDestroyed()
2408 ASSERT(m_resizeLayer);
2412 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2414 m_hoverTimer.stop();
2417 ASSERT(m_frame->document());
2419 if (RenderView* renderer = m_frame->contentRenderer()) {
2420 if (FrameView* view = m_frame->view()) {
2421 HitTestRequest request(HitTestRequest::MouseMove);
2422 HitTestResult result(view->windowToContents(m_currentMousePosition));
2423 renderer->layer()->hitTest(request, result);
2424 m_frame->document()->updateStyleIfNeeded();
2429 static Node* eventTargetNodeForDocument(Document* doc)
2433 Node* node = doc->focusedNode();
2434 if (!node && doc->isPluginDocument()) {
2435 PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
2436 node = pluginDocument->pluginNode();
2438 if (!node && doc->isHTMLDocument())
2441 node = doc->documentElement();
2445 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2447 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2448 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2449 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2450 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2451 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey));
2452 if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers())
2454 String key = evt.unmodifiedText();
2455 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2458 elem->accessKeyAction(false);
2463 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2469 #if ENABLE(FULLSCREEN_API)
2470 bool EventHandler::isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent& keyEvent) const
2472 Document* document = m_frame->document();
2473 if (document->webkitFullScreenKeyboardInputAllowed())
2476 int keyCode = keyEvent.windowsVirtualKeyCode();
2477 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2478 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2479 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2480 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2484 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2486 RefPtr<FrameView> protector(m_frame->view());
2488 #if ENABLE(FULLSCREEN_API)
2489 if (m_frame->document()->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(initialKeyEvent))
2493 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2494 capsLockStateMayHaveChanged();
2496 #if ENABLE(PAN_SCROLLING)
2497 if (Page* page = m_frame->page()) {
2498 if (page->mainFrame()->eventHandler()->m_panScrollInProgress || m_autoscrollInProgress) {
2499 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
2500 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown)
2501 stopAutoscrollTimer();
2503 // If we were in autoscroll/panscroll mode, we swallow the key event
2509 // Check for cases where we are too early for events -- possible unmatched key up
2510 // from pressing return in the location bar.
2511 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2515 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2516 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2518 if (FrameView* view = m_frame->view())
2519 view->resetDeferredRepaintDelay();
2521 // FIXME: what is this doing here, in keyboard event handler?
2522 m_frame->loader()->resetMultipleFormSubmissionProtection();
2524 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2525 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2526 // with access keys. Then we dispatch keydown, but suppress its default handling.
2527 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2528 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2529 bool matchedAnAccessKey = false;
2530 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
2531 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2533 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2534 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
2535 return !node->dispatchKeyEvent(initialKeyEvent);
2537 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2540 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2541 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
2542 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
2543 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2544 if (matchedAnAccessKey)
2545 keydown->setDefaultPrevented(true);
2546 keydown->setTarget(node);
2548 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
2549 node->dispatchEvent(keydown, ec);
2550 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2551 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2552 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2555 // Run input method in advance of DOM event handling. This may result in the IM
2556 // modifying the page prior the keydown event, but this behaviour is necessary
2557 // in order to match IE:
2558 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2559 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2560 m_frame->editor()->handleInputMethodKeydown(keydown.get());
2562 bool handledByInputMethod = keydown->defaultHandled();
2564 if (handledByInputMethod) {
2565 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2566 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2567 keydown->setTarget(node);
2568 keydown->setDefaultHandled();
2571 node->dispatchEvent(keydown, ec);
2572 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2573 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2574 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2575 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2576 return keydownResult;
2578 // Focus may have changed during keydown handling, so refetch node.
2579 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2580 if (!keydownResult) {
2581 node = eventTargetNodeForDocument(m_frame->document());
2586 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2587 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
2588 if (keyPressEvent.text().isEmpty())
2589 return keydownResult;
2590 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
2591 keypress->setTarget(node);
2593 keypress->setDefaultPrevented(true);
2595 keypress->keypressCommands() = keydown->keypressCommands();
2597 node->dispatchEvent(keypress, ec);
2599 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2602 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
2604 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
2605 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
2606 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
2607 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
2609 FocusDirection retVal = FocusDirectionNone;
2611 if (keyIdentifier == Down)
2612 retVal = FocusDirectionDown;
2613 else if (keyIdentifier == Up)
2614 retVal = FocusDirectionUp;
2615 else if (keyIdentifier == Left)
2616 retVal = FocusDirectionLeft;
2617 else if (keyIdentifier == Right)
2618 retVal = FocusDirectionRight;
2623 static void handleKeyboardSelectionMovement(FrameSelection* selection, KeyboardEvent* event)
2628 bool isOptioned = event->getModifierState("Alt");
2629 bool isCommanded = event->getModifierState("Meta");
2631 SelectionDirection direction = DirectionForward;
2632 TextGranularity granularity = CharacterGranularity;
2634 switch (focusDirectionForKey(event->keyIdentifier())) {
2635 case FocusDirectionNone:
2637 case FocusDirectionForward:
2638 case FocusDirectionBackward:
2639 ASSERT_NOT_REACHED();
2641 case FocusDirectionUp:
2642 direction = DirectionBackward;
2643 granularity = isCommanded ? DocumentBoundary : LineGranularity;
2645 case FocusDirectionDown:
2646 direction = DirectionForward;
2647 granularity = isCommanded ? DocumentBoundary : LineGranularity;
2649 case FocusDirectionLeft:
2650 direction = DirectionLeft;
2651 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
2653 case FocusDirectionRight:
2654 direction = DirectionRight;
2655 granularity = (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity;
2659 FrameSelection::EAlteration alternation = event->getModifierState("Shift") ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove;
2660 selection->modify(alternation, direction, granularity, UserTriggered);
2661 event->setDefaultHandled();
2664 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2666 if (event->type() == eventNames().keydownEvent) {
2667 m_frame->editor()->handleKeyboardEvent(event);
2668 if (event->defaultHandled())
2670 if (event->keyIdentifier() == "U+0009")
2671 defaultTabEventHandler(event);
2672 else if (event->keyIdentifier() == "U+0008")
2673 defaultBackspaceEventHandler(event);
2675 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
2676 if (direction != FocusDirectionNone)
2677 defaultArrowEventHandler(direction, event);
2680 // provides KB navigation and selection for enhanced accessibility users
2681 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2682 handleKeyboardSelectionMovement(m_frame->selection(), event);
2684 if (event->type() == eventNames().keypressEvent) {
2685 m_frame->editor()->handleKeyboardEvent(event);
2686 if (event->defaultHandled())
2688 if (event->charCode() == ' ')
2689 defaultSpaceEventHandler(event);
2693 #if ENABLE(DRAG_SUPPORT)
2694 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
2696 FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
2697 return dragHysteresisExceeded(dragViewportLocation);
2700 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
2702 FrameView* view = m_frame->view();
2705 LayoutPoint dragLocation = view->windowToContents(flooredLayoutPoint(dragViewportLocation));
2706 LayoutSize delta = dragLocation - m_mouseDownPos;
2708 int threshold = GeneralDragHysteresis;
2709 switch (dragState().m_dragType) {
2710 case DragSourceActionSelection:
2711 threshold = TextDragHysteresis;
2713 case DragSourceActionImage:
2714 threshold = ImageDragHysteresis;
2716 case DragSourceActionLink:
2717 threshold = LinkDragHysteresis;
2719 case DragSourceActionDHTML:
2721 case DragSourceActionNone:
2722 case DragSourceActionAny:
2723 ASSERT_NOT_REACHED();
2726 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
2729 void EventHandler::freeClipboard()
2731 if (dragState().m_dragClipboard)
2732 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
2735 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
2737 if (dragState().m_dragSrc && dragState().shouldDispatchEvents()) {
2738 dragState().m_dragClipboard->setDestinationOperation(operation);
2739 // for now we don't care if event handler cancels default behavior, since there is none
2740 dispatchDragSrcEvent(eventNames().dragendEvent, event);
2743 dragState().m_dragSrc = 0;
2744 // In case the drag was ended due to an escape key press we need to ensure
2745 // that consecutive mousemove events don't reinitiate the drag and drop.
2746 m_mouseDownMayStartDrag = false;
2749 // returns if we should continue "default processing", i.e., whether eventhandler canceled
2750 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
2752 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
2755 static bool ExactlyOneBitSet(DragSourceAction n)
2757 return n && !(n & (n - 1));
2760 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
2762 if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) {
2763 // If we allowed the other side of the bridge to handle a drag
2764 // last time, then m_mousePressed might still be set. So we
2765 // clear it now to make sure the next move after a drag
2766 // doesn't look like a drag.
2767 m_mousePressed = false;
2771 if (eventLoopHandleMouseDragged(event))
2774 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
2776 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2777 dragState().m_eventDispatchPolicy = (updateDragSourceActionsAllowed() & DragSourceActionDHTML) ? DragState::DispatchEvents: DragState::DoNotDispatchEvents;
2779 // try to find an element that wants to be dragged
2780 HitTestRequest request(HitTestRequest::ReadOnly);
2781 HitTestResult result(m_mouseDownPos);
2782 m_frame->contentRenderer()->layer()->hitTest(request, result);
2783 Node* node = result.innerNode();
2784 if (node && m_frame->page())
2785 dragState().m_dragSrc = m_frame->page()->dragController()->draggableNode(m_frame, node, m_mouseDownPos, dragState());
2787 dragState().m_dragSrc = 0;
2789 if (!dragState().m_dragSrc)
2790 m_mouseDownMayStartDrag = false; // no element is draggable
2792 m_dragMayStartSelectionInstead = (dragState().m_dragType & DragSourceActionSelection);
2795 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
2796 // or else we bail on the dragging stuff and allow selection to occur
2797 if (m_mouseDownMayStartDrag && m_dragMayStartSelectionInstead && (dragState().m_dragType & DragSourceActionSelection) && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
2798 ASSERT(event.event().eventType() == MouseEventMoved);
2799 if ((dragState().m_dragType & DragSourceActionImage)) {
2800 // ... unless the mouse is over an image, then we start dragging just the image
2801 dragState().m_dragType = DragSourceActionImage;
2802 } else if (!(dragState().m_dragType & (DragSourceActionDHTML | DragSourceActionLink))) {
2803 // ... but only bail if we're not over an unselectable element.
2804 m_mouseDownMayStartDrag = false;
2805 dragState().m_dragSrc = 0;
2806 // ... but if this was the first click in the window, we don't even want to start selection
2807 if (eventActivatedView(event.event()))
2808 m_mouseDownMayStartSelect = false;
2810 // Prevent the following case from occuring:
2811 // 1. User starts a drag immediately after mouse down over an unselectable element.
2812 // 2. We enter this block and decided that since we're over an unselectable element,
2813 // don't cancel the drag.
2814 // 3. The drag gets resolved as a potential selection drag below /but/ we haven't
2815 // exceeded the drag hysteresis yet.
2816 // 4. We enter this block again, and since it's now marked as a selection drag, we
2818 m_dragMayStartSelectionInstead = false;
2822 if (!m_mouseDownMayStartDrag)
2823 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
2825 if (!ExactlyOneBitSet(dragState().m_dragType)) {
2826 ASSERT((dragState().m_dragType & DragSourceActionSelection));
2827 ASSERT((dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionDHTML
2828 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionImage
2829 || (dragState().m_dragType & ~DragSourceActionSelection) == DragSourceActionLink);
2830 dragState().m_dragType = DragSourceActionSelection;
2833 // We are starting a text/image/url drag, so the cursor should be an arrow
2834 if (FrameView* view = m_frame->view()) {
2835 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
2836 view->setCursor(pointerCursor());
2839 if (!dragHysteresisExceeded(event.event().pos()))
2842 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2845 DragOperation srcOp = DragOperationNone;
2847 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
2848 // to make sure it gets numbified
2849 dragState().m_dragClipboard = createDraggingClipboard();
2851 if (dragState().shouldDispatchEvents()) {
2852 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
2854 if (dragState().m_dragType == DragSourceActionDHTML) {
2855 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
2856 // FIXME: This doesn't work correctly with transforms.
2857 FloatPoint absPos = renderer->localToAbsolute();
2858 LayoutSize delta = m_mouseDownPos - roundedLayoutPoint(absPos);
2859 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
2861 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
2862 // the element in some way. In this case we just kill the drag.
2863 m_mouseDownMayStartDrag = false;
2868 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
2869 && !m_frame->selection()->isInPasswordField();
2871 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
2872 // image can still be changed as we drag, but not the pasteboard data.
2873 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
2875 if (m_mouseDownMayStartDrag) {
2876 // gather values from DHTML element, if it set any
2877 srcOp = dragState().m_dragClipboard->sourceOperation();
2879 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
2880 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
2881 // started the drag when that happens. So we have to assume it's started before we
2883 dragState().m_dragClipboard->setDragHasStarted();
2887 if (m_mouseDownMayStartDrag) {
2888 Page* page = m_frame->page();
2889 DragController* dragController = page ? page->dragController() : 0;
2890 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
2891 if (!startedDrag && dragState().shouldDispatchEvents()) {
2892 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
2893 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
2894 m_mouseDownMayStartDrag = false;
2899 if (!m_mouseDownMayStartDrag) {
2900 // something failed to start the drag, cleanup
2902 dragState().m_dragSrc = 0;
2905 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2908 #endif // ENABLE(DRAG_SUPPORT)
2910 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
2912 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
2913 // and avoid dispatching text input events from keydown default handlers.
2914 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
2919 EventTarget* target;
2920 if (underlyingEvent)
2921 target = underlyingEvent->target();
2923 target = eventTargetNodeForDocument(m_frame->document());
2927 if (FrameView* view = m_frame->view())
2928 view->resetDeferredRepaintDelay();
2930 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
2931 event->setUnderlyingEvent(underlyingEvent);
2934 target->dispatchEvent(event, ec);
2935 return event->defaultHandled();
2938 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
2941 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
2943 && event->keyIdentifier() == "U+0009";
2946 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
2948 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(HAIKU) || PLATFORM(EFL)
2949 return EventHandler::isKeyboardOptionTab(event);
2955 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
2957 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
2959 Page* page = m_frame->page();
2963 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
2964 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
2967 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
2969 if (m_frame->editor()->handleTextEvent(event))
2970 event->setDefaultHandled();
2974 // Qt handles the space event in platform-specific WebKit code.
2975 // Eventually it would be good to eliminate that and use the code here instead.
2976 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
2981 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
2983 ASSERT(event->type() == eventNames().keypressEvent);
2985 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
2988 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
2989 if (logicalScrollOverflow(direction, ScrollByPage)) {
2990 event->setDefaultHandled();
2994 FrameView* view = m_frame->view();
2998 if (view->logicalScroll(direction, ScrollByPage))
2999 event->setDefaultHandled();
3004 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3006 ASSERT(event->type() == eventNames().keydownEvent);
3008 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3011 if (!m_frame->editor()->behavior().shouldNavigateBackOnBackspace())
3014 Page* page = m_frame->page();
3018 bool handledEvent = false;
3020 if (event->shiftKey())
3021 handledEvent = page->goForward();
3023 handledEvent = page->goBack();
3026 event->setDefaultHandled();
3030 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3032 ASSERT(event->type() == eventNames().keydownEvent);
3034 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3037 Page* page = m_frame->page();
3041 if (!isSpatialNavigationEnabled(m_frame))
3044 // Arrows and other possible directional navigation keys can be used in design
3046 if (m_frame->document()->inDesignMode())
3049 if (page->focusController()->advanceFocus(focusDirection, event))
3050 event->setDefaultHandled();
3053 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3055 ASSERT(event->type() == eventNames().keydownEvent);
3057 // We should only advance focus on tabs if no special modifier keys are held down.
3058 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3061 Page* page = m_frame->page();
3064 if (!page->tabKeyCyclesThroughElements())
3067 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3069 // Tabs can be used in design mode editing.
3070 if (m_frame->document()->inDesignMode())
3073 if (page->focusController()->advanceFocus(focusDirection, event))
3074 event->setDefaultHandled();
3077 void EventHandler::capsLockStateMayHaveChanged()
3079 Document* d = m_frame->document();
3080 if (Node* node = d->focusedNode()) {
3081 if (RenderObject* r = node->renderer()) {
3082 if (r->isTextField())
3083 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3088 void EventHandler::sendResizeEvent()
3090 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
3093 void EventHandler::sendScrollEvent()
3095 setFrameWasScrolledByUser();
3096 if (m_frame->view() && m_frame->document())
3097 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), EventQueue::ScrollEventDocumentTarget);
3100 void EventHandler::setFrameWasScrolledByUser()
3102 FrameView* v = m_frame->view();
3104 v->setWasScrolledByUser(true);
3107 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3109 if (!scrollbar || !scrollbar->enabled())
3111 setFrameWasScrolledByUser();
3112 return scrollbar->mouseDown(mev.event());
3115 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3116 // last to scrollbar if setLast is true; else set last to 0.
3117 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3119 if (m_lastScrollbarUnderMouse != scrollbar) {
3120 // Send mouse exited to the old scrollbar.
3121 if (m_lastScrollbarUnderMouse)
3122 m_lastScrollbarUnderMouse->mouseExited();
3123 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3127 #if ENABLE(TOUCH_EVENTS)
3129 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3132 case PlatformTouchPoint::TouchReleased:
3133 return eventNames().touchendEvent;
3134 case PlatformTouchPoint::TouchCancelled:
3135 return eventNames().touchcancelEvent;
3136 case PlatformTouchPoint::TouchPressed:
3137 return eventNames().touchstartEvent;
3138 case PlatformTouchPoint::TouchMoved:
3139 return eventNames().touchmoveEvent;
3141 ASSERT_NOT_REACHED();
3146 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3148 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3149 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3150 // for an overview of how these lists fit together.
3152 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3153 RefPtr<TouchList> touches = TouchList::create();
3155 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3156 // 'targetTouches' list in the JS event.
3157 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3158 TargetTouchesMap touchesByTarget;
3160 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3161 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3163 // The touches corresponding to the particular change state this struct instance represents.
3164 RefPtr<TouchList> m_touches;
3165 // Set of targets involved in m_touches.
3166 EventTargetSet m_targets;
3167 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3169 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3171 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3173 for (unsigned i = 0; i < points.size(); ++i) {
3174 const PlatformTouchPoint& point = points[i];
3175 PlatformTouchPoint::State pointState = point.state();
3176 LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3178 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ReadOnly;
3179 // The HitTestRequest types used for mouse events map quite adequately
3180 // to touch events. Note that in addition to meaning that the hit test
3181 // should affect the active state of the current node if necessary,
3182 // HitTestRequest::Active signifies that the hit test is taking place
3183 // with the mouse (or finger in this case) being pressed.
3184 switch (pointState) {
3185 case PlatformTouchPoint::TouchPressed:
3186 hitType = HitTestRequest::Active;
3188 case PlatformTouchPoint::TouchMoved:
3189 hitType = HitTestRequest::Active | HitTestRequest::MouseMove | HitTestRequest::ReadOnly;
3191 case PlatformTouchPoint::TouchReleased:
3192 case PlatformTouchPoint::TouchCancelled:
3193 hitType = HitTestRequest::MouseUp;
3199 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3200 Node* node = result.innerNode();
3203 // Touch events should not go to text nodes
3204 if (node->isTextNode())
3205 node = node->parentNode();
3207 Document* doc = node->document();
3210 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3213 if (m_frame != doc->frame()) {
3214 // pagePoint should always be relative to the target elements containing frame.
3215 pagePoint = documentPointForWindowPoint(doc->frame(), point.pos());
3218 int adjustedPageX = lroundf(pagePoint.x() / m_frame->pageZoomFactor());
3219 int adjustedPageY = lroundf(pagePoint.y() / m_frame->pageZoomFactor());
3221 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3222 unsigned touchPointTargetKey = point.id() + 1;
3223 RefPtr<EventTarget> touchTarget;
3224 if (pointState == PlatformTouchPoint::TouchPressed) {
3225 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3227 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3228 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3229 // we also remove it from the map.
3230 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3232 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3234 if (!touchTarget.get())
3237 RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget.get(), point.id(),
3238 point.screenPos().x(), point.screenPos().y(),
3239 adjustedPageX, adjustedPageY,
3240 point.radiusX(), point.radiusY(), point.rotationAngle(), point.force());
3242 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3243 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3244 if (targetTouchesIterator == touchesByTarget.end())
3245 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).first;
3247 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3248 // released or cancelled it will only appear in the changedTouches list.
3249 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3250 touches->append(touch);
3251 targetTouchesIterator->second->append(touch);
3254 // Now build up the correct list for changedTouches.
3255 // Note that any touches that are in the TouchStationary state (e.g. if
3256 // the user had several points touched but did not move them all) should
3257 // never be in the changedTouches list so we do not handle them explicitly here.
3258 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3259 // about the TouchStationary state.
3260 if (pointState != PlatformTouchPoint::TouchStationary) {
3261 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3262 if (!changedTouches[pointState].m_touches)
3263 changedTouches[pointState].m_touches = TouchList::create();
3264 changedTouches[pointState].m_touches->append(touch);
3265 changedTouches[pointState].m_targets.add(touchTarget);
3268 m_touchPressed = touches->length() > 0;
3270 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3271 bool defaultPrevented = false;
3272 RefPtr<TouchList> emptyList = TouchList::create();
3273 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3274 if (!changedTouches[state].m_touches)
3277 // When sending a touch cancel event, use empty touches and targetTouches lists.
3278 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3279 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3280 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3281 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3283 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3284 EventTarget* touchEventTarget = it->get();
3285 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3286 ASSERT(targetTouches);
3288 RefPtr<TouchEvent> touchEvent =
3289 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3290 stateName, touchEventTarget->toNode()->document()->defaultView(),
3291 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3292 ExceptionCode ec = 0;
3293 touchEventTarget->dispatchEvent(touchEvent.get(), ec);
3294 defaultPrevented |= touchEvent->defaultPrevented();
3298 return defaultPrevented;