Updated WebKit from /home/shausman/src/webkit/trunk to qtwebkit-4.6-snapshot-29062009...
[qt-netbsd.git] / src / 3rdparty / webkit / WebCore / page / EventHandler.cpp
blob8f0b420c79dd7971754631a4dc57a8766c534822
1 /*
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
7 * are met:
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.
27 #include "config.h"
28 #include "EventHandler.h"
30 #include "AXObjectCache.h"
31 #include "CachedImage.h"
32 #include "ChromeClient.h"
33 #include "Cursor.h"
34 #include "Document.h"
35 #include "DragController.h"
36 #include "Editor.h"
37 #include "EventNames.h"
38 #include "FloatPoint.h"
39 #include "FloatRect.h"
40 #include "FocusController.h"
41 #include "Frame.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"
51 #include "Image.h"
52 #include "InspectorController.h"
53 #include "KeyboardEvent.h"
54 #include "MouseEvent.h"
55 #include "MouseEventWithHitTestResults.h"
56 #include "Page.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"
65 #include "Settings.h"
66 #include "TextEvent.h"
67 #include "htmlediting.h" // for comparePositions()
68 #include <wtf/StdLibExtras.h>
70 #if ENABLE(SVG)
71 #include "SVGDocument.h"
72 #include "SVGElementInstance.h"
73 #include "SVGNames.h"
74 #include "SVGUseElement.h"
75 #endif
77 namespace WebCore {
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;
93 #if ENABLE(SVG)
94 using namespace SVGNames;
95 #endif
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)
105 if (!delta)
106 return;
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))
113 e.accept();
114 return;
116 float pixelsToScroll = delta > 0 ? delta : -delta;
117 if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll))
118 e.accept();
121 #if !PLATFORM(MAC)
123 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
125 return false;
128 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
130 return false;
133 #endif
135 EventHandler::EventHandler(Frame* frame)
136 : m_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)
150 #if ENABLE(SVG)
151 , m_svgPan(false)
152 #endif
153 , m_resizeLayer(0)
154 , m_capturingMouseEventsNode(0)
155 , m_clickCount(0)
156 , m_mouseDownTimestamp(0)
157 #if PLATFORM(MAC)
158 , m_mouseDownView(nil)
159 , m_sendingEventToSubview(false)
160 , m_activationEventNumber(0)
161 #endif
165 EventHandler::~EventHandler()
169 EventHandler::EventHandlerDragState& EventHandler::dragState()
171 DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
172 return state;
175 void EventHandler::clear()
177 m_hoverTimer.stop();
178 m_resizeLayer = 0;
179 m_nodeUnderMouse = 0;
180 m_lastNodeUnderMouse = 0;
181 #if ENABLE(SVG)
182 m_instanceUnderMouse = 0;
183 m_lastInstanceUnderMouse = 0;
184 #endif
185 m_lastMouseMoveEventSubframe = 0;
186 m_lastScrollbarUnderMouse = 0;
187 m_clickCount = 0;
188 m_clickNode = 0;
189 m_frameSetBeingResized = 0;
190 m_dragTarget = 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)
249 return false;
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;
258 else
259 selectClosestWordFromMouseEvent(event);
261 return true;
264 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
266 if (event.event().button() != LeftButton)
267 return false;
269 Node* innerNode = event.targetNode();
270 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
271 return false;
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);
287 return true;
290 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
292 Node* innerNode = event.targetNode();
293 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
294 return false;
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;
305 return false;
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);
324 else
325 newSelection = VisibleSelection(start, pos);
327 if (m_frame->selectionGranularity() != CharacterGranularity)
328 newSelection.expandUsingGranularity(m_frame->selectionGranularity());
329 m_beganSelectingText = true;
330 } else {
331 newSelection = VisibleSelection(visiblePos);
332 m_frame->setSelectionGranularity(CharacterGranularity);
335 if (m_frame->shouldChangeSelection(newSelection))
336 m_frame->selection()->setSelection(newSelection);
338 return true;
341 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
343 // Reset drag state.
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))
360 return true;
362 #if ENABLE(SVG)
363 if (m_frame->document()->isSVGDocument() &&
364 static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
365 if (event.event().shiftKey() && singleClick) {
366 m_svgPan = true;
367 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
368 return true;
371 #endif
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.
375 if (singleClick)
376 focusDocumentView();
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);
392 else
393 swallowEvent = handleMousePressEventSingleClick(event);
395 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect ||
396 (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
398 return swallowEvent;
401 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
403 if (handleDrag(event))
404 return true;
406 if (!m_mousePressed)
407 return false;
409 Node* targetNode = event.targetNode();
410 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
411 return false;
413 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
414 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
415 #endif
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();
426 else
427 renderer = renderer->parent();
430 if (renderer) {
431 m_autoscrollInProgress = true;
432 handleAutoscroll(renderer);
435 m_mouseDownMayStartAutoscroll = false;
438 updateSelectionForMouseDrag(targetNode, event.localPoint());
439 return true;
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())
449 return false;
451 if (event.button() != LeftButton || event.clickCount() != 1)
452 return false;
454 bool DHTMLFlag;
455 bool UAFlag;
456 allowDHTMLDrag(DHTMLFlag, UAFlag);
457 if (!DHTMLFlag && !UAFlag)
458 return false;
460 FrameView* view = m_frame->view();
461 if (!view)
462 return false;
464 HitTestRequest request(HitTestRequest::ReadOnly);
465 HitTestResult result(view->windowToContents(event.pos()));
466 m_frame->contentRenderer()->layer()->hitTest(request, result);
467 bool srcIsDHTML;
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();
474 if (!view)
475 return;
476 RenderView* renderer = m_frame->contentRenderer();
477 if (!renderer)
478 return;
479 RenderLayer* layer = renderer->layer();
480 if (!layer)
481 return;
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)
494 return;
496 if (!targetNode)
497 return;
499 RenderObject* targetRenderer = targetNode->renderer();
500 if (!targetRenderer)
501 return;
503 if (!canMouseDragExtendSelect(targetNode))
504 return;
506 VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint));
508 // Don't modify the selection if we're not on a node.
509 if (targetPosition.isNull())
510 return;
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();
516 #if ENABLE(SVG)
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())
523 return;
524 #endif
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))
544 return true;
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))
560 return true;
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);
592 handled = true;
595 m_frame->notifyRendererOfSelectionChange(true);
597 m_frame->selection()->selectFrameElementInParentIfFullySelected();
599 return handled;
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())
606 return;
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);
622 #endif
624 startAutoscrollTimer();
627 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
629 RenderObject* r = autoscrollRenderer();
630 if (!r || !r->isBox()) {
631 stopAutoscrollTimer();
632 return;
635 if (m_autoscrollInProgress) {
636 if (!m_mousePressed) {
637 stopAutoscrollTimer();
638 return;
640 toRenderBox(r)->autoscroll();
641 } else {
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();
646 return;
649 #if ENABLE(PAN_SCROLLING)
650 setPanScrollCursor();
651 toRenderBox(r)->panScroll(m_panScrollStartPos);
652 #endif
656 #if ENABLE(PAN_SCROLLING)
658 void EventHandler::setPanScrollCursor()
660 FrameView* view = m_frame->view();
661 if (!view)
662 return;
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);
671 if (north) {
672 if (east)
673 view->setCursor(northEastPanningCursor());
674 else if (west)
675 view->setCursor(northWestPanningCursor());
676 else
677 view->setCursor(northPanningCursor());
678 } else if (south) {
679 if (east)
680 view->setCursor(southEastPanningCursor());
681 else if (west)
682 view->setCursor(southWestPanningCursor());
683 else
684 view->setCursor(southPanningCursor());
685 } else if (east)
686 view->setCursor(eastPanningCursor());
687 else if (west)
688 view->setCursor(westPanningCursor());
689 else
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)
703 return;
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
721 flagDHTML = false;
722 flagUA = false;
724 if (!m_frame)
725 return;
727 Page* page = m_frame->page();
728 if (!page)
729 return;
731 FrameView* view = m_frame->view();
732 if (!view)
733 return;
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())
744 return result;
745 int hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
746 if (ignoreClipping)
747 hitType |= HitTestRequest::IgnoreClipping;
748 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
750 while (true) {
751 Node* n = result.innerNode();
752 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
753 break;
754 RenderWidget* renderWidget = static_cast<RenderWidget*>(n->renderer());
755 Widget* widget = renderWidget->widget();
756 if (!widget || !widget->isFrameView())
757 break;
758 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
759 if (!frame || !frame->contentRenderer())
760 break;
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);
770 if (eventScrollbar)
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();
794 return result;
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);
809 return;
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());
823 #endif
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();
855 if (!node)
856 node = m_mousePressNode.get();
858 if (node) {
859 RenderObject* r = node->renderer();
860 if (r && !r->isListBox())
861 return r->enclosingBox()->scroll(direction, granularity);
864 return false;
867 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity)
869 bool handled = scrollOverflow(direction, granularity);
870 if (!handled) {
871 Frame* frame = m_frame;
872 do {
873 FrameView* view = frame->view();
874 handled = view ? view->scroll(direction, granularity) : false;
875 frame = frame->tree()->parent();
876 } while (!handled && frame);
879 return handled;
882 IntPoint EventHandler::currentMousePosition() const
884 return m_currentMousePosition;
887 Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
889 if (!hitTestResult.isOverWidget())
890 return 0;
891 return subframeForTargetNode(hitTestResult.targetNode());
894 Frame* subframeForTargetNode(Node* node)
896 if (!node)
897 return 0;
899 RenderObject* renderer = node->renderer();
900 if (!renderer || !renderer->isWidget())
901 return 0;
903 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
904 if (!widget || !widget->isFrameView())
905 return 0;
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;
946 if (!cimage)
947 continue;
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)
951 continue;
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())
954 continue;
955 if (cimage->image()->isNull())
956 break;
957 if (!cimage->errorOccurred())
958 return Cursor(cimage->image(), hotSpot);
962 switch (style ? style->cursor() : CURSOR_AUTO) {
963 case 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
968 if (editable) {
969 ASSERT(m_frame->settings());
970 switch(m_frame->settings()->editableLinkBehavior()) {
971 default:
972 case EditableLinkDefaultBehavior:
973 case EditableLinkAlwaysLive:
974 editableLinkEnabled = true;
975 break;
977 case EditableLinkNeverLive:
978 editableLinkEnabled = false;
979 break;
981 case EditableLinkLiveWhenNotFocused:
982 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
983 break;
985 case EditableLinkOnlyLiveWithShiftKey:
986 editableLinkEnabled = event.event().shiftKey();
987 break;
991 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
992 return handCursor();
993 bool inResizer = false;
994 if (renderer) {
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();
1004 case CURSOR_CROSS:
1005 return crossCursor();
1006 case CURSOR_POINTER:
1007 return handCursor();
1008 case CURSOR_MOVE:
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();
1040 case CURSOR_TEXT:
1041 return iBeamCursor();
1042 case CURSOR_WAIT:
1043 return waitCursor();
1044 case CURSOR_HELP:
1045 return helpCursor();
1046 case CURSOR_VERTICAL_TEXT:
1047 return verticalTextCursor();
1048 case CURSOR_CELL:
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();
1056 case CURSOR_ALIAS:
1057 return aliasCursor();
1058 case CURSOR_COPY:
1059 return copyCursor();
1060 case CURSOR_NONE:
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());
1099 else {
1100 invalidateClick();
1101 return false;
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()) {
1112 invalidateClick();
1113 return false;
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());
1122 invalidateClick();
1123 return true;
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();
1134 invalidateClick();
1135 return true;
1138 #if ENABLE(PAN_SCROLLING)
1139 Page* page = m_frame->page();
1140 if (page && page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
1141 stopAutoscrollTimer();
1142 invalidateClick();
1143 return true;
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();
1152 else
1153 renderer = renderer->parent();
1156 if (renderer) {
1157 m_panScrollInProgress = true;
1158 handleAutoscroll(renderer);
1159 invalidateClick();
1160 return true;
1163 #endif
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);
1175 invalidateClick();
1176 return true;
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;
1193 if (swallowEvent) {
1194 // scrollbars should get events anyway, even disabled controls might be scrollable
1195 if (mev.scrollbar())
1196 passMousePressEventToScrollbar(mev, mev.scrollbar());
1197 } else {
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;
1209 if (!scrollbar)
1210 scrollbar = mev.scrollbar();
1211 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1212 swallowEvent = true;
1213 else
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;
1234 return true;
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);
1252 invalidateClick();
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();
1263 if (!page)
1264 return result;
1266 hoveredNode.setToNonShadowAncestor();
1267 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1268 page->chrome()->setToolTip(hoveredNode);
1269 return result;
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.
1278 ASSERT(m_frame);
1279 if (!m_frame)
1280 return false;
1282 RefPtr<FrameView> protector(m_frame->view());
1283 m_currentMousePosition = mouseEvent.pos();
1285 if (m_hoverTimer.isActive())
1286 m_hoverTimer.stop();
1288 #if ENABLE(SVG)
1289 if (m_svgPan) {
1290 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1291 return true;
1293 #endif
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;
1309 if (m_mousePressed)
1310 hitType |= HitTestRequest::Active;
1311 HitTestRequest request(hitType);
1312 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1313 if (hoveredNode)
1314 *hoveredNode = mev.hitTestResult();
1316 Scrollbar* scrollbar = 0;
1318 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1319 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1320 else {
1321 if (FrameView* view = m_frame->view())
1322 scrollbar = view->scrollbarUnderPoint(mouseEvent.pos());
1324 if (!scrollbar)
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());
1342 if (newSubframe) {
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);
1350 } else {
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;
1363 if (swallowEvent)
1364 return true;
1366 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
1367 if (!swallowEvent)
1368 swallowEvent = handleMouseDraggedEvent(mev);
1370 return swallowEvent;
1373 void EventHandler::invalidateClick()
1375 m_clickCount = 0;
1376 m_clickNode = 0;
1379 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1381 RefPtr<FrameView> protector(m_frame->view());
1383 m_mousePressed = false;
1384 m_currentMousePosition = mouseEvent.pos();
1386 #if ENABLE(SVG)
1387 if (m_svgPan) {
1388 m_svgPan = false;
1389 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1390 return true;
1392 #endif
1394 if (m_frameSetBeingResized)
1395 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1397 if (m_lastScrollbarUnderMouse) {
1398 invalidateClick();
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;
1407 return true;
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);
1419 m_resizeLayer = 0;
1422 bool swallowMouseReleaseEvent = false;
1423 if (!swallowMouseUpEvent)
1424 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1426 invalidateClick();
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.
1436 if (!view)
1437 return false;
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(),
1446 0, 0, clipboard);
1448 ExceptionCode ec;
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())
1458 return false;
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();
1467 if (newTarget)
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.
1474 if (newTarget) {
1475 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
1476 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
1477 else
1478 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
1481 if (m_dragTarget) {
1482 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1483 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1484 if (frame)
1485 accept = frame->eventHandler()->updateDragAndDrop(event, clipboard);
1486 else
1487 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1489 } else {
1490 if (newTarget) {
1491 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
1492 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
1493 else
1494 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
1497 m_dragTarget = newTarget;
1499 return accept;
1502 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1504 if (m_dragTarget) {
1505 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1506 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1507 if (frame)
1508 frame->eventHandler()->cancelDragAndDrop(event, clipboard);
1509 else
1510 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1512 clearDragState();
1515 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1517 bool accept = false;
1518 if (m_dragTarget) {
1519 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1520 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1521 if (frame)
1522 accept = frame->eventHandler()->performDragAndDrop(event, clipboard);
1523 else
1524 accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
1526 clearDragState();
1527 return accept;
1530 void EventHandler::clearDragState()
1532 m_dragTarget = 0;
1533 m_capturingMouseEventsNode = 0;
1534 #if PLATFORM(MAC)
1535 m_sendingEventToSubview = false;
1536 #endif
1539 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1541 m_capturingMouseEventsNode = n;
1544 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1546 ASSERT(m_frame);
1547 ASSERT(m_frame->document());
1549 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
1552 #if ENABLE(SVG)
1553 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1555 if (!referenceNode || !referenceNode->isSVGElement())
1556 return 0;
1558 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
1559 if (!shadowTreeElement)
1560 return 0;
1562 Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode();
1563 if (!shadowTreeParentElement)
1564 return 0;
1566 ASSERT(shadowTreeParentElement->hasTagName(useTag));
1567 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1569 #endif
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();
1578 else {
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();
1582 if (result)
1583 result = result->shadowAncestorNode();
1585 m_nodeUnderMouse = result;
1586 #if ENABLE(SVG)
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)
1604 continue;
1606 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1607 continue;
1609 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1610 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1611 continue;
1613 m_lastNodeUnderMouse = shadowTreeElement;
1614 m_lastInstanceUnderMouse = instance;
1615 break;
1619 #endif
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;
1626 #if ENABLE(SVG)
1627 m_lastInstanceUnderMouse = 0;
1628 #endif
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;
1640 #if ENABLE(SVG)
1641 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
1642 #endif
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.
1667 while (renderer) {
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()))
1679 return false;
1681 break;
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();
1708 if (!docRenderer)
1709 return false;
1711 RefPtr<FrameView> protector(m_frame->view());
1713 FrameView* view = m_frame->view();
1714 if (!view)
1715 return false;
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();
1723 if (node) {
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)) {
1731 e.accept();
1732 return true;
1736 node = node->shadowAncestorNode();
1737 node->dispatchWheelEvent(e);
1738 if (e.isAccepted())
1739 return true;
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);
1754 if (e.isAccepted())
1755 return true;
1757 view = m_frame->view();
1758 if (!view)
1759 return false;
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();
1769 if (!v)
1770 return false;
1772 bool swallowEvent;
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);
1789 #endif
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())
1806 return true;
1808 // Some controls and images can't start a select on a mouse down.
1809 if (!node->canStartSelection())
1810 return false;
1812 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
1813 if (Node* node = curr->node())
1814 return node->dispatchEvent(eventNames().selectstartEvent, true, true);
1817 return true;
1820 bool EventHandler::canMouseDragExtendSelect(Node* node)
1822 if (!node || !node->renderer())
1823 return true;
1825 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
1826 if (Node* node = curr->node())
1827 return node->dispatchEvent(eventNames().selectstartEvent, true, true);
1830 return true;
1833 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1835 m_frameSetBeingResized = frameSet;
1838 void EventHandler::resizeLayerDestroyed()
1840 ASSERT(m_resizeLayer);
1841 m_resizeLayer = 0;
1844 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
1846 m_hoverTimer.stop();
1848 ASSERT(m_frame);
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)
1863 if (!doc)
1864 return 0;
1865 Node* node = doc->focusedNode();
1866 if (!node && doc->isHTMLDocument())
1867 node = doc->body();
1868 if (!node)
1869 node = doc->documentElement();
1870 return node;
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())
1881 return false;
1882 String key = evt.unmodifiedText();
1883 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
1884 if (!elem)
1885 return false;
1886 elem->accessKeyAction(false);
1887 return true;
1890 #if !PLATFORM(MAC)
1891 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
1893 return false;
1895 #endif
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
1909 return true;
1912 #endif
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());
1917 if (!node)
1918 return false;
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();
1941 ExceptionCode ec;
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());
1980 if (!node)
1981 return false;
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);
1990 if (keydownResult)
1991 keypress->setDefaultPrevented(true);
1992 #if PLATFORM(MAC)
1993 keypress->keypressCommands() = keydown->keypressCommands();
1994 #endif
1995 node->dispatchEvent(keypress, ec);
1997 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2000 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
2002 if (!event)
2003 return;
2005 String key = event->keyIdentifier();
2006 bool isShifted = event->getModifierState("Shift");
2007 bool isOptioned = event->getModifierState("Alt");
2008 bool isCommanded = event->getModifierState("Meta");
2010 if (key == "Up") {
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())
2033 return;
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())
2044 return;
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();
2059 if (!view)
2060 return false;
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())
2084 return false;
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);
2103 freeClipboard();
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;
2121 return false;
2124 if (eventLoopHandleMouseDragged(event))
2125 return true;
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);
2144 else
2145 dragState().m_dragSrc = 0;
2147 if (!dragState().m_dragSrc)
2148 m_mouseDownMayStartDrag = false; // no element is draggable
2149 else {
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()))
2179 return true;
2181 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2182 invalidateClick();
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
2192 // image and offset
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);
2199 } else {
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;
2203 goto cleanupDrag;
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;
2236 cleanupDrag:
2237 if (!m_mouseDownMayStartDrag) {
2238 // something failed to start the drag, cleanup
2239 freeClipboard();
2240 dragState().m_dragSrc = 0;
2243 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2244 return true;
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);
2253 if (!m_frame)
2254 return false;
2256 EventTarget* target;
2257 if (underlyingEvent)
2258 target = underlyingEvent->target();
2259 else
2260 target = eventTargetNodeForDocument(m_frame->document());
2261 if (!target)
2262 return false;
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);
2271 ExceptionCode ec;
2272 target->dispatchEvent(event, ec);
2273 return event->defaultHandled();
2277 #if !PLATFORM(MAC) && !PLATFORM(QT)
2278 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const
2280 return false;
2282 #endif
2284 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
2286 Page* page = m_frame->page();
2287 if (!page)
2288 return false;
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();
2299 if (data == "\n") {
2300 if (event->isLineBreak()) {
2301 if (m_frame->editor()->insertLineBreak())
2302 event->setDefaultHandled();
2303 } else {
2304 if (m_frame->editor()->insertParagraphSeparator())
2305 event->setDefaultHandled();
2307 } else {
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*)
2323 #else
2325 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
2327 ScrollDirection direction = event->shiftKey() ? ScrollUp : ScrollDown;
2328 if (scrollOverflow(direction, ScrollByPage)) {
2329 event->setDefaultHandled();
2330 return;
2333 FrameView* view = m_frame->view();
2334 if (!view)
2335 return;
2337 if (view->scroll(direction, ScrollByPage))
2338 event->setDefaultHandled();
2341 #endif
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())
2347 return;
2349 Page* page = m_frame->page();
2350 if (!page)
2351 return;
2352 if (!page->tabKeyCyclesThroughElements())
2353 return;
2355 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
2357 // Tabs can be used in design mode editing.
2358 if (m_frame->document()->inDesignMode())
2359 return;
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();
2384 if (!v)
2385 return;
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())
2393 return false;
2394 return scrollbar->mouseDown(mev.event());