2 * Copyright (C) 2006, 2007, 2008, 2009 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"
32 #include "ChromeClient.h"
35 #include "DragController.h"
37 #include "EventNames.h"
38 #include "FloatPoint.h"
39 #include "FloatRect.h"
40 #include "FocusController.h"
42 #include "FrameLoader.h"
43 #include "FrameTree.h"
44 #include "FrameView.h"
45 #include "HTMLFrameElementBase.h"
46 #include "HTMLFrameSetElement.h"
47 #include "HTMLInputElement.h"
48 #include "HTMLNames.h"
49 #include "HitTestRequest.h"
50 #include "HitTestResult.h"
52 #include "InspectorController.h"
53 #include "KeyboardEvent.h"
54 #include "MouseEvent.h"
55 #include "MouseEventWithHitTestResults.h"
57 #include "PlatformKeyboardEvent.h"
58 #include "PlatformWheelEvent.h"
59 #include "RenderFrameSet.h"
60 #include "RenderTextControlSingleLine.h"
61 #include "RenderView.h"
62 #include "RenderWidget.h"
63 #include "Scrollbar.h"
64 #include "SelectionController.h"
66 #include "TextEvent.h"
67 #include "htmlediting.h" // for comparePositions()
68 #include <wtf/StdLibExtras.h>
71 #include "SVGDocument.h"
72 #include "SVGElementInstance.h"
74 #include "SVGUseElement.h"
79 using namespace HTMLNames
;
81 // The link drag hysteresis is much larger than the others because there
82 // needs to be enough space to cancel the link press without starting a link drag,
83 // and because dragging links is rare.
84 const int LinkDragHysteresis
= 40;
85 const int ImageDragHysteresis
= 5;
86 const int TextDragHysteresis
= 3;
87 const int GeneralDragHysteresis
= 3;
89 // Match key code of composition keydown event on windows.
90 // IE sends VK_PROCESSKEY which has value 229;
91 const int CompositionEventKeyCode
= 229;
94 using namespace SVGNames
;
97 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
98 const double autoscrollInterval
= 0.05;
100 static Frame
* subframeForTargetNode(Node
*);
101 static Frame
* subframeForHitTestResult(const MouseEventWithHitTestResults
&);
103 static inline void scrollAndAcceptEvent(float delta
, ScrollDirection positiveDirection
, ScrollDirection negativeDirection
, PlatformWheelEvent
& e
, Node
* node
)
108 // Find the nearest enclosing box.
109 RenderBox
* enclosingBox
= node
->renderer()->enclosingBox();
111 if (e
.granularity() == ScrollByPageWheelEvent
) {
112 if (enclosingBox
->scroll(delta
< 0 ? negativeDirection
: positiveDirection
, ScrollByPage
, 1))
116 float pixelsToScroll
= delta
> 0 ? delta
: -delta
;
117 if (enclosingBox
->scroll(delta
< 0 ? negativeDirection
: positiveDirection
, ScrollByPixel
, pixelsToScroll
))
123 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults
&)
128 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults
&)
135 EventHandler::EventHandler(Frame
* frame
)
137 , m_mousePressed(false)
138 , m_capturesDragging(false)
139 , m_mouseDownMayStartSelect(false)
140 , m_mouseDownMayStartDrag(false)
141 , m_mouseDownWasSingleClickInSelection(false)
142 , m_beganSelectingText(false)
143 , m_panScrollInProgress(false)
144 , m_hoverTimer(this, &EventHandler::hoverTimerFired
)
145 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired
)
146 , m_autoscrollRenderer(0)
147 , m_autoscrollInProgress(false)
148 , m_mouseDownMayStartAutoscroll(false)
149 , m_mouseDownWasInSubframe(false)
154 , m_capturingMouseEventsNode(0)
156 , m_mouseDownTimestamp(0)
158 , m_mouseDownView(nil
)
159 , m_sendingEventToSubview(false)
160 , m_activationEventNumber(0)
165 EventHandler::~EventHandler()
169 EventHandler::EventHandlerDragState
& EventHandler::dragState()
171 DEFINE_STATIC_LOCAL(EventHandlerDragState
, state
, ());
175 void EventHandler::clear()
179 m_nodeUnderMouse
= 0;
180 m_lastNodeUnderMouse
= 0;
182 m_instanceUnderMouse
= 0;
183 m_lastInstanceUnderMouse
= 0;
185 m_lastMouseMoveEventSubframe
= 0;
186 m_lastScrollbarUnderMouse
= 0;
189 m_frameSetBeingResized
= 0;
191 m_currentMousePosition
= IntPoint();
192 m_mousePressNode
= 0;
193 m_mousePressed
= false;
194 m_capturesDragging
= false;
195 m_capturingMouseEventsNode
= 0;
198 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults
& result
)
200 Node
* innerNode
= result
.targetNode();
201 VisibleSelection newSelection
;
203 if (innerNode
&& innerNode
->renderer() && m_mouseDownMayStartSelect
) {
204 VisiblePosition
pos(innerNode
->renderer()->positionForPoint(result
.localPoint()));
205 if (pos
.isNotNull()) {
206 newSelection
= VisibleSelection(pos
);
207 newSelection
.expandUsingGranularity(WordGranularity
);
210 if (newSelection
.isRange()) {
211 m_frame
->setSelectionGranularity(WordGranularity
);
212 m_beganSelectingText
= true;
213 if (result
.event().clickCount() == 2 && m_frame
->editor()->isSelectTrailingWhitespaceEnabled())
214 newSelection
.appendTrailingWhitespace();
217 if (m_frame
->shouldChangeSelection(newSelection
))
218 m_frame
->selection()->setSelection(newSelection
);
222 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults
& result
)
224 if (!result
.hitTestResult().isLiveLink())
225 return selectClosestWordFromMouseEvent(result
);
227 Node
* innerNode
= result
.targetNode();
229 if (innerNode
&& innerNode
->renderer() && m_mouseDownMayStartSelect
) {
230 VisibleSelection newSelection
;
231 Element
* URLElement
= result
.hitTestResult().URLElement();
232 VisiblePosition
pos(innerNode
->renderer()->positionForPoint(result
.localPoint()));
233 if (pos
.isNotNull() && pos
.deepEquivalent().node()->isDescendantOf(URLElement
))
234 newSelection
= VisibleSelection::selectionFromContentsOfNode(URLElement
);
236 if (newSelection
.isRange()) {
237 m_frame
->setSelectionGranularity(WordGranularity
);
238 m_beganSelectingText
= true;
241 if (m_frame
->shouldChangeSelection(newSelection
))
242 m_frame
->selection()->setSelection(newSelection
);
246 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults
& event
)
248 if (event
.event().button() != LeftButton
)
251 if (m_frame
->selection()->isRange())
252 // A double-click when range is already selected
253 // should not change the selection. So, do not call
254 // selectClosestWordFromMouseEvent, but do set
255 // m_beganSelectingText to prevent handleMouseReleaseEvent
256 // from setting caret selection.
257 m_beganSelectingText
= true;
259 selectClosestWordFromMouseEvent(event
);
264 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults
& event
)
266 if (event
.event().button() != LeftButton
)
269 Node
* innerNode
= event
.targetNode();
270 if (!(innerNode
&& innerNode
->renderer() && m_mouseDownMayStartSelect
))
273 VisibleSelection newSelection
;
274 VisiblePosition
pos(innerNode
->renderer()->positionForPoint(event
.localPoint()));
275 if (pos
.isNotNull()) {
276 newSelection
= VisibleSelection(pos
);
277 newSelection
.expandUsingGranularity(ParagraphGranularity
);
279 if (newSelection
.isRange()) {
280 m_frame
->setSelectionGranularity(ParagraphGranularity
);
281 m_beganSelectingText
= true;
284 if (m_frame
->shouldChangeSelection(newSelection
))
285 m_frame
->selection()->setSelection(newSelection
);
290 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults
& event
)
292 Node
* innerNode
= event
.targetNode();
293 if (!(innerNode
&& innerNode
->renderer() && m_mouseDownMayStartSelect
))
296 // Extend the selection if the Shift key is down, unless the click is in a link.
297 bool extendSelection
= event
.event().shiftKey() && !event
.isOverLink();
299 // Don't restart the selection when the mouse is pressed on an
300 // existing selection so we can allow for text dragging.
301 if (FrameView
* view
= m_frame
->view()) {
302 IntPoint vPoint
= view
->windowToContents(event
.event().pos());
303 if (!extendSelection
&& m_frame
->selection()->contains(vPoint
)) {
304 m_mouseDownWasSingleClickInSelection
= true;
309 VisiblePosition
visiblePos(innerNode
->renderer()->positionForPoint(event
.localPoint()));
310 if (visiblePos
.isNull())
311 visiblePos
= VisiblePosition(innerNode
, 0, DOWNSTREAM
);
312 Position pos
= visiblePos
.deepEquivalent();
314 VisibleSelection newSelection
= m_frame
->selection()->selection();
315 if (extendSelection
&& newSelection
.isCaretOrRange()) {
316 m_frame
->selection()->setLastChangeWasHorizontalExtension(false);
318 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
319 // was created right-to-left
320 Position start
= newSelection
.start();
321 Position end
= newSelection
.end();
322 if (comparePositions(pos
, start
) <= 0)
323 newSelection
= VisibleSelection(pos
, end
);
325 newSelection
= VisibleSelection(start
, pos
);
327 if (m_frame
->selectionGranularity() != CharacterGranularity
)
328 newSelection
.expandUsingGranularity(m_frame
->selectionGranularity());
329 m_beganSelectingText
= true;
331 newSelection
= VisibleSelection(visiblePos
);
332 m_frame
->setSelectionGranularity(CharacterGranularity
);
335 if (m_frame
->shouldChangeSelection(newSelection
))
336 m_frame
->selection()->setSelection(newSelection
);
341 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults
& event
)
344 dragState().m_dragSrc
= 0;
346 bool singleClick
= event
.event().clickCount() <= 1;
348 // If we got the event back, that must mean it wasn't prevented,
349 // so it's allowed to start a drag or selection.
350 m_mouseDownMayStartSelect
= canMouseDownStartSelect(event
.targetNode());
352 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
353 m_mouseDownMayStartDrag
= singleClick
;
355 m_mouseDownWasSingleClickInSelection
= false;
357 m_mouseDown
= event
.event();
359 if (event
.isOverWidget() && passWidgetMouseDownEventToWidget(event
))
363 if (m_frame
->document()->isSVGDocument() &&
364 static_cast<SVGDocument
*>(m_frame
->document())->zoomAndPanEnabled()) {
365 if (event
.event().shiftKey() && singleClick
) {
367 static_cast<SVGDocument
*>(m_frame
->document())->startPan(event
.event().pos());
373 // We don't do this at the start of mouse down handling,
374 // because we don't want to do it until we know we didn't hit a widget.
378 Node
* innerNode
= event
.targetNode();
380 m_mousePressNode
= innerNode
;
381 m_dragStartPos
= event
.event().pos();
383 bool swallowEvent
= false;
384 m_frame
->selection()->setCaretBlinkingSuspended(true);
385 m_mousePressed
= true;
386 m_beganSelectingText
= false;
388 if (event
.event().clickCount() == 2)
389 swallowEvent
= handleMousePressEventDoubleClick(event
);
390 else if (event
.event().clickCount() >= 3)
391 swallowEvent
= handleMousePressEventTripleClick(event
);
393 swallowEvent
= handleMousePressEventSingleClick(event
);
395 m_mouseDownMayStartAutoscroll
= m_mouseDownMayStartSelect
||
396 (m_mousePressNode
&& m_mousePressNode
->renderBox() && m_mousePressNode
->renderBox()->canBeProgramaticallyScrolled(true));
401 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults
& event
)
403 if (handleDrag(event
))
409 Node
* targetNode
= event
.targetNode();
410 if (event
.event().button() != LeftButton
|| !targetNode
|| !targetNode
->renderer())
413 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
414 ASSERT(m_mouseDownMayStartSelect
|| m_mouseDownMayStartAutoscroll
);
417 m_mouseDownMayStartDrag
= false;
419 if (m_mouseDownMayStartAutoscroll
&& !m_panScrollInProgress
) {
420 // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
421 // Otherwise, let the bridge handle it so the view can scroll itself.
422 RenderObject
* renderer
= targetNode
->renderer();
423 while (renderer
&& (!renderer
->isBox() || !toRenderBox(renderer
)->canBeProgramaticallyScrolled(false))) {
424 if (!renderer
->parent() && renderer
->node() == renderer
->document() && renderer
->document()->ownerElement())
425 renderer
= renderer
->document()->ownerElement()->renderer();
427 renderer
= renderer
->parent();
431 m_autoscrollInProgress
= true;
432 handleAutoscroll(renderer
);
435 m_mouseDownMayStartAutoscroll
= false;
438 updateSelectionForMouseDrag(targetNode
, event
.localPoint());
442 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent
& event
) const
444 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
445 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
446 // in handleMousePressEvent
448 if (!m_frame
->contentRenderer() || !m_frame
->contentRenderer()->hasLayer())
451 if (event
.button() != LeftButton
|| event
.clickCount() != 1)
456 allowDHTMLDrag(DHTMLFlag
, UAFlag
);
457 if (!DHTMLFlag
&& !UAFlag
)
460 FrameView
* view
= m_frame
->view();
464 HitTestRequest
request(HitTestRequest::ReadOnly
);
465 HitTestResult
result(view
->windowToContents(event
.pos()));
466 m_frame
->contentRenderer()->layer()->hitTest(request
, result
);
468 return result
.innerNode() && result
.innerNode()->renderer()->draggableNode(DHTMLFlag
, UAFlag
, result
.point().x(), result
.point().y(), srcIsDHTML
);
471 void EventHandler::updateSelectionForMouseDrag()
473 FrameView
* view
= m_frame
->view();
476 RenderView
* renderer
= m_frame
->contentRenderer();
479 RenderLayer
* layer
= renderer
->layer();
483 HitTestRequest
request(HitTestRequest::ReadOnly
|
484 HitTestRequest::Active
|
485 HitTestRequest::MouseMove
);
486 HitTestResult
result(view
->windowToContents(m_currentMousePosition
));
487 layer
->hitTest(request
, result
);
488 updateSelectionForMouseDrag(result
.innerNode(), result
.localPoint());
491 void EventHandler::updateSelectionForMouseDrag(Node
* targetNode
, const IntPoint
& localPoint
)
493 if (!m_mouseDownMayStartSelect
)
499 RenderObject
* targetRenderer
= targetNode
->renderer();
503 if (!canMouseDragExtendSelect(targetNode
))
506 VisiblePosition
targetPosition(targetRenderer
->positionForPoint(localPoint
));
508 // Don't modify the selection if we're not on a node.
509 if (targetPosition
.isNull())
512 // Restart the selection if this is the first mouse move. This work is usually
513 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
514 VisibleSelection newSelection
= m_frame
->selection()->selection();
517 // Special case to limit selection to the containing block for SVG text.
518 // FIXME: Isn't there a better non-SVG-specific way to do this?
519 if (Node
* selectionBaseNode
= newSelection
.base().node())
520 if (RenderObject
* selectionBaseRenderer
= selectionBaseNode
->renderer())
521 if (selectionBaseRenderer
->isSVGText())
522 if (targetNode
->renderer()->containingBlock() != selectionBaseRenderer
->containingBlock())
526 if (!m_beganSelectingText
) {
527 m_beganSelectingText
= true;
528 newSelection
= VisibleSelection(targetPosition
);
531 newSelection
.setExtent(targetPosition
);
532 if (m_frame
->selectionGranularity() != CharacterGranularity
)
533 newSelection
.expandUsingGranularity(m_frame
->selectionGranularity());
535 if (m_frame
->shouldChangeSelection(newSelection
)) {
536 m_frame
->selection()->setLastChangeWasHorizontalExtension(false);
537 m_frame
->selection()->setSelection(newSelection
);
541 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults
& event
)
543 if (eventLoopHandleMouseUp(event
))
546 // If this was the first click in the window, we don't even want to clear the selection.
547 // This case occurs when the user clicks on a draggable element, since we have to process
548 // the mouse down and drag events to see if we might start a drag. For other first clicks
549 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
550 // ignored upstream of this layer.
551 return eventActivatedView(event
.event());
554 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults
& event
)
556 if (m_autoscrollInProgress
)
557 stopAutoscrollTimer();
559 if (handleMouseUp(event
))
562 // Used to prevent mouseMoveEvent from initiating a drag before
563 // the mouse is pressed again.
564 m_frame
->selection()->setCaretBlinkingSuspended(false);
565 m_mousePressed
= false;
566 m_capturesDragging
= false;
567 m_mouseDownMayStartDrag
= false;
568 m_mouseDownMayStartSelect
= false;
569 m_mouseDownMayStartAutoscroll
= false;
570 m_mouseDownWasInSubframe
= false;
572 bool handled
= false;
574 // Clear the selection if the mouse didn't move after the last mouse
575 // press and it's not a context menu click. We do this so when clicking
576 // on the selection, the selection goes away. However, if we are
577 // editing, place the caret.
578 if (m_mouseDownWasSingleClickInSelection
&& !m_beganSelectingText
579 && m_dragStartPos
== event
.event().pos()
580 && m_frame
->selection()->isRange()
581 && event
.event().button() != RightButton
) {
582 VisibleSelection newSelection
;
583 Node
*node
= event
.targetNode();
584 bool caretBrowsing
= m_frame
->settings()->caretBrowsingEnabled();
585 if (node
&& (caretBrowsing
|| node
->isContentEditable()) && node
->renderer()) {
586 VisiblePosition pos
= node
->renderer()->positionForPoint(event
.localPoint());
587 newSelection
= VisibleSelection(pos
);
589 if (m_frame
->shouldChangeSelection(newSelection
))
590 m_frame
->selection()->setSelection(newSelection
);
595 m_frame
->notifyRendererOfSelectionChange(true);
597 m_frame
->selection()->selectFrameElementInParentIfFullySelected();
602 void EventHandler::handleAutoscroll(RenderObject
* renderer
)
604 // We don't want to trigger the autoscroll or the panScroll if it's already active
605 if (m_autoscrollTimer
.isActive())
608 setAutoscrollRenderer(renderer
);
610 #if ENABLE(PAN_SCROLLING)
611 if (m_panScrollInProgress
) {
612 m_panScrollStartPos
= currentMousePosition();
613 if (FrameView
* view
= m_frame
->view())
614 view
->addPanScrollIcon(m_panScrollStartPos
);
615 // If we're not in the top frame we notify it that we doing a panScroll.
616 if (Page
* page
= m_frame
->page()) {
617 Frame
* mainFrame
= page
->mainFrame();
618 if (m_frame
!= mainFrame
)
619 mainFrame
->eventHandler()->setPanScrollInProgress(true);
624 startAutoscrollTimer();
627 void EventHandler::autoscrollTimerFired(Timer
<EventHandler
>*)
629 RenderObject
* r
= autoscrollRenderer();
630 if (!r
|| !r
->isBox()) {
631 stopAutoscrollTimer();
635 if (m_autoscrollInProgress
) {
636 if (!m_mousePressed
) {
637 stopAutoscrollTimer();
640 toRenderBox(r
)->autoscroll();
642 // we verify that the main frame hasn't received the order to stop the panScroll
643 if (Page
* page
= m_frame
->page()) {
644 if (!page
->mainFrame()->eventHandler()->panScrollInProgress()) {
645 stopAutoscrollTimer();
649 #if ENABLE(PAN_SCROLLING)
650 setPanScrollCursor();
651 toRenderBox(r
)->panScroll(m_panScrollStartPos
);
656 #if ENABLE(PAN_SCROLLING)
658 void EventHandler::setPanScrollCursor()
660 FrameView
* view
= m_frame
->view();
664 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
665 // So we don't want to change the cursor over this area
666 bool east
= m_panScrollStartPos
.x() < (m_currentMousePosition
.x() - ScrollView::noPanScrollRadius
);
667 bool west
= m_panScrollStartPos
.x() > (m_currentMousePosition
.x() + ScrollView::noPanScrollRadius
);
668 bool north
= m_panScrollStartPos
.y() > (m_currentMousePosition
.y() + ScrollView::noPanScrollRadius
);
669 bool south
= m_panScrollStartPos
.y() < (m_currentMousePosition
.y() - ScrollView::noPanScrollRadius
);
673 view
->setCursor(northEastPanningCursor());
675 view
->setCursor(northWestPanningCursor());
677 view
->setCursor(northPanningCursor());
680 view
->setCursor(southEastPanningCursor());
682 view
->setCursor(southWestPanningCursor());
684 view
->setCursor(southPanningCursor());
686 view
->setCursor(eastPanningCursor());
688 view
->setCursor(westPanningCursor());
690 view
->setCursor(middlePanningCursor());
693 #endif // ENABLE(PAN_SCROLLING)
695 RenderObject
* EventHandler::autoscrollRenderer() const
697 return m_autoscrollRenderer
;
700 void EventHandler::updateAutoscrollRenderer()
702 if (!m_autoscrollRenderer
)
705 HitTestResult hitTest
= hitTestResultAtPoint(m_panScrollStartPos
, true);
707 if (Node
* nodeAtPoint
= hitTest
.innerNode())
708 m_autoscrollRenderer
= nodeAtPoint
->renderer();
710 while (m_autoscrollRenderer
&& (!m_autoscrollRenderer
->isBox() || !toRenderBox(m_autoscrollRenderer
)->canBeProgramaticallyScrolled(false)))
711 m_autoscrollRenderer
= m_autoscrollRenderer
->parent();
714 void EventHandler::setAutoscrollRenderer(RenderObject
* renderer
)
716 m_autoscrollRenderer
= renderer
;
719 void EventHandler::allowDHTMLDrag(bool& flagDHTML
, bool& flagUA
) const
727 Page
* page
= m_frame
->page();
731 FrameView
* view
= m_frame
->view();
735 unsigned mask
= page
->dragController()->delegateDragSourceAction(view
->contentsToWindow(m_mouseDownPos
));
736 flagDHTML
= (mask
& DragSourceActionDHTML
) != DragSourceActionNone
;
737 flagUA
= ((mask
& DragSourceActionImage
) || (mask
& DragSourceActionLink
) || (mask
& DragSourceActionSelection
));
740 HitTestResult
EventHandler::hitTestResultAtPoint(const IntPoint
& point
, bool allowShadowContent
, bool ignoreClipping
, HitTestScrollbars testScrollbars
)
742 HitTestResult
result(point
);
743 if (!m_frame
->contentRenderer())
745 int hitType
= HitTestRequest::ReadOnly
| HitTestRequest::Active
;
747 hitType
|= HitTestRequest::IgnoreClipping
;
748 m_frame
->contentRenderer()->layer()->hitTest(HitTestRequest(hitType
), result
);
751 Node
* n
= result
.innerNode();
752 if (!result
.isOverWidget() || !n
|| !n
->renderer() || !n
->renderer()->isWidget())
754 RenderWidget
* renderWidget
= static_cast<RenderWidget
*>(n
->renderer());
755 Widget
* widget
= renderWidget
->widget();
756 if (!widget
|| !widget
->isFrameView())
758 Frame
* frame
= static_cast<HTMLFrameElementBase
*>(n
)->contentFrame();
759 if (!frame
|| !frame
->contentRenderer())
761 FrameView
* view
= static_cast<FrameView
*>(widget
);
762 IntPoint
widgetPoint(result
.localPoint().x() + view
->scrollX() - renderWidget
->borderLeft() - renderWidget
->paddingLeft(),
763 result
.localPoint().y() + view
->scrollY() - renderWidget
->borderTop() - renderWidget
->paddingTop());
764 HitTestResult
widgetHitTestResult(widgetPoint
);
765 frame
->contentRenderer()->layer()->hitTest(HitTestRequest(hitType
), widgetHitTestResult
);
766 result
= widgetHitTestResult
;
768 if (testScrollbars
== ShouldHitTestScrollbars
) {
769 Scrollbar
* eventScrollbar
= view
->scrollbarUnderPoint(point
);
771 result
.setScrollbar(eventScrollbar
);
775 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
776 // Another hit test at the main frame level should get us the correct visible result.
777 Frame
* resultFrame
= result
.innerNonSharedNode() ? result
.innerNonSharedNode()->document()->frame() : 0;
778 if (Page
* page
= m_frame
->page()) {
779 Frame
* mainFrame
= page
->mainFrame();
780 if (m_frame
!= mainFrame
&& resultFrame
&& resultFrame
!= mainFrame
&& !resultFrame
->editor()->insideVisibleArea(result
.point())) {
781 FrameView
* resultView
= resultFrame
->view();
782 FrameView
* mainView
= mainFrame
->view();
783 if (resultView
&& mainView
) {
784 IntPoint windowPoint
= resultView
->contentsToWindow(result
.point());
785 IntPoint mainFramePoint
= mainView
->windowToContents(windowPoint
);
786 result
= mainFrame
->eventHandler()->hitTestResultAtPoint(mainFramePoint
, allowShadowContent
, ignoreClipping
);
791 if (!allowShadowContent
)
792 result
.setToNonShadowAncestor();
798 void EventHandler::startAutoscrollTimer()
800 m_autoscrollTimer
.startRepeating(autoscrollInterval
);
803 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed
)
805 if (m_autoscrollInProgress
) {
806 if (m_mouseDownWasInSubframe
) {
807 if (Frame
* subframe
= subframeForTargetNode(m_mousePressNode
.get()))
808 subframe
->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed
);
813 if (autoscrollRenderer()) {
814 if (!rendererIsBeingDestroyed
&& (m_autoscrollInProgress
|| m_panScrollInProgress
))
815 toRenderBox(autoscrollRenderer())->stopAutoscroll();
816 #if ENABLE(PAN_SCROLLING)
817 if (m_panScrollInProgress
) {
818 if (FrameView
* view
= m_frame
->view()) {
819 view
->removePanScrollIcon();
820 view
->setCursor(pointerCursor());
825 setAutoscrollRenderer(0);
828 m_autoscrollTimer
.stop();
830 m_panScrollInProgress
= false;
832 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
833 if (Page
* page
= m_frame
->page()) {
834 Frame
* mainFrame
= page
->mainFrame();
835 if (m_frame
!= mainFrame
)
836 mainFrame
->eventHandler()->setPanScrollInProgress(false);
839 m_autoscrollInProgress
= false;
842 Node
* EventHandler::mousePressNode() const
844 return m_mousePressNode
.get();
847 void EventHandler::setMousePressNode(PassRefPtr
<Node
> node
)
849 m_mousePressNode
= node
;
852 bool EventHandler::scrollOverflow(ScrollDirection direction
, ScrollGranularity granularity
)
854 Node
* node
= m_frame
->document()->focusedNode();
856 node
= m_mousePressNode
.get();
859 RenderObject
* r
= node
->renderer();
860 if (r
&& !r
->isListBox())
861 return r
->enclosingBox()->scroll(direction
, granularity
);
867 bool EventHandler::scrollRecursively(ScrollDirection direction
, ScrollGranularity granularity
)
869 bool handled
= scrollOverflow(direction
, granularity
);
871 Frame
* frame
= m_frame
;
873 FrameView
* view
= frame
->view();
874 handled
= view
? view
->scroll(direction
, granularity
) : false;
875 frame
= frame
->tree()->parent();
876 } while (!handled
&& frame
);
882 IntPoint
EventHandler::currentMousePosition() const
884 return m_currentMousePosition
;
887 Frame
* subframeForHitTestResult(const MouseEventWithHitTestResults
& hitTestResult
)
889 if (!hitTestResult
.isOverWidget())
891 return subframeForTargetNode(hitTestResult
.targetNode());
894 Frame
* subframeForTargetNode(Node
* node
)
899 RenderObject
* renderer
= node
->renderer();
900 if (!renderer
|| !renderer
->isWidget())
903 Widget
* widget
= static_cast<RenderWidget
*>(renderer
)->widget();
904 if (!widget
|| !widget
->isFrameView())
907 return static_cast<FrameView
*>(widget
)->frame();
910 static bool isSubmitImage(Node
* node
)
912 return node
&& node
->hasTagName(inputTag
)
913 && static_cast<HTMLInputElement
*>(node
)->inputType() == HTMLInputElement::IMAGE
;
916 // Returns true if the node's editable block is not current focused for editing
917 static bool nodeIsNotBeingEdited(Node
* node
, Frame
* frame
)
919 return frame
->selection()->rootEditableElement() != node
->rootEditableElement();
922 Cursor
EventHandler::selectCursor(const MouseEventWithHitTestResults
& event
, Scrollbar
* scrollbar
)
924 // During selection, use an I-beam no matter what we're over.
925 // If you're capturing mouse events for a particular node, don't treat this as a selection.
926 if (m_mousePressed
&& m_mouseDownMayStartSelect
&& m_frame
->selection()->isCaretOrRange() && !m_capturingMouseEventsNode
)
927 return iBeamCursor();
929 Node
* node
= event
.targetNode();
930 RenderObject
* renderer
= node
? node
->renderer() : 0;
931 RenderStyle
* style
= renderer
? renderer
->style() : 0;
933 if (renderer
&& renderer
->isFrameSet()) {
934 RenderFrameSet
* fs
= static_cast<RenderFrameSet
*>(renderer
);
935 if (fs
->canResizeRow(event
.localPoint()))
936 return rowResizeCursor();
937 if (fs
->canResizeColumn(event
.localPoint()))
938 return columnResizeCursor();
941 if (style
&& style
->cursors()) {
942 const CursorList
* cursors
= style
->cursors();
943 for (unsigned i
= 0; i
< cursors
->size(); ++i
) {
944 CachedImage
* cimage
= (*cursors
)[i
].cursorImage
.get();
945 IntPoint hotSpot
= (*cursors
)[i
].hotSpot
;
948 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
949 IntSize size
= cimage
->image()->size();
950 if (size
.width() > 128 || size
.height() > 128)
952 // Do not let the hotspot be outside the bounds of the image.
953 if (hotSpot
.x() < 0 || hotSpot
.y() < 0 || hotSpot
.x() > size
.width() || hotSpot
.y() > size
.height())
955 if (cimage
->image()->isNull())
957 if (!cimage
->errorOccurred())
958 return Cursor(cimage
->image(), hotSpot
);
962 switch (style
? style
->cursor() : CURSOR_AUTO
) {
964 bool editable
= (node
&& node
->isContentEditable());
965 bool editableLinkEnabled
= false;
967 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
969 ASSERT(m_frame
->settings());
970 switch(m_frame
->settings()->editableLinkBehavior()) {
972 case EditableLinkDefaultBehavior
:
973 case EditableLinkAlwaysLive
:
974 editableLinkEnabled
= true;
977 case EditableLinkNeverLive
:
978 editableLinkEnabled
= false;
981 case EditableLinkLiveWhenNotFocused
:
982 editableLinkEnabled
= nodeIsNotBeingEdited(node
, m_frame
) || event
.event().shiftKey();
985 case EditableLinkOnlyLiveWithShiftKey
:
986 editableLinkEnabled
= event
.event().shiftKey();
991 if ((event
.isOverLink() || isSubmitImage(node
)) && (!editable
|| editableLinkEnabled
))
993 bool inResizer
= false;
995 if (RenderLayer
* layer
= renderer
->enclosingLayer()) {
996 if (FrameView
* view
= m_frame
->view())
997 inResizer
= layer
->isPointInResizeControl(view
->windowToContents(event
.event().pos()));
1000 if ((editable
|| (renderer
&& renderer
->isText() && node
->canStartSelection())) && !inResizer
&& !scrollbar
)
1001 return iBeamCursor();
1002 return pointerCursor();
1005 return crossCursor();
1006 case CURSOR_POINTER
:
1007 return handCursor();
1009 return moveCursor();
1010 case CURSOR_ALL_SCROLL
:
1011 return moveCursor();
1012 case CURSOR_E_RESIZE
:
1013 return eastResizeCursor();
1014 case CURSOR_W_RESIZE
:
1015 return westResizeCursor();
1016 case CURSOR_N_RESIZE
:
1017 return northResizeCursor();
1018 case CURSOR_S_RESIZE
:
1019 return southResizeCursor();
1020 case CURSOR_NE_RESIZE
:
1021 return northEastResizeCursor();
1022 case CURSOR_SW_RESIZE
:
1023 return southWestResizeCursor();
1024 case CURSOR_NW_RESIZE
:
1025 return northWestResizeCursor();
1026 case CURSOR_SE_RESIZE
:
1027 return southEastResizeCursor();
1028 case CURSOR_NS_RESIZE
:
1029 return northSouthResizeCursor();
1030 case CURSOR_EW_RESIZE
:
1031 return eastWestResizeCursor();
1032 case CURSOR_NESW_RESIZE
:
1033 return northEastSouthWestResizeCursor();
1034 case CURSOR_NWSE_RESIZE
:
1035 return northWestSouthEastResizeCursor();
1036 case CURSOR_COL_RESIZE
:
1037 return columnResizeCursor();
1038 case CURSOR_ROW_RESIZE
:
1039 return rowResizeCursor();
1041 return iBeamCursor();
1043 return waitCursor();
1045 return helpCursor();
1046 case CURSOR_VERTICAL_TEXT
:
1047 return verticalTextCursor();
1049 return cellCursor();
1050 case CURSOR_CONTEXT_MENU
:
1051 return contextMenuCursor();
1052 case CURSOR_PROGRESS
:
1053 return progressCursor();
1054 case CURSOR_NO_DROP
:
1055 return noDropCursor();
1057 return aliasCursor();
1059 return copyCursor();
1061 return noneCursor();
1062 case CURSOR_NOT_ALLOWED
:
1063 return notAllowedCursor();
1064 case CURSOR_DEFAULT
:
1065 return pointerCursor();
1066 case CURSOR_WEBKIT_ZOOM_IN
:
1067 return zoomInCursor();
1068 case CURSOR_WEBKIT_ZOOM_OUT
:
1069 return zoomOutCursor();
1070 case CURSOR_WEBKIT_GRAB
:
1071 return grabCursor();
1072 case CURSOR_WEBKIT_GRABBING
:
1073 return grabbingCursor();
1075 return pointerCursor();
1078 static IntPoint
documentPointForWindowPoint(Frame
* frame
, const IntPoint
& windowPoint
)
1080 FrameView
* view
= frame
->view();
1081 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1082 // Historically the code would just crash; this is clearly no worse than that.
1083 return view
? view
->windowToContents(windowPoint
) : windowPoint
;
1086 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent
& mouseEvent
)
1088 RefPtr
<FrameView
> protector(m_frame
->view());
1090 m_mousePressed
= true;
1091 m_capturesDragging
= true;
1092 m_currentMousePosition
= mouseEvent
.pos();
1093 m_mouseDownTimestamp
= mouseEvent
.timestamp();
1094 m_mouseDownMayStartDrag
= false;
1095 m_mouseDownMayStartSelect
= false;
1096 m_mouseDownMayStartAutoscroll
= false;
1097 if (FrameView
* view
= m_frame
->view())
1098 m_mouseDownPos
= view
->windowToContents(mouseEvent
.pos());
1103 m_mouseDownWasInSubframe
= false;
1105 HitTestRequest
request(HitTestRequest::Active
);
1106 // Save the document point we generate in case the window coordinate is invalidated by what happens
1107 // when we dispatch the event.
1108 IntPoint documentPoint
= documentPointForWindowPoint(m_frame
, mouseEvent
.pos());
1109 MouseEventWithHitTestResults mev
= m_frame
->document()->prepareMouseEvent(request
, documentPoint
, mouseEvent
);
1111 if (!mev
.targetNode()) {
1116 m_mousePressNode
= mev
.targetNode();
1118 if (Page
* page
= m_frame
->page()) {
1119 InspectorController
* inspector
= page
->inspectorController();
1120 if (inspector
&& inspector
->enabled() && inspector
->searchingForNodeInPage()) {
1121 inspector
->handleMousePressOnNode(m_mousePressNode
.get());
1127 Frame
* subframe
= subframeForHitTestResult(mev
);
1128 if (subframe
&& passMousePressEventToSubframe(mev
, subframe
)) {
1129 // Start capturing future events for this frame. We only do this if we didn't clear
1130 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1131 m_capturesDragging
= subframe
->eventHandler()->capturesDragging();
1132 if (m_mousePressed
&& m_capturesDragging
)
1133 m_capturingMouseEventsNode
= mev
.targetNode();
1138 #if ENABLE(PAN_SCROLLING)
1139 Page
* page
= m_frame
->page();
1140 if (page
&& page
->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress
) {
1141 stopAutoscrollTimer();
1146 if (mouseEvent
.button() == MiddleButton
&& !mev
.isOverLink()) {
1147 RenderObject
* renderer
= mev
.targetNode()->renderer();
1149 while (renderer
&& (!renderer
->isBox() || !toRenderBox(renderer
)->canBeProgramaticallyScrolled(false))) {
1150 if (!renderer
->parent() && renderer
->node() == renderer
->document() && renderer
->document()->ownerElement())
1151 renderer
= renderer
->document()->ownerElement()->renderer();
1153 renderer
= renderer
->parent();
1157 m_panScrollInProgress
= true;
1158 handleAutoscroll(renderer
);
1165 m_clickCount
= mouseEvent
.clickCount();
1166 m_clickNode
= mev
.targetNode();
1168 if (FrameView
* view
= m_frame
->view()) {
1169 RenderLayer
* layer
= m_clickNode
->renderer() ? m_clickNode
->renderer()->enclosingLayer() : 0;
1170 IntPoint p
= view
->windowToContents(mouseEvent
.pos());
1171 if (layer
&& layer
->isPointInResizeControl(p
)) {
1172 layer
->setInResizeMode(true);
1173 m_resizeLayer
= layer
;
1174 m_offsetFromResizeCorner
= layer
->offsetFromResizeCorner(p
);
1180 bool swallowEvent
= dispatchMouseEvent(eventNames().mousedownEvent
, mev
.targetNode(), true, m_clickCount
, mouseEvent
, true);
1181 m_capturesDragging
= !swallowEvent
;
1183 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1184 // in case the scrollbar widget was destroyed when the mouse event was handled.
1185 if (mev
.scrollbar()) {
1186 const bool wasLastScrollBar
= mev
.scrollbar() == m_lastScrollbarUnderMouse
.get();
1187 HitTestRequest
request(HitTestRequest::ReadOnly
| HitTestRequest::Active
);
1188 mev
= m_frame
->document()->prepareMouseEvent(request
, documentPoint
, mouseEvent
);
1189 if (wasLastScrollBar
&& mev
.scrollbar() != m_lastScrollbarUnderMouse
.get())
1190 m_lastScrollbarUnderMouse
= 0;
1194 // scrollbars should get events anyway, even disabled controls might be scrollable
1195 if (mev
.scrollbar())
1196 passMousePressEventToScrollbar(mev
, mev
.scrollbar());
1198 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1199 // If a mouse event handler changes the input element type to one that has a widget associated,
1200 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1201 // event target node can't still be the shadow node.
1202 if (mev
.targetNode()->isShadowNode() && mev
.targetNode()->shadowParentNode()->hasTagName(inputTag
)) {
1203 HitTestRequest
request(HitTestRequest::ReadOnly
| HitTestRequest::Active
);
1204 mev
= m_frame
->document()->prepareMouseEvent(request
, documentPoint
, mouseEvent
);
1207 FrameView
* view
= m_frame
->view();
1208 Scrollbar
* scrollbar
= view
? view
->scrollbarUnderPoint(mouseEvent
.pos()) : 0;
1210 scrollbar
= mev
.scrollbar();
1211 if (scrollbar
&& passMousePressEventToScrollbar(mev
, scrollbar
))
1212 swallowEvent
= true;
1214 swallowEvent
= handleMousePressEvent(mev
);
1217 return swallowEvent
;
1220 // This method only exists for platforms that don't know how to deliver
1221 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent
& mouseEvent
)
1223 RefPtr
<FrameView
> protector(m_frame
->view());
1225 // We get this instead of a second mouse-up
1226 m_mousePressed
= false;
1227 m_currentMousePosition
= mouseEvent
.pos();
1229 HitTestRequest
request(HitTestRequest::Active
);
1230 MouseEventWithHitTestResults mev
= prepareMouseEvent(request
, mouseEvent
);
1231 Frame
* subframe
= subframeForHitTestResult(mev
);
1232 if (subframe
&& passMousePressEventToSubframe(mev
, subframe
)) {
1233 m_capturingMouseEventsNode
= 0;
1237 m_clickCount
= mouseEvent
.clickCount();
1238 bool swallowMouseUpEvent
= dispatchMouseEvent(eventNames().mouseupEvent
, mev
.targetNode(), true, m_clickCount
, mouseEvent
, false);
1240 bool swallowClickEvent
= false;
1241 // Don't ever dispatch click events for right clicks
1242 if (mouseEvent
.button() != RightButton
&& mev
.targetNode() == m_clickNode
)
1243 swallowClickEvent
= dispatchMouseEvent(eventNames().clickEvent
, mev
.targetNode(), true, m_clickCount
, mouseEvent
, true);
1245 if (m_lastScrollbarUnderMouse
)
1246 swallowMouseUpEvent
= m_lastScrollbarUnderMouse
->mouseUp();
1248 bool swallowMouseReleaseEvent
= false;
1249 if (!swallowMouseUpEvent
)
1250 swallowMouseReleaseEvent
= handleMouseReleaseEvent(mev
);
1254 return swallowMouseUpEvent
|| swallowClickEvent
|| swallowMouseReleaseEvent
;
1257 bool EventHandler::mouseMoved(const PlatformMouseEvent
& event
)
1259 HitTestResult hoveredNode
= HitTestResult(IntPoint());
1260 bool result
= handleMouseMoveEvent(event
, &hoveredNode
);
1262 Page
* page
= m_frame
->page();
1266 hoveredNode
.setToNonShadowAncestor();
1267 page
->chrome()->mouseDidMoveOverElement(hoveredNode
, event
.modifierFlags());
1268 page
->chrome()->setToolTip(hoveredNode
);
1272 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent
& mouseEvent
, HitTestResult
* hoveredNode
)
1274 // in Radar 3703768 we saw frequent crashes apparently due to the
1275 // part being null here, which seems impossible, so check for nil
1276 // but also assert so that we can try to figure this out in debug
1277 // builds, if it happens.
1282 RefPtr
<FrameView
> protector(m_frame
->view());
1283 m_currentMousePosition
= mouseEvent
.pos();
1285 if (m_hoverTimer
.isActive())
1286 m_hoverTimer
.stop();
1290 static_cast<SVGDocument
*>(m_frame
->document())->updatePan(m_currentMousePosition
);
1295 if (m_frameSetBeingResized
)
1296 return dispatchMouseEvent(eventNames().mousemoveEvent
, m_frameSetBeingResized
.get(), false, 0, mouseEvent
, false);
1298 // Send events right to a scrollbar if the mouse is pressed.
1299 if (m_lastScrollbarUnderMouse
&& m_mousePressed
)
1300 return m_lastScrollbarUnderMouse
->mouseMoved(m_lastScrollbarUnderMouse
->transformEvent(mouseEvent
));
1302 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
1303 // if we are allowed to select.
1304 // This means that :hover and :active freeze in the state they were in when the mouse
1305 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
1306 int hitType
= HitTestRequest::MouseMove
;
1307 if (m_mousePressed
&& m_mouseDownMayStartSelect
)
1308 hitType
|= HitTestRequest::ReadOnly
;
1310 hitType
|= HitTestRequest::Active
;
1311 HitTestRequest
request(hitType
);
1312 MouseEventWithHitTestResults mev
= prepareMouseEvent(request
, mouseEvent
);
1314 *hoveredNode
= mev
.hitTestResult();
1316 Scrollbar
* scrollbar
= 0;
1318 if (m_resizeLayer
&& m_resizeLayer
->inResizeMode())
1319 m_resizeLayer
->resize(mouseEvent
, m_offsetFromResizeCorner
);
1321 if (FrameView
* view
= m_frame
->view())
1322 scrollbar
= view
->scrollbarUnderPoint(mouseEvent
.pos());
1325 scrollbar
= mev
.scrollbar();
1327 if (m_lastScrollbarUnderMouse
!= scrollbar
) {
1328 // Send mouse exited to the old scrollbar.
1329 if (m_lastScrollbarUnderMouse
)
1330 m_lastScrollbarUnderMouse
->mouseExited();
1331 m_lastScrollbarUnderMouse
= m_mousePressed
? 0 : scrollbar
;
1335 bool swallowEvent
= false;
1336 RefPtr
<Frame
> newSubframe
= m_capturingMouseEventsNode
.get() ? subframeForTargetNode(m_capturingMouseEventsNode
.get()) : subframeForHitTestResult(mev
);
1338 // 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.
1339 if (m_lastMouseMoveEventSubframe
&& m_lastMouseMoveEventSubframe
->tree()->isDescendantOf(m_frame
) && m_lastMouseMoveEventSubframe
!= newSubframe
)
1340 passMouseMoveEventToSubframe(mev
, m_lastMouseMoveEventSubframe
.get());
1343 // Update over/out state before passing the event to the subframe.
1344 updateMouseEventTargetNode(mev
.targetNode(), mouseEvent
, true);
1346 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1347 // node to be detached from its FrameView, in which case the event should not be passed.
1348 if (newSubframe
->view())
1349 swallowEvent
|= passMouseMoveEventToSubframe(mev
, newSubframe
.get(), hoveredNode
);
1351 if (scrollbar
&& !m_mousePressed
)
1352 scrollbar
->mouseMoved(scrollbar
->transformEvent(mouseEvent
)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1353 if (Page
* page
= m_frame
->page()) {
1354 if ((!m_resizeLayer
|| !m_resizeLayer
->inResizeMode()) && !page
->mainFrame()->eventHandler()->panScrollInProgress()) {
1355 if (FrameView
* view
= m_frame
->view())
1356 view
->setCursor(selectCursor(mev
, scrollbar
));
1361 m_lastMouseMoveEventSubframe
= newSubframe
;
1366 swallowEvent
= dispatchMouseEvent(eventNames().mousemoveEvent
, mev
.targetNode(), false, 0, mouseEvent
, true);
1368 swallowEvent
= handleMouseDraggedEvent(mev
);
1370 return swallowEvent
;
1373 void EventHandler::invalidateClick()
1379 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent
& mouseEvent
)
1381 RefPtr
<FrameView
> protector(m_frame
->view());
1383 m_mousePressed
= false;
1384 m_currentMousePosition
= mouseEvent
.pos();
1389 static_cast<SVGDocument
*>(m_frame
->document())->updatePan(m_currentMousePosition
);
1394 if (m_frameSetBeingResized
)
1395 return dispatchMouseEvent(eventNames().mouseupEvent
, m_frameSetBeingResized
.get(), true, m_clickCount
, mouseEvent
, false);
1397 if (m_lastScrollbarUnderMouse
) {
1399 return m_lastScrollbarUnderMouse
->mouseUp();
1402 HitTestRequest
request(HitTestRequest::MouseUp
);
1403 MouseEventWithHitTestResults mev
= prepareMouseEvent(request
, mouseEvent
);
1404 Frame
* subframe
= m_capturingMouseEventsNode
.get() ? subframeForTargetNode(m_capturingMouseEventsNode
.get()) : subframeForHitTestResult(mev
);
1405 if (subframe
&& passMouseReleaseEventToSubframe(mev
, subframe
)) {
1406 m_capturingMouseEventsNode
= 0;
1410 bool swallowMouseUpEvent
= dispatchMouseEvent(eventNames().mouseupEvent
, mev
.targetNode(), true, m_clickCount
, mouseEvent
, false);
1412 // Don't ever dispatch click events for right clicks
1413 bool swallowClickEvent
= false;
1414 if (m_clickCount
> 0 && mouseEvent
.button() != RightButton
&& mev
.targetNode() == m_clickNode
)
1415 swallowClickEvent
= dispatchMouseEvent(eventNames().clickEvent
, mev
.targetNode(), true, m_clickCount
, mouseEvent
, true);
1417 if (m_resizeLayer
) {
1418 m_resizeLayer
->setInResizeMode(false);
1422 bool swallowMouseReleaseEvent
= false;
1423 if (!swallowMouseUpEvent
)
1424 swallowMouseReleaseEvent
= handleMouseReleaseEvent(mev
);
1428 return swallowMouseUpEvent
|| swallowClickEvent
|| swallowMouseReleaseEvent
;
1431 bool EventHandler::dispatchDragEvent(const AtomicString
& eventType
, Node
* dragTarget
, const PlatformMouseEvent
& event
, Clipboard
* clipboard
)
1433 FrameView
* view
= m_frame
->view();
1435 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1439 view
->resetDeferredRepaintDelay();
1440 IntPoint contentsPos
= view
->windowToContents(event
.pos());
1442 RefPtr
<MouseEvent
> me
= MouseEvent::create(eventType
,
1443 true, true, m_frame
->document()->defaultView(),
1444 0, event
.globalX(), event
.globalY(), contentsPos
.x(), contentsPos
.y(),
1445 event
.ctrlKey(), event
.altKey(), event
.shiftKey(), event
.metaKey(),
1449 dragTarget
->dispatchEvent(me
.get(), ec
);
1450 return me
->defaultPrevented();
1453 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent
& event
, Clipboard
* clipboard
)
1455 bool accept
= false;
1457 if (!m_frame
->view())
1460 HitTestRequest
request(HitTestRequest::ReadOnly
);
1461 MouseEventWithHitTestResults mev
= prepareMouseEvent(request
, event
);
1463 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1464 Node
* newTarget
= mev
.targetNode();
1465 if (newTarget
&& newTarget
->isTextNode())
1466 newTarget
= newTarget
->parentNode();
1468 newTarget
= newTarget
->shadowAncestorNode();
1470 if (m_dragTarget
!= newTarget
) {
1471 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1472 // it is sometimes incorrect when dragging within subframes, as seen with
1473 // LayoutTests/fast/events/drag-in-frames.html.
1475 if (newTarget
->hasTagName(frameTag
) || newTarget
->hasTagName(iframeTag
))
1476 accept
= static_cast<HTMLFrameElementBase
*>(newTarget
)->contentFrame()->eventHandler()->updateDragAndDrop(event
, clipboard
);
1478 accept
= dispatchDragEvent(eventNames().dragenterEvent
, newTarget
, event
, clipboard
);
1482 Frame
* frame
= (m_dragTarget
->hasTagName(frameTag
) || m_dragTarget
->hasTagName(iframeTag
))
1483 ? static_cast<HTMLFrameElementBase
*>(m_dragTarget
.get())->contentFrame() : 0;
1485 accept
= frame
->eventHandler()->updateDragAndDrop(event
, clipboard
);
1487 dispatchDragEvent(eventNames().dragleaveEvent
, m_dragTarget
.get(), event
, clipboard
);
1491 if (newTarget
->hasTagName(frameTag
) || newTarget
->hasTagName(iframeTag
))
1492 accept
= static_cast<HTMLFrameElementBase
*>(newTarget
)->contentFrame()->eventHandler()->updateDragAndDrop(event
, clipboard
);
1494 accept
= dispatchDragEvent(eventNames().dragoverEvent
, newTarget
, event
, clipboard
);
1497 m_dragTarget
= newTarget
;
1502 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent
& event
, Clipboard
* clipboard
)
1505 Frame
* frame
= (m_dragTarget
->hasTagName(frameTag
) || m_dragTarget
->hasTagName(iframeTag
))
1506 ? static_cast<HTMLFrameElementBase
*>(m_dragTarget
.get())->contentFrame() : 0;
1508 frame
->eventHandler()->cancelDragAndDrop(event
, clipboard
);
1510 dispatchDragEvent(eventNames().dragleaveEvent
, m_dragTarget
.get(), event
, clipboard
);
1515 bool EventHandler::performDragAndDrop(const PlatformMouseEvent
& event
, Clipboard
* clipboard
)
1517 bool accept
= false;
1519 Frame
* frame
= (m_dragTarget
->hasTagName(frameTag
) || m_dragTarget
->hasTagName(iframeTag
))
1520 ? static_cast<HTMLFrameElementBase
*>(m_dragTarget
.get())->contentFrame() : 0;
1522 accept
= frame
->eventHandler()->performDragAndDrop(event
, clipboard
);
1524 accept
= dispatchDragEvent(eventNames().dropEvent
, m_dragTarget
.get(), event
, clipboard
);
1530 void EventHandler::clearDragState()
1533 m_capturingMouseEventsNode
= 0;
1535 m_sendingEventToSubview
= false;
1539 void EventHandler::setCapturingMouseEventsNode(PassRefPtr
<Node
> n
)
1541 m_capturingMouseEventsNode
= n
;
1544 MouseEventWithHitTestResults
EventHandler::prepareMouseEvent(const HitTestRequest
& request
, const PlatformMouseEvent
& mev
)
1547 ASSERT(m_frame
->document());
1549 return m_frame
->document()->prepareMouseEvent(request
, documentPointForWindowPoint(m_frame
, mev
.pos()), mev
);
1553 static inline SVGElementInstance
* instanceAssociatedWithShadowTreeElement(Node
* referenceNode
)
1555 if (!referenceNode
|| !referenceNode
->isSVGElement())
1558 Node
* shadowTreeElement
= referenceNode
->shadowTreeRootNode();
1559 if (!shadowTreeElement
)
1562 Node
* shadowTreeParentElement
= shadowTreeElement
->shadowParentNode();
1563 if (!shadowTreeParentElement
)
1566 ASSERT(shadowTreeParentElement
->hasTagName(useTag
));
1567 return static_cast<SVGUseElement
*>(shadowTreeParentElement
)->instanceForShadowTreeElement(referenceNode
);
1571 void EventHandler::updateMouseEventTargetNode(Node
* targetNode
, const PlatformMouseEvent
& mouseEvent
, bool fireMouseOverOut
)
1573 Node
* result
= targetNode
;
1575 // If we're capturing, we always go right to that node.
1576 if (m_capturingMouseEventsNode
)
1577 result
= m_capturingMouseEventsNode
.get();
1579 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1580 if (result
&& result
->isTextNode())
1581 result
= result
->parentNode();
1583 result
= result
->shadowAncestorNode();
1585 m_nodeUnderMouse
= result
;
1587 m_instanceUnderMouse
= instanceAssociatedWithShadowTreeElement(result
);
1589 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1590 if (m_lastInstanceUnderMouse
) {
1591 SVGElement
* lastCorrespondingElement
= m_lastInstanceUnderMouse
->correspondingElement();
1592 SVGElement
* lastCorrespondingUseElement
= m_lastInstanceUnderMouse
->correspondingUseElement();
1594 if (lastCorrespondingElement
&& lastCorrespondingUseElement
) {
1595 HashSet
<SVGElementInstance
*> instances
= lastCorrespondingElement
->instancesForElement();
1597 // Locate the recloned shadow tree element for our corresponding instance
1598 HashSet
<SVGElementInstance
*>::iterator end
= instances
.end();
1599 for (HashSet
<SVGElementInstance
*>::iterator it
= instances
.begin(); it
!= end
; ++it
) {
1600 SVGElementInstance
* instance
= (*it
);
1601 ASSERT(instance
->correspondingElement() == lastCorrespondingElement
);
1603 if (instance
== m_lastInstanceUnderMouse
)
1606 if (instance
->correspondingUseElement() != lastCorrespondingUseElement
)
1609 SVGElement
* shadowTreeElement
= instance
->shadowTreeElement();
1610 if (!shadowTreeElement
->inDocument() || m_lastNodeUnderMouse
== shadowTreeElement
)
1613 m_lastNodeUnderMouse
= shadowTreeElement
;
1614 m_lastInstanceUnderMouse
= instance
;
1621 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1622 if (fireMouseOverOut
) {
1623 if (m_lastNodeUnderMouse
&& m_lastNodeUnderMouse
->document() != m_frame
->document()) {
1624 m_lastNodeUnderMouse
= 0;
1625 m_lastScrollbarUnderMouse
= 0;
1627 m_lastInstanceUnderMouse
= 0;
1631 if (m_lastNodeUnderMouse
!= m_nodeUnderMouse
) {
1632 // send mouseout event to the old node
1633 if (m_lastNodeUnderMouse
)
1634 m_lastNodeUnderMouse
->dispatchMouseEvent(mouseEvent
, eventNames().mouseoutEvent
, 0, m_nodeUnderMouse
.get());
1635 // send mouseover event to the new node
1636 if (m_nodeUnderMouse
)
1637 m_nodeUnderMouse
->dispatchMouseEvent(mouseEvent
, eventNames().mouseoverEvent
, 0, m_lastNodeUnderMouse
.get());
1639 m_lastNodeUnderMouse
= m_nodeUnderMouse
;
1641 m_lastInstanceUnderMouse
= instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse
.get());
1646 bool EventHandler::dispatchMouseEvent(const AtomicString
& eventType
, Node
* targetNode
, bool /*cancelable*/, int clickCount
, const PlatformMouseEvent
& mouseEvent
, bool setUnder
)
1648 if (FrameView
* view
= m_frame
->view())
1649 view
->resetDeferredRepaintDelay();
1651 updateMouseEventTargetNode(targetNode
, mouseEvent
, setUnder
);
1653 bool swallowEvent
= false;
1655 if (m_nodeUnderMouse
)
1656 swallowEvent
= m_nodeUnderMouse
->dispatchMouseEvent(mouseEvent
, eventType
, clickCount
);
1658 if (!swallowEvent
&& eventType
== eventNames().mousedownEvent
) {
1659 // Blur current focus node when a link/button is clicked; this
1660 // is expected by some sites that rely on onChange handlers running
1661 // from form fields before the button click is processed.
1662 Node
* node
= m_nodeUnderMouse
.get();
1663 RenderObject
* renderer
= node
? node
->renderer() : 0;
1665 // Walk up the render tree to search for a node to focus.
1666 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1668 node
= renderer
->node();
1669 if (node
&& node
->isFocusable()) {
1670 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
1671 // node on mouse down if it's selected and inside a focused node. It will be
1672 // focused if the user does a mouseup over it, however, because the mouseup
1673 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
1674 ExceptionCode ec
= 0;
1675 Node
* n
= node
->isShadowNode() ? node
->shadowParentNode() : node
;
1676 if (m_frame
->selection()->isRange() &&
1677 m_frame
->selection()->toNormalizedRange()->compareNode(n
, ec
) == Range::NODE_INSIDE
&&
1678 n
->isDescendantOf(m_frame
->document()->focusedNode()))
1684 renderer
= renderer
->parent();
1687 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1688 // if the page already set it (e.g., by canceling default behavior).
1689 if (Page
* page
= m_frame
->page()) {
1690 if (node
&& node
->isMouseFocusable()) {
1691 if (!page
->focusController()->setFocusedNode(node
, m_frame
))
1692 swallowEvent
= true;
1693 } else if (!node
|| !node
->focused()) {
1694 if (!page
->focusController()->setFocusedNode(0, m_frame
))
1695 swallowEvent
= true;
1700 return swallowEvent
;
1703 bool EventHandler::handleWheelEvent(PlatformWheelEvent
& e
)
1705 Document
* doc
= m_frame
->document();
1707 RenderObject
* docRenderer
= doc
->renderer();
1711 RefPtr
<FrameView
> protector(m_frame
->view());
1713 FrameView
* view
= m_frame
->view();
1716 IntPoint vPoint
= view
->windowToContents(e
.pos());
1718 HitTestRequest
request(HitTestRequest::ReadOnly
);
1719 HitTestResult
result(vPoint
);
1720 doc
->renderView()->layer()->hitTest(request
, result
);
1721 Node
* node
= result
.innerNode();
1724 // Figure out which view to send the event to.
1725 RenderObject
* target
= node
->renderer();
1727 if (result
.isOverWidget() && target
&& target
->isWidget()) {
1728 Widget
* widget
= static_cast<RenderWidget
*>(target
)->widget();
1730 if (widget
&& passWheelEventToWidget(e
, widget
)) {
1736 node
= node
->shadowAncestorNode();
1737 node
->dispatchWheelEvent(e
);
1741 // If we don't have a renderer, send the wheel event to the first node we find with a renderer.
1742 // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll.
1743 while (node
&& !node
->renderer())
1744 node
= node
->parent();
1746 if (node
&& node
->renderer()) {
1747 // Just break up into two scrolls if we need to. Diagonal movement on
1748 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
1749 scrollAndAcceptEvent(e
.deltaX(), ScrollLeft
, ScrollRight
, e
, node
);
1750 scrollAndAcceptEvent(e
.deltaY(), ScrollUp
, ScrollDown
, e
, node
);
1757 view
= m_frame
->view();
1761 view
->wheelEvent(e
);
1762 return e
.isAccepted();
1765 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent
& event
)
1767 Document
* doc
= m_frame
->document();
1768 FrameView
* v
= m_frame
->view();
1773 IntPoint viewportPos
= v
->windowToContents(event
.pos());
1774 HitTestRequest
request(HitTestRequest::Active
);
1775 MouseEventWithHitTestResults mev
= doc
->prepareMouseEvent(request
, viewportPos
, event
);
1777 // Context menu events shouldn't select text in GTK+ applications or in Chromium.
1778 // FIXME: This should probably be configurable by embedders. Consider making it a WebPreferences setting.
1779 // See: https://bugs.webkit.org/show_bug.cgi?id=15279
1780 #if !PLATFORM(GTK) && !PLATFORM(CHROMIUM)
1781 if (!m_frame
->selection()->contains(viewportPos
) &&
1782 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
1783 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
1784 // available for text selections. But only if we're above text.
1785 (m_frame
->selection()->isContentEditable() || (mev
.targetNode() && mev
.targetNode()->isTextNode()))) {
1786 m_mouseDownMayStartSelect
= true; // context menu events are always allowed to perform a selection
1787 selectClosestWordOrLinkFromMouseEvent(mev
);
1791 swallowEvent
= dispatchMouseEvent(eventNames().contextmenuEvent
, mev
.targetNode(), true, 0, event
, true);
1793 return swallowEvent
;
1796 void EventHandler::scheduleHoverStateUpdate()
1798 if (!m_hoverTimer
.isActive())
1799 m_hoverTimer
.startOneShot(0);
1802 // Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
1803 bool EventHandler::canMouseDownStartSelect(Node
* node
)
1805 if (!node
|| !node
->renderer())
1808 // Some controls and images can't start a select on a mouse down.
1809 if (!node
->canStartSelection())
1812 for (RenderObject
* curr
= node
->renderer(); curr
; curr
= curr
->parent()) {
1813 if (Node
* node
= curr
->node())
1814 return node
->dispatchEvent(eventNames().selectstartEvent
, true, true);
1820 bool EventHandler::canMouseDragExtendSelect(Node
* node
)
1822 if (!node
|| !node
->renderer())
1825 for (RenderObject
* curr
= node
->renderer(); curr
; curr
= curr
->parent()) {
1826 if (Node
* node
= curr
->node())
1827 return node
->dispatchEvent(eventNames().selectstartEvent
, true, true);
1833 void EventHandler::setResizingFrameSet(HTMLFrameSetElement
* frameSet
)
1835 m_frameSetBeingResized
= frameSet
;
1838 void EventHandler::resizeLayerDestroyed()
1840 ASSERT(m_resizeLayer
);
1844 void EventHandler::hoverTimerFired(Timer
<EventHandler
>*)
1846 m_hoverTimer
.stop();
1849 ASSERT(m_frame
->document());
1851 if (RenderView
* renderer
= m_frame
->contentRenderer()) {
1852 if (FrameView
* view
= m_frame
->view()) {
1853 HitTestRequest
request(HitTestRequest::MouseMove
);
1854 HitTestResult
result(view
->windowToContents(m_currentMousePosition
));
1855 renderer
->layer()->hitTest(request
, result
);
1856 m_frame
->document()->updateStyleIfNeeded();
1861 static Node
* eventTargetNodeForDocument(Document
* doc
)
1865 Node
* node
= doc
->focusedNode();
1866 if (!node
&& doc
->isHTMLDocument())
1869 node
= doc
->documentElement();
1873 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent
& evt
)
1875 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
1876 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
1877 // lower case variants are present in a document, the correct element is matched based on Shift key state.
1878 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
1879 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey
));
1880 if ((evt
.modifiers() & ~PlatformKeyboardEvent::ShiftKey
) != accessKeyModifiers())
1882 String key
= evt
.unmodifiedText();
1883 Element
* elem
= m_frame
->document()->getElementByAccessKey(key
.lower());
1886 elem
->accessKeyAction(false);
1891 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
1897 bool EventHandler::keyEvent(const PlatformKeyboardEvent
& initialKeyEvent
)
1899 #if ENABLE(PAN_SCROLLING)
1900 if (Page
* page
= m_frame
->page()) {
1901 if (page
->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress
) {
1902 static const char* const escapeKeyIdentifier
= "U+001B";
1904 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
1905 if (initialKeyEvent
.keyIdentifier() == escapeKeyIdentifier
&& initialKeyEvent
.type() == PlatformKeyboardEvent::KeyUp
)
1906 stopAutoscrollTimer();
1908 // If we were in autoscroll/panscroll mode, we swallow the key event
1914 // Check for cases where we are too early for events -- possible unmatched key up
1915 // from pressing return in the location bar.
1916 RefPtr
<Node
> node
= eventTargetNodeForDocument(m_frame
->document());
1920 if (FrameView
* view
= m_frame
->view())
1921 view
->resetDeferredRepaintDelay();
1923 // FIXME: what is this doing here, in keyboard event handler?
1924 m_frame
->loader()->resetMultipleFormSubmissionProtection();
1926 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
1927 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
1928 // with access keys. Then we dispatch keydown, but suppress its default handling.
1929 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
1930 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
1931 bool matchedAnAccessKey
= false;
1932 if (initialKeyEvent
.type() == PlatformKeyboardEvent::KeyDown
)
1933 matchedAnAccessKey
= handleAccessKey(initialKeyEvent
);
1935 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
1936 if (initialKeyEvent
.type() == PlatformKeyboardEvent::KeyUp
|| initialKeyEvent
.type() == PlatformKeyboardEvent::Char
)
1937 return !node
->dispatchKeyEvent(initialKeyEvent
);
1939 bool backwardCompatibilityMode
= needsKeyboardEventDisambiguationQuirks();
1942 PlatformKeyboardEvent keyDownEvent
= initialKeyEvent
;
1943 if (keyDownEvent
.type() != PlatformKeyboardEvent::RawKeyDown
)
1944 keyDownEvent
.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown
, backwardCompatibilityMode
);
1945 RefPtr
<KeyboardEvent
> keydown
= KeyboardEvent::create(keyDownEvent
, m_frame
->document()->defaultView());
1946 if (matchedAnAccessKey
)
1947 keydown
->setDefaultPrevented(true);
1948 keydown
->setTarget(node
);
1950 if (initialKeyEvent
.type() == PlatformKeyboardEvent::RawKeyDown
) {
1951 node
->dispatchEvent(keydown
, ec
);
1952 return keydown
->defaultHandled() || keydown
->defaultPrevented();
1955 // Run input method in advance of DOM event handling. This may result in the IM
1956 // modifying the page prior the keydown event, but this behaviour is necessary
1957 // in order to match IE:
1958 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
1959 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
1960 m_frame
->editor()->handleInputMethodKeydown(keydown
.get());
1962 bool handledByInputMethod
= keydown
->defaultHandled();
1964 if (handledByInputMethod
) {
1965 keyDownEvent
.setWindowsVirtualKeyCode(CompositionEventKeyCode
);
1966 keydown
= KeyboardEvent::create(keyDownEvent
, m_frame
->document()->defaultView());
1967 keydown
->setTarget(node
);
1968 keydown
->setDefaultHandled();
1971 node
->dispatchEvent(keydown
, ec
);
1972 bool keydownResult
= keydown
->defaultHandled() || keydown
->defaultPrevented();
1973 if (handledByInputMethod
|| (keydownResult
&& !backwardCompatibilityMode
))
1974 return keydownResult
;
1976 // Focus may have changed during keydown handling, so refetch node.
1977 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
1978 if (!keydownResult
) {
1979 node
= eventTargetNodeForDocument(m_frame
->document());
1984 PlatformKeyboardEvent keyPressEvent
= initialKeyEvent
;
1985 keyPressEvent
.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char
, backwardCompatibilityMode
);
1986 if (keyPressEvent
.text().isEmpty())
1987 return keydownResult
;
1988 RefPtr
<KeyboardEvent
> keypress
= KeyboardEvent::create(keyPressEvent
, m_frame
->document()->defaultView());
1989 keypress
->setTarget(node
);
1991 keypress
->setDefaultPrevented(true);
1993 keypress
->keypressCommands() = keydown
->keypressCommands();
1995 node
->dispatchEvent(keypress
, ec
);
1997 return keydownResult
|| keypress
->defaultPrevented() || keypress
->defaultHandled();
2000 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent
* event
)
2005 String key
= event
->keyIdentifier();
2006 bool isShifted
= event
->getModifierState("Shift");
2007 bool isOptioned
= event
->getModifierState("Alt");
2008 bool isCommanded
= event
->getModifierState("Meta");
2011 m_frame
->selection()->modify((isShifted
) ? SelectionController::EXTEND
: SelectionController::MOVE
, SelectionController::BACKWARD
, (isCommanded
) ? DocumentBoundary
: LineGranularity
, true);
2012 event
->setDefaultHandled();
2014 else if (key
== "Down") {
2015 m_frame
->selection()->modify((isShifted
) ? SelectionController::EXTEND
: SelectionController::MOVE
, SelectionController::FORWARD
, (isCommanded
) ? DocumentBoundary
: LineGranularity
, true);
2016 event
->setDefaultHandled();
2018 else if (key
== "Left") {
2019 m_frame
->selection()->modify((isShifted
) ? SelectionController::EXTEND
: SelectionController::MOVE
, SelectionController::LEFT
, (isCommanded
) ? LineBoundary
: (isOptioned
) ? WordGranularity
: CharacterGranularity
, true);
2020 event
->setDefaultHandled();
2022 else if (key
== "Right") {
2023 m_frame
->selection()->modify((isShifted
) ? SelectionController::EXTEND
: SelectionController::MOVE
, SelectionController::RIGHT
, (isCommanded
) ? LineBoundary
: (isOptioned
) ? WordGranularity
: CharacterGranularity
, true);
2024 event
->setDefaultHandled();
2028 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent
* event
)
2030 if (event
->type() == eventNames().keydownEvent
) {
2031 m_frame
->editor()->handleKeyboardEvent(event
);
2032 if (event
->defaultHandled())
2034 if (event
->keyIdentifier() == "U+0009")
2035 defaultTabEventHandler(event
);
2037 // provides KB navigation and selection for enhanced accessibility users
2038 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2039 handleKeyboardSelectionMovement(event
);
2041 if (event
->type() == eventNames().keypressEvent
) {
2042 m_frame
->editor()->handleKeyboardEvent(event
);
2043 if (event
->defaultHandled())
2045 if (event
->charCode() == ' ')
2046 defaultSpaceEventHandler(event
);
2050 bool EventHandler::dragHysteresisExceeded(const FloatPoint
& floatDragViewportLocation
) const
2052 IntPoint
dragViewportLocation((int)floatDragViewportLocation
.x(), (int)floatDragViewportLocation
.y());
2053 return dragHysteresisExceeded(dragViewportLocation
);
2056 bool EventHandler::dragHysteresisExceeded(const IntPoint
& dragViewportLocation
) const
2058 FrameView
* view
= m_frame
->view();
2061 IntPoint dragLocation
= view
->windowToContents(dragViewportLocation
);
2062 IntSize delta
= dragLocation
- m_mouseDownPos
;
2064 int threshold
= GeneralDragHysteresis
;
2065 if (dragState().m_dragSrcIsImage
)
2066 threshold
= ImageDragHysteresis
;
2067 else if (dragState().m_dragSrcIsLink
)
2068 threshold
= LinkDragHysteresis
;
2069 else if (dragState().m_dragSrcInSelection
)
2070 threshold
= TextDragHysteresis
;
2072 return abs(delta
.width()) >= threshold
|| abs(delta
.height()) >= threshold
;
2075 void EventHandler::freeClipboard()
2077 if (dragState().m_dragClipboard
)
2078 dragState().m_dragClipboard
->setAccessPolicy(ClipboardNumb
);
2081 bool EventHandler::shouldDragAutoNode(Node
* node
, const IntPoint
& point
) const
2083 if (!node
|| node
->hasChildNodes() || !m_frame
->view())
2085 Page
* page
= m_frame
->page();
2086 return page
&& page
->dragController()->mayStartDragAtEventLocation(m_frame
, point
);
2089 void EventHandler::dragSourceMovedTo(const PlatformMouseEvent
& event
)
2091 if (dragState().m_dragSrc
&& dragState().m_dragSrcMayBeDHTML
)
2092 // for now we don't care if event handler cancels default behavior, since there is none
2093 dispatchDragSrcEvent(eventNames().dragEvent
, event
);
2096 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent
& event
, DragOperation operation
)
2098 if (dragState().m_dragSrc
&& dragState().m_dragSrcMayBeDHTML
) {
2099 dragState().m_dragClipboard
->setDestinationOperation(operation
);
2100 // for now we don't care if event handler cancels default behavior, since there is none
2101 dispatchDragSrcEvent(eventNames().dragendEvent
, event
);
2104 dragState().m_dragSrc
= 0;
2107 // returns if we should continue "default processing", i.e., whether eventhandler canceled
2108 bool EventHandler::dispatchDragSrcEvent(const AtomicString
& eventType
, const PlatformMouseEvent
& event
)
2110 return !dispatchDragEvent(eventType
, dragState().m_dragSrc
.get(), event
, dragState().m_dragClipboard
.get());
2113 bool EventHandler::handleDrag(const MouseEventWithHitTestResults
& event
)
2115 if (event
.event().button() != LeftButton
|| event
.event().eventType() != MouseEventMoved
) {
2116 // If we allowed the other side of the bridge to handle a drag
2117 // last time, then m_mousePressed might still be set. So we
2118 // clear it now to make sure the next move after a drag
2119 // doesn't look like a drag.
2120 m_mousePressed
= false;
2124 if (eventLoopHandleMouseDragged(event
))
2127 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
2129 if (m_mouseDownMayStartDrag
&& !dragState().m_dragSrc
) {
2130 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML
, dragState().m_dragSrcMayBeUA
);
2131 if (!dragState().m_dragSrcMayBeDHTML
&& !dragState().m_dragSrcMayBeUA
)
2132 m_mouseDownMayStartDrag
= false; // no element is draggable
2135 if (m_mouseDownMayStartDrag
&& !dragState().m_dragSrc
) {
2136 // try to find an element that wants to be dragged
2137 HitTestRequest
request(HitTestRequest::ReadOnly
);
2138 HitTestResult
result(m_mouseDownPos
);
2139 m_frame
->contentRenderer()->layer()->hitTest(request
, result
);
2140 Node
* node
= result
.innerNode();
2141 if (node
&& node
->renderer())
2142 dragState().m_dragSrc
= node
->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML
, dragState().m_dragSrcMayBeUA
,
2143 m_mouseDownPos
.x(), m_mouseDownPos
.y(), dragState().m_dragSrcIsDHTML
);
2145 dragState().m_dragSrc
= 0;
2147 if (!dragState().m_dragSrc
)
2148 m_mouseDownMayStartDrag
= false; // no element is draggable
2150 // remember some facts about this source, while we have a HitTestResult handy
2151 node
= result
.URLElement();
2152 dragState().m_dragSrcIsLink
= node
&& node
->isLink();
2154 node
= result
.innerNonSharedNode();
2155 dragState().m_dragSrcIsImage
= node
&& node
->renderer() && node
->renderer()->isImage();
2157 dragState().m_dragSrcInSelection
= m_frame
->selection()->contains(m_mouseDownPos
);
2161 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
2162 // or else we bail on the dragging stuff and allow selection to occur
2163 if (m_mouseDownMayStartDrag
&& !dragState().m_dragSrcIsImage
&& dragState().m_dragSrcInSelection
&& event
.event().timestamp() - m_mouseDownTimestamp
< TextDragDelay
) {
2164 m_mouseDownMayStartDrag
= false;
2165 dragState().m_dragSrc
= 0;
2166 // ...but if this was the first click in the window, we don't even want to start selection
2167 if (eventActivatedView(event
.event()))
2168 m_mouseDownMayStartSelect
= false;
2171 if (!m_mouseDownMayStartDrag
)
2172 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll
;
2174 // We are starting a text/image/url drag, so the cursor should be an arrow
2175 if (FrameView
* view
= m_frame
->view())
2176 view
->setCursor(pointerCursor());
2178 if (!dragHysteresisExceeded(event
.event().pos()))
2181 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2184 DragOperation srcOp
= DragOperationNone
;
2186 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
2187 // to make sure it gets numbified
2188 dragState().m_dragClipboard
= createDraggingClipboard();
2190 if (dragState().m_dragSrcMayBeDHTML
) {
2191 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
2193 if (dragState().m_dragSrcIsDHTML
) {
2194 if (RenderObject
* renderer
= dragState().m_dragSrc
->renderer()) {
2195 // FIXME: This doesn't work correctly with transforms.
2196 FloatPoint absPos
= renderer
->localToAbsolute();
2197 IntSize delta
= m_mouseDownPos
- roundedIntPoint(absPos
);
2198 dragState().m_dragClipboard
->setDragImageElement(dragState().m_dragSrc
.get(), IntPoint() + delta
);
2200 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
2201 // the element in some way. In this case we just kill the drag.
2202 m_mouseDownMayStartDrag
= false;
2207 m_mouseDownMayStartDrag
= dispatchDragSrcEvent(eventNames().dragstartEvent
, m_mouseDown
)
2208 && !m_frame
->selection()->isInPasswordField();
2210 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
2211 // image can still be changed as we drag, but not the pasteboard data.
2212 dragState().m_dragClipboard
->setAccessPolicy(ClipboardImageWritable
);
2214 if (m_mouseDownMayStartDrag
) {
2215 // gather values from DHTML element, if it set any
2216 dragState().m_dragClipboard
->sourceOperation(srcOp
);
2218 // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with
2219 // dragImage! Because of that dumb reentrancy, we may think we've not started the
2220 // drag when that happens. So we have to assume it's started before we kick it off.
2221 dragState().m_dragClipboard
->setDragHasStarted();
2225 if (m_mouseDownMayStartDrag
) {
2226 Page
* page
= m_frame
->page();
2227 DragController
* dragController
= page
? page
->dragController() : 0;
2228 bool startedDrag
= dragController
&& dragController
->startDrag(m_frame
, dragState().m_dragClipboard
.get(), srcOp
, event
.event(), m_mouseDownPos
, dragState().m_dragSrcIsDHTML
);
2229 if (!startedDrag
&& dragState().m_dragSrcMayBeDHTML
) {
2230 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
2231 dispatchDragSrcEvent(eventNames().dragendEvent
, event
.event());
2232 m_mouseDownMayStartDrag
= false;
2237 if (!m_mouseDownMayStartDrag
) {
2238 // something failed to start the drag, cleanup
2240 dragState().m_dragSrc
= 0;
2243 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2247 bool EventHandler::handleTextInputEvent(const String
& text
, Event
* underlyingEvent
, bool isLineBreak
, bool isBackTab
)
2249 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
2250 // and avoid dispatching text input events from keydown default handlers.
2251 ASSERT(!underlyingEvent
|| !underlyingEvent
->isKeyboardEvent() || static_cast<KeyboardEvent
*>(underlyingEvent
)->type() == eventNames().keypressEvent
);
2256 EventTarget
* target
;
2257 if (underlyingEvent
)
2258 target
= underlyingEvent
->target();
2260 target
= eventTargetNodeForDocument(m_frame
->document());
2264 if (FrameView
* view
= m_frame
->view())
2265 view
->resetDeferredRepaintDelay();
2267 RefPtr
<TextEvent
> event
= TextEvent::create(m_frame
->domWindow(), text
);
2268 event
->setUnderlyingEvent(underlyingEvent
);
2269 event
->setIsLineBreak(isLineBreak
);
2270 event
->setIsBackTab(isBackTab
);
2272 target
->dispatchEvent(event
, ec
);
2273 return event
->defaultHandled();
2277 #if !PLATFORM(MAC) && !PLATFORM(QT)
2278 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent
*) const
2284 bool EventHandler::tabsToLinks(KeyboardEvent
* event
) const
2286 Page
* page
= m_frame
->page();
2290 if (page
->chrome()->client()->tabsToLinks())
2291 return !invertSenseOfTabsToLinks(event
);
2293 return invertSenseOfTabsToLinks(event
);
2296 void EventHandler::defaultTextInputEventHandler(TextEvent
* event
)
2298 String data
= event
->data();
2300 if (event
->isLineBreak()) {
2301 if (m_frame
->editor()->insertLineBreak())
2302 event
->setDefaultHandled();
2304 if (m_frame
->editor()->insertParagraphSeparator())
2305 event
->setDefaultHandled();
2308 if (m_frame
->editor()->insertTextWithoutSendingTextEvent(data
, false, event
))
2309 event
->setDefaultHandled();
2313 #if PLATFORM(QT) || PLATFORM(MAC)
2315 // These two platforms handle the space event in the platform-specific WebKit code.
2316 // Eventually it would be good to eliminate that and use the code here instead, but
2317 // the Qt version is inside an ifdef and the Mac version has some extra behavior
2318 // so we can't unify everything yet.
2319 void EventHandler::defaultSpaceEventHandler(KeyboardEvent
*)
2325 void EventHandler::defaultSpaceEventHandler(KeyboardEvent
* event
)
2327 ScrollDirection direction
= event
->shiftKey() ? ScrollUp
: ScrollDown
;
2328 if (scrollOverflow(direction
, ScrollByPage
)) {
2329 event
->setDefaultHandled();
2333 FrameView
* view
= m_frame
->view();
2337 if (view
->scroll(direction
, ScrollByPage
))
2338 event
->setDefaultHandled();
2343 void EventHandler::defaultTabEventHandler(KeyboardEvent
* event
)
2345 // We should only advance focus on tabs if no special modifier keys are held down.
2346 if (event
->ctrlKey() || event
->metaKey() || event
->altGraphKey())
2349 Page
* page
= m_frame
->page();
2352 if (!page
->tabKeyCyclesThroughElements())
2355 FocusDirection focusDirection
= event
->shiftKey() ? FocusDirectionBackward
: FocusDirectionForward
;
2357 // Tabs can be used in design mode editing.
2358 if (m_frame
->document()->inDesignMode())
2361 if (page
->focusController()->advanceFocus(focusDirection
, event
))
2362 event
->setDefaultHandled();
2365 void EventHandler::capsLockStateMayHaveChanged()
2367 Document
* d
= m_frame
->document();
2368 if (Node
* node
= d
->focusedNode()) {
2369 if (RenderObject
* r
= node
->renderer()) {
2370 if (r
->isTextField())
2371 static_cast<RenderTextControlSingleLine
*>(r
)->capsLockStateMayHaveChanged();
2376 void EventHandler::sendResizeEvent()
2378 m_frame
->document()->dispatchWindowEvent(eventNames().resizeEvent
, false, false);
2381 void EventHandler::sendScrollEvent()
2383 FrameView
* v
= m_frame
->view();
2386 v
->setWasScrolledByUser(true);
2387 m_frame
->document()->dispatchEvent(eventNames().scrollEvent
, true, false);
2390 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults
& mev
, Scrollbar
* scrollbar
)
2392 if (!scrollbar
|| !scrollbar
->enabled())
2394 return scrollbar
->mouseDown(mev
.event());