1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 *
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.
13 *
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.
25 */
26
27 #include "config.h"
28 #include "EventHandler.h"
29
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>
69
70 #if ENABLE(SVG)
71 #include "SVGDocument.h"
72 #include "SVGElementInstance.h"
73 #include "SVGNames.h"
74 #include "SVGUseElement.h"
75 #endif
76
77 #if ENABLE(TOUCH_EVENTS) // Android
78 #include "TouchEvent.h"
79 #include "PlatformTouchEvent.h"
80 #endif
81
82 #if defined(ANDROID_PLUGINS)
83 #include "WebViewCore.h"
84 #endif
85
86 namespace WebCore {
87
88 using namespace HTMLNames;
89
90 // The link drag hysteresis is much larger than the others because there
91 // needs to be enough space to cancel the link press without starting a link drag,
92 // and because dragging links is rare.
93 const int LinkDragHysteresis = 40;
94 const int ImageDragHysteresis = 5;
95 const int TextDragHysteresis = 3;
96 const int GeneralDragHysteresis = 3;
97
98 // Match key code of composition keydown event on windows.
99 // IE sends VK_PROCESSKEY which has value 229;
100 const int CompositionEventKeyCode = 229;
101
102 #if ENABLE(SVG)
103 using namespace SVGNames;
104 #endif
105
106 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
107 const double autoscrollInterval = 0.05;
108
109 static Frame* subframeForTargetNode(Node*);
110 static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
111
scrollAndAcceptEvent(float delta,ScrollDirection positiveDirection,ScrollDirection negativeDirection,PlatformWheelEvent & e,Node * node)112 static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node)
113 {
114 if (!delta)
115 return;
116
117 // Find the nearest enclosing box.
118 RenderBox* enclosingBox = node->renderer()->enclosingBox();
119
120 if (e.granularity() == ScrollByPageWheelEvent) {
121 if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1))
122 e.accept();
123 return;
124 }
125 float pixelsToScroll = delta > 0 ? delta : -delta;
126 if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll))
127 e.accept();
128 }
129
130 #if !PLATFORM(MAC)
131
eventLoopHandleMouseUp(const MouseEventWithHitTestResults &)132 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
133 {
134 return false;
135 }
136
eventLoopHandleMouseDragged(const MouseEventWithHitTestResults &)137 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
138 {
139 return false;
140 }
141
142 #endif
143
EventHandler(Frame * frame)144 EventHandler::EventHandler(Frame* frame)
145 : m_frame(frame)
146 , m_mousePressed(false)
147 , m_capturesDragging(false)
148 , m_mouseDownMayStartSelect(false)
149 , m_mouseDownMayStartDrag(false)
150 , m_mouseDownWasSingleClickInSelection(false)
151 , m_beganSelectingText(false)
152 , m_panScrollInProgress(false)
153 , m_panScrollButtonPressed(false)
154 , m_springLoadedPanScrollInProgress(false)
155 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
156 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
157 , m_autoscrollRenderer(0)
158 , m_autoscrollInProgress(false)
159 , m_mouseDownMayStartAutoscroll(false)
160 , m_mouseDownWasInSubframe(false)
161 #if ENABLE(SVG)
162 , m_svgPan(false)
163 #endif
164 , m_resizeLayer(0)
165 , m_capturingMouseEventsNode(0)
166 , m_clickCount(0)
167 , m_mouseDownTimestamp(0)
168 , m_useLatchedWheelEventNode(false)
169 , m_widgetIsLatched(false)
170 #if PLATFORM(MAC)
171 , m_mouseDownView(nil)
172 , m_sendingEventToSubview(false)
173 , m_activationEventNumber(0)
174 #endif
175 {
176 }
177
~EventHandler()178 EventHandler::~EventHandler()
179 {
180 }
181
dragState()182 EventHandler::EventHandlerDragState& EventHandler::dragState()
183 {
184 DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
185 return state;
186 }
187
clear()188 void EventHandler::clear()
189 {
190 m_hoverTimer.stop();
191 m_resizeLayer = 0;
192 m_nodeUnderMouse = 0;
193 m_lastNodeUnderMouse = 0;
194 #if ENABLE(SVG)
195 m_instanceUnderMouse = 0;
196 m_lastInstanceUnderMouse = 0;
197 #endif
198 m_lastMouseMoveEventSubframe = 0;
199 m_lastScrollbarUnderMouse = 0;
200 m_clickCount = 0;
201 m_clickNode = 0;
202 #if ENABLE(TOUCH_EVENTS) // Android
203 m_touch = 0;
204 #endif
205 m_frameSetBeingResized = 0;
206 m_dragTarget = 0;
207 m_currentMousePosition = IntPoint();
208 m_mousePressNode = 0;
209 m_mousePressed = false;
210 m_capturesDragging = false;
211 m_capturingMouseEventsNode = 0;
212 m_latchedWheelEventNode = 0;
213 }
214
selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults & result)215 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
216 {
217 Node* innerNode = result.targetNode();
218 VisibleSelection newSelection;
219
220 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
221 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
222 if (pos.isNotNull()) {
223 newSelection = VisibleSelection(pos);
224 newSelection.expandUsingGranularity(WordGranularity);
225 }
226
227 if (newSelection.isRange()) {
228 m_frame->setSelectionGranularity(WordGranularity);
229 m_beganSelectingText = true;
230 if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
231 newSelection.appendTrailingWhitespace();
232 }
233
234 if (m_frame->shouldChangeSelection(newSelection))
235 m_frame->selection()->setSelection(newSelection);
236 }
237 }
238
selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults & result)239 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
240 {
241 if (!result.hitTestResult().isLiveLink())
242 return selectClosestWordFromMouseEvent(result);
243
244 Node* innerNode = result.targetNode();
245
246 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
247 VisibleSelection newSelection;
248 Element* URLElement = result.hitTestResult().URLElement();
249 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
250 if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement))
251 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
252
253 if (newSelection.isRange()) {
254 m_frame->setSelectionGranularity(WordGranularity);
255 m_beganSelectingText = true;
256 }
257
258 if (m_frame->shouldChangeSelection(newSelection))
259 m_frame->selection()->setSelection(newSelection);
260 }
261 }
262
handleMousePressEventDoubleClick(const MouseEventWithHitTestResults & event)263 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
264 {
265 if (event.event().button() != LeftButton)
266 return false;
267
268 if (m_frame->selection()->isRange())
269 // A double-click when range is already selected
270 // should not change the selection. So, do not call
271 // selectClosestWordFromMouseEvent, but do set
272 // m_beganSelectingText to prevent handleMouseReleaseEvent
273 // from setting caret selection.
274 m_beganSelectingText = true;
275 else
276 selectClosestWordFromMouseEvent(event);
277
278 return true;
279 }
280
handleMousePressEventTripleClick(const MouseEventWithHitTestResults & event)281 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
282 {
283 if (event.event().button() != LeftButton)
284 return false;
285
286 Node* innerNode = event.targetNode();
287 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
288 return false;
289
290 VisibleSelection newSelection;
291 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
292 if (pos.isNotNull()) {
293 newSelection = VisibleSelection(pos);
294 newSelection.expandUsingGranularity(ParagraphGranularity);
295 }
296 if (newSelection.isRange()) {
297 m_frame->setSelectionGranularity(ParagraphGranularity);
298 m_beganSelectingText = true;
299 }
300
301 if (m_frame->shouldChangeSelection(newSelection))
302 m_frame->selection()->setSelection(newSelection);
303
304 return true;
305 }
306
handleMousePressEventSingleClick(const MouseEventWithHitTestResults & event)307 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
308 {
309 Node* innerNode = event.targetNode();
310 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
311 return false;
312
313 // Extend the selection if the Shift key is down, unless the click is in a link.
314 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
315
316 // Don't restart the selection when the mouse is pressed on an
317 // existing selection so we can allow for text dragging.
318 if (FrameView* view = m_frame->view()) {
319 IntPoint vPoint = view->windowToContents(event.event().pos());
320 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
321 m_mouseDownWasSingleClickInSelection = true;
322 return false;
323 }
324 }
325
326 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
327 if (visiblePos.isNull())
328 visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM);
329 Position pos = visiblePos.deepEquivalent();
330
331 VisibleSelection newSelection = m_frame->selection()->selection();
332 if (extendSelection && newSelection.isCaretOrRange()) {
333 m_frame->selection()->setLastChangeWasHorizontalExtension(false);
334
335 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
336 // was created right-to-left
337 Position start = newSelection.start();
338 Position end = newSelection.end();
339 if (comparePositions(pos, start) <= 0)
340 newSelection = VisibleSelection(pos, end);
341 else
342 newSelection = VisibleSelection(start, pos);
343
344 if (m_frame->selectionGranularity() != CharacterGranularity)
345 newSelection.expandUsingGranularity(m_frame->selectionGranularity());
346 m_beganSelectingText = true;
347 } else {
348 newSelection = VisibleSelection(visiblePos);
349 m_frame->setSelectionGranularity(CharacterGranularity);
350 }
351
352 if (m_frame->shouldChangeSelection(newSelection))
353 m_frame->selection()->setSelection(newSelection);
354
355 return true;
356 }
357
handleMousePressEvent(const MouseEventWithHitTestResults & event)358 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
359 {
360 // Reset drag state.
361 dragState().m_dragSrc = 0;
362
363 if (ScrollView* scrollView = m_frame->view()) {
364 if (scrollView->isPointInScrollbarCorner(event.event().pos()))
365 return false;
366 }
367
368 bool singleClick = event.event().clickCount() <= 1;
369
370 // If we got the event back, that must mean it wasn't prevented,
371 // so it's allowed to start a drag or selection.
372 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode());
373
374 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
375 m_mouseDownMayStartDrag = singleClick;
376
377 m_mouseDownWasSingleClickInSelection = false;
378
379 m_mouseDown = event.event();
380
381 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
382 return true;
383
384 #if ENABLE(SVG)
385 if (m_frame->document()->isSVGDocument() &&
386 static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
387 if (event.event().shiftKey() && singleClick) {
388 m_svgPan = true;
389 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
390 return true;
391 }
392 }
393 #endif
394
395 // We don't do this at the start of mouse down handling,
396 // because we don't want to do it until we know we didn't hit a widget.
397 if (singleClick)
398 focusDocumentView();
399
400 Node* innerNode = event.targetNode();
401
402 m_mousePressNode = innerNode;
403 m_dragStartPos = event.event().pos();
404
405 bool swallowEvent = false;
406 m_frame->selection()->setCaretBlinkingSuspended(true);
407 m_mousePressed = true;
408 m_beganSelectingText = false;
409
410 if (event.event().clickCount() == 2)
411 swallowEvent = handleMousePressEventDoubleClick(event);
412 else if (event.event().clickCount() >= 3)
413 swallowEvent = handleMousePressEventTripleClick(event);
414 else
415 swallowEvent = handleMousePressEventSingleClick(event);
416
417 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect ||
418 (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
419
420 return swallowEvent;
421 }
422
handleMouseDraggedEvent(const MouseEventWithHitTestResults & event)423 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
424 {
425 if (handleDrag(event))
426 return true;
427
428 if (!m_mousePressed)
429 return false;
430
431 Node* targetNode = event.targetNode();
432 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
433 return false;
434
435 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
436 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
437 #endif
438
439 m_mouseDownMayStartDrag = false;
440
441 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
442 // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
443 // Otherwise, let the bridge handle it so the view can scroll itself.
444 RenderObject* renderer = targetNode->renderer();
445 while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) {
446 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
447 renderer = renderer->document()->ownerElement()->renderer();
448 else
449 renderer = renderer->parent();
450 }
451
452 if (renderer) {
453 m_autoscrollInProgress = true;
454 handleAutoscroll(renderer);
455 }
456
457 m_mouseDownMayStartAutoscroll = false;
458 }
459
460 updateSelectionForMouseDrag(targetNode, event.localPoint());
461 return true;
462 }
463
eventMayStartDrag(const PlatformMouseEvent & event) const464 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
465 {
466 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
467 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
468 // in handleMousePressEvent
469
470 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
471 return false;
472
473 if (event.button() != LeftButton || event.clickCount() != 1)
474 return false;
475
476 bool DHTMLFlag;
477 bool UAFlag;
478 allowDHTMLDrag(DHTMLFlag, UAFlag);
479 if (!DHTMLFlag && !UAFlag)
480 return false;
481
482 FrameView* view = m_frame->view();
483 if (!view)
484 return false;
485
486 HitTestRequest request(HitTestRequest::ReadOnly);
487 HitTestResult result(view->windowToContents(event.pos()));
488 m_frame->contentRenderer()->layer()->hitTest(request, result);
489 bool srcIsDHTML;
490 return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
491 }
492
updateSelectionForMouseDrag()493 void EventHandler::updateSelectionForMouseDrag()
494 {
495 FrameView* view = m_frame->view();
496 if (!view)
497 return;
498 RenderView* renderer = m_frame->contentRenderer();
499 if (!renderer)
500 return;
501 RenderLayer* layer = renderer->layer();
502 if (!layer)
503 return;
504
505 HitTestRequest request(HitTestRequest::ReadOnly |
506 HitTestRequest::Active |
507 HitTestRequest::MouseMove);
508 HitTestResult result(view->windowToContents(m_currentMousePosition));
509 layer->hitTest(request, result);
510 updateSelectionForMouseDrag(result.innerNode(), result.localPoint());
511 }
512
updateSelectionForMouseDrag(Node * targetNode,const IntPoint & localPoint)513 void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint)
514 {
515 if (!m_mouseDownMayStartSelect)
516 return;
517
518 if (!targetNode)
519 return;
520
521 RenderObject* targetRenderer = targetNode->renderer();
522 if (!targetRenderer)
523 return;
524
525 if (!canMouseDragExtendSelect(targetNode))
526 return;
527
528 VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint));
529
530 // Don't modify the selection if we're not on a node.
531 if (targetPosition.isNull())
532 return;
533
534 // Restart the selection if this is the first mouse move. This work is usually
535 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
536 VisibleSelection newSelection = m_frame->selection()->selection();
537
538 #if ENABLE(SVG)
539 // Special case to limit selection to the containing block for SVG text.
540 // FIXME: Isn't there a better non-SVG-specific way to do this?
541 if (Node* selectionBaseNode = newSelection.base().node())
542 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
543 if (selectionBaseRenderer->isSVGText())
544 if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
545 return;
546 #endif
547
548 if (!m_beganSelectingText) {
549 m_beganSelectingText = true;
550 newSelection = VisibleSelection(targetPosition);
551 }
552
553 newSelection.setExtent(targetPosition);
554 if (m_frame->selectionGranularity() != CharacterGranularity)
555 newSelection.expandUsingGranularity(m_frame->selectionGranularity());
556
557 if (m_frame->shouldChangeSelection(newSelection)) {
558 m_frame->selection()->setLastChangeWasHorizontalExtension(false);
559 m_frame->selection()->setSelection(newSelection);
560 }
561 }
562
handleMouseUp(const MouseEventWithHitTestResults & event)563 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
564 {
565 if (eventLoopHandleMouseUp(event))
566 return true;
567
568 // If this was the first click in the window, we don't even want to clear the selection.
569 // This case occurs when the user clicks on a draggable element, since we have to process
570 // the mouse down and drag events to see if we might start a drag. For other first clicks
571 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
572 // ignored upstream of this layer.
573 return eventActivatedView(event.event());
574 }
575
handleMouseReleaseEvent(const MouseEventWithHitTestResults & event)576 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
577 {
578 if (m_autoscrollInProgress)
579 stopAutoscrollTimer();
580
581 if (handleMouseUp(event))
582 return true;
583
584 // Used to prevent mouseMoveEvent from initiating a drag before
585 // the mouse is pressed again.
586 m_frame->selection()->setCaretBlinkingSuspended(false);
587 m_mousePressed = false;
588 m_capturesDragging = false;
589 m_mouseDownMayStartDrag = false;
590 m_mouseDownMayStartSelect = false;
591 m_mouseDownMayStartAutoscroll = false;
592 m_mouseDownWasInSubframe = false;
593
594 bool handled = false;
595
596 // Clear the selection if the mouse didn't move after the last mouse
597 // press and it's not a context menu click. We do this so when clicking
598 // on the selection, the selection goes away. However, if we are
599 // editing, place the caret.
600 if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
601 && m_dragStartPos == event.event().pos()
602 && m_frame->selection()->isRange()
603 && event.event().button() != RightButton) {
604 VisibleSelection newSelection;
605 Node *node = event.targetNode();
606 bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
607 if (node && (caretBrowsing || node->isContentEditable()) && node->renderer()) {
608 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
609 newSelection = VisibleSelection(pos);
610 }
611 if (m_frame->shouldChangeSelection(newSelection))
612 m_frame->selection()->setSelection(newSelection);
613
614 handled = true;
615 }
616
617 m_frame->notifyRendererOfSelectionChange(true);
618
619 m_frame->selection()->selectFrameElementInParentIfFullySelected();
620
621 return handled;
622 }
623
handleAutoscroll(RenderObject * renderer)624 void EventHandler::handleAutoscroll(RenderObject* renderer)
625 {
626 // We don't want to trigger the autoscroll or the panScroll if it's already active
627 if (m_autoscrollTimer.isActive())
628 return;
629
630 setAutoscrollRenderer(renderer);
631
632 #if ENABLE(PAN_SCROLLING)
633 if (m_panScrollInProgress) {
634 m_panScrollStartPos = currentMousePosition();
635 if (FrameView* view = m_frame->view())
636 view->addPanScrollIcon(m_panScrollStartPos);
637 // If we're not in the top frame we notify it that we doing a panScroll.
638 if (Page* page = m_frame->page()) {
639 Frame* mainFrame = page->mainFrame();
640 if (m_frame != mainFrame)
641 mainFrame->eventHandler()->setPanScrollInProgress(true);
642 }
643 }
644 #endif
645
646 startAutoscrollTimer();
647 }
648
autoscrollTimerFired(Timer<EventHandler> *)649 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
650 {
651 RenderObject* r = autoscrollRenderer();
652 if (!r || !r->isBox()) {
653 stopAutoscrollTimer();
654 return;
655 }
656
657 if (m_autoscrollInProgress) {
658 if (!m_mousePressed) {
659 stopAutoscrollTimer();
660 return;
661 }
662 toRenderBox(r)->autoscroll();
663 } else {
664 // we verify that the main frame hasn't received the order to stop the panScroll
665 if (Page* page = m_frame->page()) {
666 if (!page->mainFrame()->eventHandler()->panScrollInProgress()) {
667 stopAutoscrollTimer();
668 return;
669 }
670 }
671 #if ENABLE(PAN_SCROLLING)
672 updatePanScrollState();
673 toRenderBox(r)->panScroll(m_panScrollStartPos);
674 #endif
675 }
676 }
677
678 #if ENABLE(PAN_SCROLLING)
679
updatePanScrollState()680 void EventHandler::updatePanScrollState()
681 {
682 FrameView* view = m_frame->view();
683 if (!view)
684 return;
685
686 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
687 // So we don't want to change the cursor over this area
688 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
689 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
690 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
691 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
692
693 if ((east || west || north || south) && m_panScrollButtonPressed)
694 m_springLoadedPanScrollInProgress = true;
695
696 if (north) {
697 if (east)
698 view->setCursor(northEastPanningCursor());
699 else if (west)
700 view->setCursor(northWestPanningCursor());
701 else
702 view->setCursor(northPanningCursor());
703 } else if (south) {
704 if (east)
705 view->setCursor(southEastPanningCursor());
706 else if (west)
707 view->setCursor(southWestPanningCursor());
708 else
709 view->setCursor(southPanningCursor());
710 } else if (east)
711 view->setCursor(eastPanningCursor());
712 else if (west)
713 view->setCursor(westPanningCursor());
714 else
715 view->setCursor(middlePanningCursor());
716 }
717
718 #endif // ENABLE(PAN_SCROLLING)
719
autoscrollRenderer() const720 RenderObject* EventHandler::autoscrollRenderer() const
721 {
722 return m_autoscrollRenderer;
723 }
724
updateAutoscrollRenderer()725 void EventHandler::updateAutoscrollRenderer()
726 {
727 if (!m_autoscrollRenderer)
728 return;
729
730 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
731
732 if (Node* nodeAtPoint = hitTest.innerNode())
733 m_autoscrollRenderer = nodeAtPoint->renderer();
734
735 while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeProgramaticallyScrolled(false)))
736 m_autoscrollRenderer = m_autoscrollRenderer->parent();
737 }
738
setAutoscrollRenderer(RenderObject * renderer)739 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
740 {
741 m_autoscrollRenderer = renderer;
742 }
743
allowDHTMLDrag(bool & flagDHTML,bool & flagUA) const744 void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
745 {
746 flagDHTML = false;
747 flagUA = false;
748
749 if (!m_frame)
750 return;
751
752 Page* page = m_frame->page();
753 if (!page)
754 return;
755
756 FrameView* view = m_frame->view();
757 if (!view)
758 return;
759
760 unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
761 flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
762 flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
763 }
764
hitTestResultAtPoint(const IntPoint & point,bool allowShadowContent,bool ignoreClipping,HitTestScrollbars testScrollbars)765 HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars)
766 {
767 HitTestResult result(point);
768 if (!m_frame->contentRenderer())
769 return result;
770 int hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
771 if (ignoreClipping)
772 hitType |= HitTestRequest::IgnoreClipping;
773 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
774
775 while (true) {
776 Node* n = result.innerNode();
777 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
778 break;
779 RenderWidget* renderWidget = toRenderWidget(n->renderer());
780 Widget* widget = renderWidget->widget();
781 if (!widget || !widget->isFrameView())
782 break;
783 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
784 if (!frame || !frame->contentRenderer())
785 break;
786 FrameView* view = static_cast<FrameView*>(widget);
787 IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
788 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
789 HitTestResult widgetHitTestResult(widgetPoint);
790 frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
791 result = widgetHitTestResult;
792
793 if (testScrollbars == ShouldHitTestScrollbars) {
794 Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
795 if (eventScrollbar)
796 result.setScrollbar(eventScrollbar);
797 }
798 }
799
800 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
801 // Another hit test at the main frame level should get us the correct visible result.
802 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
803 if (Page* page = m_frame->page()) {
804 Frame* mainFrame = page->mainFrame();
805 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
806 FrameView* resultView = resultFrame->view();
807 FrameView* mainView = mainFrame->view();
808 if (resultView && mainView) {
809 IntPoint windowPoint = resultView->contentsToWindow(result.point());
810 IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
811 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping);
812 }
813 }
814 }
815
816 if (!allowShadowContent)
817 result.setToNonShadowAncestor();
818
819 return result;
820 }
821
822
startAutoscrollTimer()823 void EventHandler::startAutoscrollTimer()
824 {
825 m_autoscrollTimer.startRepeating(autoscrollInterval);
826 }
827
stopAutoscrollTimer(bool rendererIsBeingDestroyed)828 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
829 {
830 if (m_autoscrollInProgress) {
831 if (m_mouseDownWasInSubframe) {
832 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
833 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
834 return;
835 }
836 }
837
838 if (autoscrollRenderer()) {
839 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
840 toRenderBox(autoscrollRenderer())->stopAutoscroll();
841 #if ENABLE(PAN_SCROLLING)
842 if (m_panScrollInProgress) {
843 if (FrameView* view = m_frame->view()) {
844 view->removePanScrollIcon();
845 view->setCursor(pointerCursor());
846 }
847 }
848 #endif
849
850 setAutoscrollRenderer(0);
851 }
852
853 m_autoscrollTimer.stop();
854
855 m_panScrollInProgress = false;
856 m_springLoadedPanScrollInProgress = false;
857
858 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
859 if (Page* page = m_frame->page()) {
860 Frame* mainFrame = page->mainFrame();
861 if (m_frame != mainFrame)
862 mainFrame->eventHandler()->setPanScrollInProgress(false);
863 }
864
865 m_autoscrollInProgress = false;
866 }
867
mousePressNode() const868 Node* EventHandler::mousePressNode() const
869 {
870 return m_mousePressNode.get();
871 }
872
setMousePressNode(PassRefPtr<Node> node)873 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
874 {
875 m_mousePressNode = node;
876 }
877
scrollOverflow(ScrollDirection direction,ScrollGranularity granularity)878 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
879 {
880 Node* node = m_frame->document()->focusedNode();
881 if (!node)
882 node = m_mousePressNode.get();
883
884 if (node) {
885 RenderObject* r = node->renderer();
886 if (r && !r->isListBox())
887 return r->enclosingBox()->scroll(direction, granularity);
888 }
889
890 return false;
891 }
892
scrollRecursively(ScrollDirection direction,ScrollGranularity granularity)893 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity)
894 {
895 bool handled = scrollOverflow(direction, granularity);
896 if (!handled) {
897 Frame* frame = m_frame;
898 do {
899 FrameView* view = frame->view();
900 handled = view ? view->scroll(direction, granularity) : false;
901 frame = frame->tree()->parent();
902 } while (!handled && frame);
903 }
904
905 return handled;
906 }
907
currentMousePosition() const908 IntPoint EventHandler::currentMousePosition() const
909 {
910 return m_currentMousePosition;
911 }
912
subframeForHitTestResult(const MouseEventWithHitTestResults & hitTestResult)913 Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
914 {
915 if (!hitTestResult.isOverWidget())
916 return 0;
917 return subframeForTargetNode(hitTestResult.targetNode());
918 }
919
subframeForTargetNode(Node * node)920 Frame* subframeForTargetNode(Node* node)
921 {
922 if (!node)
923 return 0;
924
925 RenderObject* renderer = node->renderer();
926 if (!renderer || !renderer->isWidget())
927 return 0;
928
929 Widget* widget = toRenderWidget(renderer)->widget();
930 if (!widget || !widget->isFrameView())
931 return 0;
932
933 return static_cast<FrameView*>(widget)->frame();
934 }
935
isSubmitImage(Node * node)936 static bool isSubmitImage(Node* node)
937 {
938 return node && node->hasTagName(inputTag)
939 && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
940 }
941
942 // Returns true if the node's editable block is not current focused for editing
nodeIsNotBeingEdited(Node * node,Frame * frame)943 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
944 {
945 return frame->selection()->rootEditableElement() != node->rootEditableElement();
946 }
947
selectCursor(const MouseEventWithHitTestResults & event,Scrollbar * scrollbar)948 Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
949 {
950 // During selection, use an I-beam no matter what we're over.
951 // If you're capturing mouse events for a particular node, don't treat this as a selection.
952 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
953 return iBeamCursor();
954
955 Node* node = event.targetNode();
956 RenderObject* renderer = node ? node->renderer() : 0;
957 RenderStyle* style = renderer ? renderer->style() : 0;
958
959 if (renderer && renderer->isFrameSet()) {
960 RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer);
961 if (frameSetRenderer->canResizeRow(event.localPoint()))
962 return rowResizeCursor();
963 if (frameSetRenderer->canResizeColumn(event.localPoint()))
964 return columnResizeCursor();
965 }
966
967 if (style && style->cursors()) {
968 const CursorList* cursors = style->cursors();
969 for (unsigned i = 0; i < cursors->size(); ++i) {
970 CachedImage* cimage = (*cursors)[i].cursorImage.get();
971 IntPoint hotSpot = (*cursors)[i].hotSpot;
972 if (!cimage)
973 continue;
974 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
975 IntSize size = cimage->image()->size();
976 if (size.width() > 128 || size.height() > 128)
977 continue;
978 // Do not let the hotspot be outside the bounds of the image.
979 if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height())
980 continue;
981 if (cimage->image()->isNull())
982 break;
983 if (!cimage->errorOccurred())
984 return Cursor(cimage->image(), hotSpot);
985 }
986 }
987
988 switch (style ? style->cursor() : CURSOR_AUTO) {
989 case CURSOR_AUTO: {
990 bool editable = (node && node->isContentEditable());
991 bool editableLinkEnabled = false;
992
993 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
994 if (editable) {
995 ASSERT(m_frame->settings());
996 switch (m_frame->settings()->editableLinkBehavior()) {
997 default:
998 case EditableLinkDefaultBehavior:
999 case EditableLinkAlwaysLive:
1000 editableLinkEnabled = true;
1001 break;
1002
1003 case EditableLinkNeverLive:
1004 editableLinkEnabled = false;
1005 break;
1006
1007 case EditableLinkLiveWhenNotFocused:
1008 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1009 break;
1010
1011 case EditableLinkOnlyLiveWithShiftKey:
1012 editableLinkEnabled = event.event().shiftKey();
1013 break;
1014 }
1015 }
1016
1017 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1018 return handCursor();
1019 bool inResizer = false;
1020 if (renderer) {
1021 if (RenderLayer* layer = renderer->enclosingLayer()) {
1022 if (FrameView* view = m_frame->view())
1023 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos()));
1024 }
1025 }
1026 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1027 return iBeamCursor();
1028 return pointerCursor();
1029 }
1030 case CURSOR_CROSS:
1031 return crossCursor();
1032 case CURSOR_POINTER:
1033 return handCursor();
1034 case CURSOR_MOVE:
1035 return moveCursor();
1036 case CURSOR_ALL_SCROLL:
1037 return moveCursor();
1038 case CURSOR_E_RESIZE:
1039 return eastResizeCursor();
1040 case CURSOR_W_RESIZE:
1041 return westResizeCursor();
1042 case CURSOR_N_RESIZE:
1043 return northResizeCursor();
1044 case CURSOR_S_RESIZE:
1045 return southResizeCursor();
1046 case CURSOR_NE_RESIZE:
1047 return northEastResizeCursor();
1048 case CURSOR_SW_RESIZE:
1049 return southWestResizeCursor();
1050 case CURSOR_NW_RESIZE:
1051 return northWestResizeCursor();
1052 case CURSOR_SE_RESIZE:
1053 return southEastResizeCursor();
1054 case CURSOR_NS_RESIZE:
1055 return northSouthResizeCursor();
1056 case CURSOR_EW_RESIZE:
1057 return eastWestResizeCursor();
1058 case CURSOR_NESW_RESIZE:
1059 return northEastSouthWestResizeCursor();
1060 case CURSOR_NWSE_RESIZE:
1061 return northWestSouthEastResizeCursor();
1062 case CURSOR_COL_RESIZE:
1063 return columnResizeCursor();
1064 case CURSOR_ROW_RESIZE:
1065 return rowResizeCursor();
1066 case CURSOR_TEXT:
1067 return iBeamCursor();
1068 case CURSOR_WAIT:
1069 return waitCursor();
1070 case CURSOR_HELP:
1071 return helpCursor();
1072 case CURSOR_VERTICAL_TEXT:
1073 return verticalTextCursor();
1074 case CURSOR_CELL:
1075 return cellCursor();
1076 case CURSOR_CONTEXT_MENU:
1077 return contextMenuCursor();
1078 case CURSOR_PROGRESS:
1079 return progressCursor();
1080 case CURSOR_NO_DROP:
1081 return noDropCursor();
1082 case CURSOR_ALIAS:
1083 return aliasCursor();
1084 case CURSOR_COPY:
1085 return copyCursor();
1086 case CURSOR_NONE:
1087 return noneCursor();
1088 case CURSOR_NOT_ALLOWED:
1089 return notAllowedCursor();
1090 case CURSOR_DEFAULT:
1091 return pointerCursor();
1092 case CURSOR_WEBKIT_ZOOM_IN:
1093 return zoomInCursor();
1094 case CURSOR_WEBKIT_ZOOM_OUT:
1095 return zoomOutCursor();
1096 case CURSOR_WEBKIT_GRAB:
1097 return grabCursor();
1098 case CURSOR_WEBKIT_GRABBING:
1099 return grabbingCursor();
1100 }
1101 return pointerCursor();
1102 }
1103
documentPointForWindowPoint(Frame * frame,const IntPoint & windowPoint)1104 static IntPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1105 {
1106 FrameView* view = frame->view();
1107 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1108 // Historically the code would just crash; this is clearly no worse than that.
1109 return view ? view->windowToContents(windowPoint) : windowPoint;
1110 }
1111
handleMousePressEvent(const PlatformMouseEvent & mouseEvent)1112 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1113 {
1114 RefPtr<FrameView> protector(m_frame->view());
1115
1116 m_mousePressed = true;
1117 m_capturesDragging = true;
1118 m_currentMousePosition = mouseEvent.pos();
1119 m_mouseDownTimestamp = mouseEvent.timestamp();
1120 m_mouseDownMayStartDrag = false;
1121 m_mouseDownMayStartSelect = false;
1122 m_mouseDownMayStartAutoscroll = false;
1123 if (FrameView* view = m_frame->view())
1124 m_mouseDownPos = view->windowToContents(mouseEvent.pos());
1125 else {
1126 invalidateClick();
1127 return false;
1128 }
1129 m_mouseDownWasInSubframe = false;
1130
1131 HitTestRequest request(HitTestRequest::Active);
1132 // Save the document point we generate in case the window coordinate is invalidated by what happens
1133 // when we dispatch the event.
1134 IntPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos());
1135 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1136
1137 if (!mev.targetNode()) {
1138 invalidateClick();
1139 return false;
1140 }
1141
1142 m_mousePressNode = mev.targetNode();
1143
1144 if (Page* page = m_frame->page()) {
1145 InspectorController* inspector = page->inspectorController();
1146 if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) {
1147 inspector->handleMousePressOnNode(m_mousePressNode.get());
1148 invalidateClick();
1149 return true;
1150 }
1151 }
1152
1153 Frame* subframe = subframeForHitTestResult(mev);
1154 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1155 // Start capturing future events for this frame. We only do this if we didn't clear
1156 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1157 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1158 if (m_mousePressed && m_capturesDragging)
1159 m_capturingMouseEventsNode = mev.targetNode();
1160 invalidateClick();
1161 return true;
1162 }
1163
1164 #if ENABLE(PAN_SCROLLING)
1165 Page* page = m_frame->page();
1166 if (page && page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
1167 stopAutoscrollTimer();
1168 invalidateClick();
1169 return true;
1170 }
1171
1172 if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) {
1173 RenderObject* renderer = mev.targetNode()->renderer();
1174
1175 while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) {
1176 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
1177 renderer = renderer->document()->ownerElement()->renderer();
1178 else
1179 renderer = renderer->parent();
1180 }
1181
1182 if (renderer) {
1183 m_panScrollInProgress = true;
1184 m_panScrollButtonPressed = true;
1185 handleAutoscroll(renderer);
1186 invalidateClick();
1187 return true;
1188 }
1189 }
1190 #endif
1191
1192 m_clickCount = mouseEvent.clickCount();
1193 m_clickNode = mev.targetNode();
1194
1195 if (FrameView* view = m_frame->view()) {
1196 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1197 IntPoint p = view->windowToContents(mouseEvent.pos());
1198 if (layer && layer->isPointInResizeControl(p)) {
1199 layer->setInResizeMode(true);
1200 m_resizeLayer = layer;
1201 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1202 invalidateClick();
1203 return true;
1204 }
1205 }
1206
1207 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1208 m_capturesDragging = !swallowEvent;
1209
1210 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1211 // in case the scrollbar widget was destroyed when the mouse event was handled.
1212 if (mev.scrollbar()) {
1213 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1214 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1215 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1216 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1217 m_lastScrollbarUnderMouse = 0;
1218 }
1219
1220 if (swallowEvent) {
1221 // scrollbars should get events anyway, even disabled controls might be scrollable
1222 Scrollbar* scrollbar = mev.scrollbar();
1223
1224 updateLastScrollbarUnderMouse(scrollbar, true);
1225
1226 if (scrollbar)
1227 passMousePressEventToScrollbar(mev, scrollbar);
1228 } else {
1229 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1230 // If a mouse event handler changes the input element type to one that has a widget associated,
1231 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1232 // event target node can't still be the shadow node.
1233 if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) {
1234 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1235 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1236 }
1237
1238 FrameView* view = m_frame->view();
1239 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0;
1240 if (!scrollbar)
1241 scrollbar = mev.scrollbar();
1242
1243 updateLastScrollbarUnderMouse(scrollbar, true);
1244
1245 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1246 swallowEvent = true;
1247 else
1248 swallowEvent = handleMousePressEvent(mev);
1249 }
1250
1251 return swallowEvent;
1252 }
1253
1254 // This method only exists for platforms that don't know how to deliver
handleMouseDoubleClickEvent(const PlatformMouseEvent & mouseEvent)1255 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1256 {
1257 RefPtr<FrameView> protector(m_frame->view());
1258
1259 // We get this instead of a second mouse-up
1260 m_mousePressed = false;
1261 m_currentMousePosition = mouseEvent.pos();
1262
1263 HitTestRequest request(HitTestRequest::Active);
1264 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1265 Frame* subframe = subframeForHitTestResult(mev);
1266 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1267 m_capturingMouseEventsNode = 0;
1268 return true;
1269 }
1270
1271 m_clickCount = mouseEvent.clickCount();
1272 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1273
1274 bool swallowClickEvent = false;
1275 // Don't ever dispatch click events for right clicks
1276 if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
1277 swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1278
1279 if (m_lastScrollbarUnderMouse)
1280 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
1281
1282 bool swallowMouseReleaseEvent = false;
1283 if (!swallowMouseUpEvent)
1284 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1285
1286 invalidateClick();
1287
1288 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1289 }
1290
mouseMoved(const PlatformMouseEvent & event)1291 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1292 {
1293 HitTestResult hoveredNode = HitTestResult(IntPoint());
1294 bool result = handleMouseMoveEvent(event, &hoveredNode);
1295
1296 Page* page = m_frame->page();
1297 if (!page)
1298 return result;
1299
1300 hoveredNode.setToNonShadowAncestor();
1301 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1302 page->chrome()->setToolTip(hoveredNode);
1303 return result;
1304 }
1305
handleMouseMoveEvent(const PlatformMouseEvent & mouseEvent,HitTestResult * hoveredNode)1306 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode)
1307 {
1308 // in Radar 3703768 we saw frequent crashes apparently due to the
1309 // part being null here, which seems impossible, so check for nil
1310 // but also assert so that we can try to figure this out in debug
1311 // builds, if it happens.
1312 ASSERT(m_frame);
1313 if (!m_frame)
1314 return false;
1315
1316 RefPtr<FrameView> protector(m_frame->view());
1317 m_currentMousePosition = mouseEvent.pos();
1318
1319 if (m_hoverTimer.isActive())
1320 m_hoverTimer.stop();
1321
1322 #if ENABLE(SVG)
1323 if (m_svgPan) {
1324 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1325 return true;
1326 }
1327 #endif
1328
1329 if (m_frameSetBeingResized)
1330 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1331
1332 // Send events right to a scrollbar if the mouse is pressed.
1333 if (m_lastScrollbarUnderMouse && m_mousePressed)
1334 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1335
1336 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
1337 // if we are allowed to select.
1338 // This means that :hover and :active freeze in the state they were in when the mouse
1339 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
1340 int hitType = HitTestRequest::MouseMove;
1341 if (m_mousePressed && m_mouseDownMayStartSelect)
1342 hitType |= HitTestRequest::ReadOnly;
1343 if (m_mousePressed)
1344 hitType |= HitTestRequest::Active;
1345 HitTestRequest request(hitType);
1346 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1347 if (hoveredNode)
1348 *hoveredNode = mev.hitTestResult();
1349
1350 Scrollbar* scrollbar = 0;
1351
1352 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1353 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1354 else {
1355 if (FrameView* view = m_frame->view())
1356 scrollbar = view->scrollbarAtPoint(mouseEvent.pos());
1357
1358 if (!scrollbar)
1359 scrollbar = mev.scrollbar();
1360
1361 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1362 }
1363
1364 bool swallowEvent = false;
1365 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1366
1367 // 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.
1368 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1369 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1370
1371 if (newSubframe) {
1372 // Update over/out state before passing the event to the subframe.
1373 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1374
1375 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1376 // node to be detached from its FrameView, in which case the event should not be passed.
1377 if (newSubframe->view())
1378 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1379 } else {
1380 if (scrollbar && !m_mousePressed)
1381 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1382 if (Page* page = m_frame->page()) {
1383 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) {
1384 if (FrameView* view = m_frame->view())
1385 view->setCursor(selectCursor(mev, scrollbar));
1386 }
1387 }
1388 }
1389
1390 m_lastMouseMoveEventSubframe = newSubframe;
1391
1392 if (swallowEvent)
1393 return true;
1394
1395 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
1396 if (!swallowEvent)
1397 swallowEvent = handleMouseDraggedEvent(mev);
1398
1399 return swallowEvent;
1400 }
1401
invalidateClick()1402 void EventHandler::invalidateClick()
1403 {
1404 m_clickCount = 0;
1405 m_clickNode = 0;
1406 }
1407
handleMouseReleaseEvent(const PlatformMouseEvent & mouseEvent)1408 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1409 {
1410 RefPtr<FrameView> protector(m_frame->view());
1411
1412 #if ENABLE(PAN_SCROLLING)
1413 if (mouseEvent.button() == MiddleButton)
1414 m_panScrollButtonPressed = false;
1415 if (m_springLoadedPanScrollInProgress)
1416 stopAutoscrollTimer();
1417 #endif
1418
1419 m_mousePressed = false;
1420 m_currentMousePosition = mouseEvent.pos();
1421
1422 #if ENABLE(SVG)
1423 if (m_svgPan) {
1424 m_svgPan = false;
1425 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1426 return true;
1427 }
1428 #endif
1429
1430 if (m_frameSetBeingResized)
1431 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1432
1433 if (m_lastScrollbarUnderMouse) {
1434 invalidateClick();
1435 return m_lastScrollbarUnderMouse->mouseUp();
1436 }
1437
1438 HitTestRequest request(HitTestRequest::MouseUp);
1439 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1440 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1441 if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) {
1442 m_capturingMouseEventsNode = 0;
1443 return true;
1444 }
1445
1446 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1447
1448 // Don't ever dispatch click events for right clicks
1449 bool swallowClickEvent = false;
1450 if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
1451 swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1452
1453 if (m_resizeLayer) {
1454 m_resizeLayer->setInResizeMode(false);
1455 m_resizeLayer = 0;
1456 }
1457
1458 bool swallowMouseReleaseEvent = false;
1459 if (!swallowMouseUpEvent)
1460 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1461
1462 invalidateClick();
1463
1464 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1465 }
1466
dispatchDragEvent(const AtomicString & eventType,Node * dragTarget,const PlatformMouseEvent & event,Clipboard * clipboard)1467 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1468 {
1469 FrameView* view = m_frame->view();
1470
1471 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1472 if (!view)
1473 return false;
1474
1475 view->resetDeferredRepaintDelay();
1476 IntPoint contentsPos = view->windowToContents(event.pos());
1477
1478 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1479 true, true, m_frame->document()->defaultView(),
1480 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
1481 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1482 0, 0, clipboard);
1483
1484 ExceptionCode ec;
1485 dragTarget->dispatchEvent(me.get(), ec);
1486 return me->defaultPrevented();
1487 }
1488
updateDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1489 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1490 {
1491 bool accept = false;
1492
1493 if (!m_frame->view())
1494 return false;
1495
1496 HitTestRequest request(HitTestRequest::ReadOnly);
1497 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1498
1499 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1500 Node* newTarget = mev.targetNode();
1501 if (newTarget && newTarget->isTextNode())
1502 newTarget = newTarget->parentNode();
1503 if (newTarget)
1504 newTarget = newTarget->shadowAncestorNode();
1505
1506 if (m_dragTarget != newTarget) {
1507 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1508 // it is sometimes incorrect when dragging within subframes, as seen with
1509 // LayoutTests/fast/events/drag-in-frames.html.
1510 if (newTarget) {
1511 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
1512 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
1513 else
1514 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
1515 }
1516
1517 if (m_dragTarget) {
1518 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1519 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1520 if (frame)
1521 accept = frame->eventHandler()->updateDragAndDrop(event, clipboard);
1522 else
1523 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1524 }
1525 } else {
1526 if (newTarget) {
1527 if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
1528 accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
1529 else
1530 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
1531 }
1532 }
1533 m_dragTarget = newTarget;
1534
1535 return accept;
1536 }
1537
cancelDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1538 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1539 {
1540 if (m_dragTarget) {
1541 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1542 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1543 if (frame)
1544 frame->eventHandler()->cancelDragAndDrop(event, clipboard);
1545 else
1546 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1547 }
1548 clearDragState();
1549 }
1550
performDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1551 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1552 {
1553 bool accept = false;
1554 if (m_dragTarget) {
1555 Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
1556 ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
1557 if (frame)
1558 accept = frame->eventHandler()->performDragAndDrop(event, clipboard);
1559 else
1560 accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
1561 }
1562 clearDragState();
1563 return accept;
1564 }
1565
clearDragState()1566 void EventHandler::clearDragState()
1567 {
1568 m_dragTarget = 0;
1569 m_capturingMouseEventsNode = 0;
1570 #if PLATFORM(MAC)
1571 m_sendingEventToSubview = false;
1572 #endif
1573 }
1574
setCapturingMouseEventsNode(PassRefPtr<Node> n)1575 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1576 {
1577 m_capturingMouseEventsNode = n;
1578 }
1579
prepareMouseEvent(const HitTestRequest & request,const PlatformMouseEvent & mev)1580 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1581 {
1582 ASSERT(m_frame);
1583 ASSERT(m_frame->document());
1584
1585 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
1586 }
1587
1588 #if ENABLE(SVG)
instanceAssociatedWithShadowTreeElement(Node * referenceNode)1589 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1590 {
1591 if (!referenceNode || !referenceNode->isSVGElement())
1592 return 0;
1593
1594 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
1595 if (!shadowTreeElement)
1596 return 0;
1597
1598 Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode();
1599 if (!shadowTreeParentElement)
1600 return 0;
1601
1602 ASSERT(shadowTreeParentElement->hasTagName(useTag));
1603 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1604 }
1605 #endif
1606
updateMouseEventTargetNode(Node * targetNode,const PlatformMouseEvent & mouseEvent,bool fireMouseOverOut)1607 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1608 {
1609 Node* result = targetNode;
1610
1611 // If we're capturing, we always go right to that node.
1612 if (m_capturingMouseEventsNode)
1613 result = m_capturingMouseEventsNode.get();
1614 else {
1615 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1616 if (result && result->isTextNode())
1617 result = result->parentNode();
1618 if (result)
1619 result = result->shadowAncestorNode();
1620 }
1621 m_nodeUnderMouse = result;
1622 #if ENABLE(SVG)
1623 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1624
1625 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1626 if (m_lastInstanceUnderMouse) {
1627 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1628 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1629
1630 if (lastCorrespondingElement && lastCorrespondingUseElement) {
1631 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1632
1633 // Locate the recloned shadow tree element for our corresponding instance
1634 HashSet<SVGElementInstance*>::iterator end = instances.end();
1635 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1636 SVGElementInstance* instance = (*it);
1637 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1638
1639 if (instance == m_lastInstanceUnderMouse)
1640 continue;
1641
1642 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1643 continue;
1644
1645 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1646 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1647 continue;
1648
1649 m_lastNodeUnderMouse = shadowTreeElement;
1650 m_lastInstanceUnderMouse = instance;
1651 break;
1652 }
1653 }
1654 }
1655 #endif
1656
1657 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1658 if (fireMouseOverOut) {
1659 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1660 m_lastNodeUnderMouse = 0;
1661 m_lastScrollbarUnderMouse = 0;
1662 #if ENABLE(SVG)
1663 m_lastInstanceUnderMouse = 0;
1664 #endif
1665 }
1666
1667 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1668 // send mouseout event to the old node
1669 if (m_lastNodeUnderMouse)
1670 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
1671 // send mouseover event to the new node
1672 if (m_nodeUnderMouse)
1673 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
1674 }
1675 m_lastNodeUnderMouse = m_nodeUnderMouse;
1676 #if ENABLE(SVG)
1677 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
1678 #endif
1679 }
1680 }
1681
dispatchMouseEvent(const AtomicString & eventType,Node * targetNode,bool,int clickCount,const PlatformMouseEvent & mouseEvent,bool setUnder)1682 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1683 {
1684 if (FrameView* view = m_frame->view())
1685 view->resetDeferredRepaintDelay();
1686
1687 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1688
1689 bool swallowEvent = false;
1690
1691 if (m_nodeUnderMouse)
1692 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1693
1694 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
1695 // Blur current focus node when a link/button is clicked; this
1696 // is expected by some sites that rely on onChange handlers running
1697 // from form fields before the button click is processed.
1698 Node* node = m_nodeUnderMouse.get();
1699 RenderObject* renderer = node ? node->renderer() : 0;
1700
1701 // Walk up the render tree to search for a node to focus.
1702 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1703 while (renderer) {
1704 node = renderer->node();
1705 if (node && node->isFocusable()) {
1706 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
1707 // node on mouse down if it's selected and inside a focused node. It will be
1708 // focused if the user does a mouseup over it, however, because the mouseup
1709 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
1710 ExceptionCode ec = 0;
1711 Node* n = node->isShadowNode() ? node->shadowParentNode() : node;
1712 if (m_frame->selection()->isRange() &&
1713 m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE &&
1714 n->isDescendantOf(m_frame->document()->focusedNode()))
1715 return false;
1716
1717 break;
1718 }
1719
1720 renderer = renderer->parent();
1721 }
1722
1723 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
1724 // if the page already set it (e.g., by canceling default behavior).
1725 if (Page* page = m_frame->page()) {
1726 if (node && node->isMouseFocusable()) {
1727 if (!page->focusController()->setFocusedNode(node, m_frame))
1728 swallowEvent = true;
1729 } else if (!node || !node->focused()) {
1730 if (!page->focusController()->setFocusedNode(0, m_frame))
1731 swallowEvent = true;
1732 }
1733 }
1734 }
1735
1736 return swallowEvent;
1737 }
1738
handleWheelEvent(PlatformWheelEvent & e)1739 bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
1740 {
1741 Document* doc = m_frame->document();
1742
1743 RenderObject* docRenderer = doc->renderer();
1744 if (!docRenderer)
1745 return false;
1746
1747 RefPtr<FrameView> protector(m_frame->view());
1748
1749 FrameView* view = m_frame->view();
1750 if (!view)
1751 return false;
1752 IntPoint vPoint = view->windowToContents(e.pos());
1753
1754 Node* node;
1755 bool isOverWidget;
1756 bool didSetLatchedNode = false;
1757
1758 if (m_useLatchedWheelEventNode) {
1759 if (!m_latchedWheelEventNode) {
1760 HitTestRequest request(HitTestRequest::ReadOnly);
1761 HitTestResult result(vPoint);
1762 doc->renderView()->layer()->hitTest(request, result);
1763 m_latchedWheelEventNode = result.innerNode();
1764 m_widgetIsLatched = result.isOverWidget();
1765 didSetLatchedNode = true;
1766 }
1767
1768 node = m_latchedWheelEventNode.get();
1769 isOverWidget = m_widgetIsLatched;
1770 } else {
1771 if (m_latchedWheelEventNode)
1772 m_latchedWheelEventNode = 0;
1773
1774 HitTestRequest request(HitTestRequest::ReadOnly);
1775 HitTestResult result(vPoint);
1776 doc->renderView()->layer()->hitTest(request, result);
1777 node = result.innerNode();
1778 isOverWidget = result.isOverWidget();
1779 }
1780
1781 if (node) {
1782 // Figure out which view to send the event to.
1783 RenderObject* target = node->renderer();
1784
1785 if (isOverWidget && target && target->isWidget()) {
1786 Widget* widget = toRenderWidget(target)->widget();
1787 if (widget && passWheelEventToWidget(e, widget)) {
1788 e.accept();
1789 return true;
1790 }
1791 }
1792
1793 node = node->shadowAncestorNode();
1794 node->dispatchWheelEvent(e);
1795 if (e.isAccepted())
1796 return true;
1797
1798 // If we don't have a renderer, send the wheel event to the first node we find with a renderer.
1799 // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll.
1800 while (node && !node->renderer())
1801 node = node->parent();
1802
1803 if (node && node->renderer()) {
1804 // Just break up into two scrolls if we need to. Diagonal movement on
1805 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
1806 scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node);
1807 scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node);
1808 }
1809 }
1810
1811 if (e.isAccepted())
1812 return true;
1813
1814 view = m_frame->view();
1815 if (!view)
1816 return false;
1817
1818 view->wheelEvent(e);
1819 return e.isAccepted();
1820 }
1821
sendContextMenuEvent(const PlatformMouseEvent & event)1822 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
1823 {
1824 Document* doc = m_frame->document();
1825 FrameView* v = m_frame->view();
1826 if (!v)
1827 return false;
1828
1829 bool swallowEvent;
1830 IntPoint viewportPos = v->windowToContents(event.pos());
1831 HitTestRequest request(HitTestRequest::Active);
1832 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
1833
1834 // Context menu events shouldn't select text in GTK+ applications or in Chromium.
1835 // FIXME: This should probably be configurable by embedders. Consider making it a WebPreferences setting.
1836 // See: https://bugs.webkit.org/show_bug.cgi?id=15279
1837 #if !PLATFORM(GTK) && !PLATFORM(CHROMIUM)
1838 if (!m_frame->selection()->contains(viewportPos) &&
1839 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
1840 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
1841 // available for text selections. But only if we're above text.
1842 (m_frame->selection()->isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
1843 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
1844 selectClosestWordOrLinkFromMouseEvent(mev);
1845 }
1846 #endif
1847
1848 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, true);
1849
1850 return swallowEvent;
1851 }
1852
scheduleHoverStateUpdate()1853 void EventHandler::scheduleHoverStateUpdate()
1854 {
1855 if (!m_hoverTimer.isActive())
1856 m_hoverTimer.startOneShot(0);
1857 }
1858
1859 // Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
canMouseDownStartSelect(Node * node)1860 bool EventHandler::canMouseDownStartSelect(Node* node)
1861 {
1862 if (!node || !node->renderer())
1863 return true;
1864
1865 // Some controls and images can't start a select on a mouse down.
1866 if (!node->canStartSelection())
1867 return false;
1868
1869 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
1870 if (Node* node = curr->node())
1871 return node->dispatchEvent(eventNames().selectstartEvent, true, true);
1872 }
1873
1874 return true;
1875 }
1876
canMouseDragExtendSelect(Node * node)1877 bool EventHandler::canMouseDragExtendSelect(Node* node)
1878 {
1879 if (!node || !node->renderer())
1880 return true;
1881
1882 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
1883 if (Node* node = curr->node())
1884 return node->dispatchEvent(eventNames().selectstartEvent, true, true);
1885 }
1886
1887 return true;
1888 }
1889
setResizingFrameSet(HTMLFrameSetElement * frameSet)1890 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
1891 {
1892 m_frameSetBeingResized = frameSet;
1893 }
1894
resizeLayerDestroyed()1895 void EventHandler::resizeLayerDestroyed()
1896 {
1897 ASSERT(m_resizeLayer);
1898 m_resizeLayer = 0;
1899 }
1900
hoverTimerFired(Timer<EventHandler> *)1901 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
1902 {
1903 m_hoverTimer.stop();
1904
1905 ASSERT(m_frame);
1906 ASSERT(m_frame->document());
1907
1908 if (RenderView* renderer = m_frame->contentRenderer()) {
1909 if (FrameView* view = m_frame->view()) {
1910 HitTestRequest request(HitTestRequest::MouseMove);
1911 HitTestResult result(view->windowToContents(m_currentMousePosition));
1912 renderer->layer()->hitTest(request, result);
1913 m_frame->document()->updateStyleIfNeeded();
1914 }
1915 }
1916 }
1917
eventTargetNodeForDocument(Document * doc)1918 static Node* eventTargetNodeForDocument(Document* doc)
1919 {
1920 if (!doc)
1921 return 0;
1922 Node* node = doc->focusedNode();
1923
1924 #if defined(ANDROID_PLUGINS)
1925 if (!node && doc->frame() && doc->frame()->view())
1926 node = android::WebViewCore::getWebViewCore(doc->frame()->view())
1927 ->cursorNodeIsPlugin();
1928 #endif
1929
1930 if (!node && doc->isHTMLDocument())
1931 node = doc->body();
1932 if (!node)
1933 node = doc->documentElement();
1934 return node;
1935 }
1936
handleAccessKey(const PlatformKeyboardEvent & evt)1937 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
1938 {
1939 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
1940 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
1941 // lower case variants are present in a document, the correct element is matched based on Shift key state.
1942 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
1943 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey));
1944 if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers())
1945 return false;
1946 String key = evt.unmodifiedText();
1947 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
1948 if (!elem)
1949 return false;
1950 elem->accessKeyAction(false);
1951 return true;
1952 }
1953
1954 #if !PLATFORM(MAC)
needsKeyboardEventDisambiguationQuirks() const1955 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
1956 {
1957 return false;
1958 }
1959 #endif
1960
keyEvent(const PlatformKeyboardEvent & initialKeyEvent)1961 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
1962 {
1963 #if ENABLE(PAN_SCROLLING)
1964 if (Page* page = m_frame->page()) {
1965 if (page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
1966 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
1967 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown)
1968 stopAutoscrollTimer();
1969
1970 // If we were in autoscroll/panscroll mode, we swallow the key event
1971 return true;
1972 }
1973 }
1974 #endif
1975
1976 // Check for cases where we are too early for events -- possible unmatched key up
1977 // from pressing return in the location bar.
1978 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
1979 if (!node)
1980 return false;
1981
1982 if (FrameView* view = m_frame->view())
1983 view->resetDeferredRepaintDelay();
1984
1985 // FIXME: what is this doing here, in keyboard event handler?
1986 m_frame->loader()->resetMultipleFormSubmissionProtection();
1987
1988 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
1989 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
1990 // with access keys. Then we dispatch keydown, but suppress its default handling.
1991 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
1992 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
1993 bool matchedAnAccessKey = false;
1994 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
1995 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
1996
1997 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
1998 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
1999 return !node->dispatchKeyEvent(initialKeyEvent);
2000
2001 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2002
2003 ExceptionCode ec;
2004 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2005 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
2006 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
2007 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2008 if (matchedAnAccessKey)
2009 keydown->setDefaultPrevented(true);
2010 keydown->setTarget(node);
2011
2012 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
2013 node->dispatchEvent(keydown, ec);
2014 return keydown->defaultHandled() || keydown->defaultPrevented();
2015 }
2016
2017 // Run input method in advance of DOM event handling. This may result in the IM
2018 // modifying the page prior the keydown event, but this behaviour is necessary
2019 // in order to match IE:
2020 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2021 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2022 m_frame->editor()->handleInputMethodKeydown(keydown.get());
2023
2024 bool handledByInputMethod = keydown->defaultHandled();
2025
2026 if (handledByInputMethod) {
2027 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2028 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2029 keydown->setTarget(node);
2030 keydown->setDefaultHandled();
2031 }
2032
2033 node->dispatchEvent(keydown, ec);
2034 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented();
2035 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2036 return keydownResult;
2037
2038 // Focus may have changed during keydown handling, so refetch node.
2039 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2040 if (!keydownResult) {
2041 node = eventTargetNodeForDocument(m_frame->document());
2042 if (!node)
2043 return false;
2044 }
2045
2046 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2047 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
2048 if (keyPressEvent.text().isEmpty())
2049 return keydownResult;
2050 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
2051 keypress->setTarget(node);
2052 if (keydownResult)
2053 keypress->setDefaultPrevented(true);
2054 #if PLATFORM(MAC)
2055 keypress->keypressCommands() = keydown->keypressCommands();
2056 #endif
2057 node->dispatchEvent(keypress, ec);
2058
2059 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2060 }
2061
handleKeyboardSelectionMovement(KeyboardEvent * event)2062 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
2063 {
2064 if (!event)
2065 return;
2066
2067 String key = event->keyIdentifier();
2068 bool isShifted = event->getModifierState("Shift");
2069 bool isOptioned = event->getModifierState("Alt");
2070 bool isCommanded = event->getModifierState("Meta");
2071
2072 if (key == "Up") {
2073 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2074 event->setDefaultHandled();
2075 }
2076 else if (key == "Down") {
2077 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2078 event->setDefaultHandled();
2079 }
2080 else if (key == "Left") {
2081 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2082 event->setDefaultHandled();
2083 }
2084 else if (key == "Right") {
2085 m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2086 event->setDefaultHandled();
2087 }
2088 }
2089
defaultKeyboardEventHandler(KeyboardEvent * event)2090 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2091 {
2092 if (event->type() == eventNames().keydownEvent) {
2093 m_frame->editor()->handleKeyboardEvent(event);
2094 if (event->defaultHandled())
2095 return;
2096 if (event->keyIdentifier() == "U+0009")
2097 defaultTabEventHandler(event);
2098
2099 // provides KB navigation and selection for enhanced accessibility users
2100 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2101 handleKeyboardSelectionMovement(event);
2102 }
2103 if (event->type() == eventNames().keypressEvent) {
2104 m_frame->editor()->handleKeyboardEvent(event);
2105 if (event->defaultHandled())
2106 return;
2107 if (event->charCode() == ' ')
2108 defaultSpaceEventHandler(event);
2109 }
2110 }
2111
dragHysteresisExceeded(const FloatPoint & floatDragViewportLocation) const2112 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
2113 {
2114 IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y());
2115 return dragHysteresisExceeded(dragViewportLocation);
2116 }
2117
dragHysteresisExceeded(const IntPoint & dragViewportLocation) const2118 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
2119 {
2120 FrameView* view = m_frame->view();
2121 if (!view)
2122 return false;
2123 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
2124 IntSize delta = dragLocation - m_mouseDownPos;
2125
2126 int threshold = GeneralDragHysteresis;
2127 if (dragState().m_dragSrcIsImage)
2128 threshold = ImageDragHysteresis;
2129 else if (dragState().m_dragSrcIsLink)
2130 threshold = LinkDragHysteresis;
2131 else if (dragState().m_dragSrcInSelection)
2132 threshold = TextDragHysteresis;
2133
2134 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
2135 }
2136
freeClipboard()2137 void EventHandler::freeClipboard()
2138 {
2139 if (dragState().m_dragClipboard)
2140 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
2141 }
2142
shouldDragAutoNode(Node * node,const IntPoint & point) const2143 bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const
2144 {
2145 if (!node || node->hasChildNodes() || !m_frame->view())
2146 return false;
2147 Page* page = m_frame->page();
2148 return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point);
2149 }
2150
dragSourceMovedTo(const PlatformMouseEvent & event)2151 void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event)
2152 {
2153 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
2154 // for now we don't care if event handler cancels default behavior, since there is none
2155 dispatchDragSrcEvent(eventNames().dragEvent, event);
2156 }
2157
dragSourceEndedAt(const PlatformMouseEvent & event,DragOperation operation)2158 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
2159 {
2160 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
2161 dragState().m_dragClipboard->setDestinationOperation(operation);
2162 // for now we don't care if event handler cancels default behavior, since there is none
2163 dispatchDragSrcEvent(eventNames().dragendEvent, event);
2164 }
2165 freeClipboard();
2166 dragState().m_dragSrc = 0;
2167 // In case the drag was ended due to an escape key press we need to ensure
2168 // that consecutive mousemove events don't reinitiate the drag and drop.
2169 m_mouseDownMayStartDrag = false;
2170 }
2171
2172 // returns if we should continue "default processing", i.e., whether eventhandler canceled
dispatchDragSrcEvent(const AtomicString & eventType,const PlatformMouseEvent & event)2173 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
2174 {
2175 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
2176 }
2177
handleDrag(const MouseEventWithHitTestResults & event)2178 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
2179 {
2180 if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) {
2181 // If we allowed the other side of the bridge to handle a drag
2182 // last time, then m_mousePressed might still be set. So we
2183 // clear it now to make sure the next move after a drag
2184 // doesn't look like a drag.
2185 m_mousePressed = false;
2186 return false;
2187 }
2188
2189 if (eventLoopHandleMouseDragged(event))
2190 return true;
2191
2192 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
2193
2194 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2195 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA);
2196 if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA)
2197 m_mouseDownMayStartDrag = false; // no element is draggable
2198 }
2199
2200 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2201 // try to find an element that wants to be dragged
2202 HitTestRequest request(HitTestRequest::ReadOnly);
2203 HitTestResult result(m_mouseDownPos);
2204 m_frame->contentRenderer()->layer()->hitTest(request, result);
2205 Node* node = result.innerNode();
2206 if (node && node->renderer())
2207 dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
2208 m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML);
2209 else
2210 dragState().m_dragSrc = 0;
2211
2212 if (!dragState().m_dragSrc)
2213 m_mouseDownMayStartDrag = false; // no element is draggable
2214 else {
2215 // remember some facts about this source, while we have a HitTestResult handy
2216 node = result.URLElement();
2217 dragState().m_dragSrcIsLink = node && node->isLink();
2218
2219 node = result.innerNonSharedNode();
2220 dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
2221
2222 dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
2223 }
2224 }
2225
2226 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
2227 // or else we bail on the dragging stuff and allow selection to occur
2228 if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
2229 m_mouseDownMayStartDrag = false;
2230 dragState().m_dragSrc = 0;
2231 // ...but if this was the first click in the window, we don't even want to start selection
2232 if (eventActivatedView(event.event()))
2233 m_mouseDownMayStartSelect = false;
2234 }
2235
2236 if (!m_mouseDownMayStartDrag)
2237 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
2238
2239 // We are starting a text/image/url drag, so the cursor should be an arrow
2240 if (FrameView* view = m_frame->view())
2241 view->setCursor(pointerCursor());
2242
2243 if (!dragHysteresisExceeded(event.event().pos()))
2244 return true;
2245
2246 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2247 invalidateClick();
2248
2249 DragOperation srcOp = DragOperationNone;
2250
2251 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
2252 // to make sure it gets numbified
2253 dragState().m_dragClipboard = createDraggingClipboard();
2254
2255 if (dragState().m_dragSrcMayBeDHTML) {
2256 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
2257 // image and offset
2258 if (dragState().m_dragSrcIsDHTML) {
2259 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
2260 // FIXME: This doesn't work correctly with transforms.
2261 FloatPoint absPos = renderer->localToAbsolute();
2262 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
2263 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta);
2264 } else {
2265 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
2266 // the element in some way. In this case we just kill the drag.
2267 m_mouseDownMayStartDrag = false;
2268 goto cleanupDrag;
2269 }
2270 }
2271
2272 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
2273 && !m_frame->selection()->isInPasswordField();
2274
2275 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
2276 // image can still be changed as we drag, but not the pasteboard data.
2277 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
2278
2279 if (m_mouseDownMayStartDrag) {
2280 // gather values from DHTML element, if it set any
2281 dragState().m_dragClipboard->sourceOperation(srcOp);
2282
2283 // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with
2284 // dragImage! Because of that dumb reentrancy, we may think we've not started the
2285 // drag when that happens. So we have to assume it's started before we kick it off.
2286 dragState().m_dragClipboard->setDragHasStarted();
2287 }
2288 }
2289
2290 if (m_mouseDownMayStartDrag) {
2291 Page* page = m_frame->page();
2292 DragController* dragController = page ? page->dragController() : 0;
2293 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
2294 if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
2295 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
2296 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
2297 m_mouseDownMayStartDrag = false;
2298 }
2299 }
2300
2301 cleanupDrag:
2302 if (!m_mouseDownMayStartDrag) {
2303 // something failed to start the drag, cleanup
2304 freeClipboard();
2305 dragState().m_dragSrc = 0;
2306 }
2307
2308 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2309 return true;
2310 }
2311
handleTextInputEvent(const String & text,Event * underlyingEvent,bool isLineBreak,bool isBackTab)2312 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab)
2313 {
2314 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
2315 // and avoid dispatching text input events from keydown default handlers.
2316 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
2317
2318 if (!m_frame)
2319 return false;
2320
2321 EventTarget* target;
2322 if (underlyingEvent)
2323 target = underlyingEvent->target();
2324 else
2325 target = eventTargetNodeForDocument(m_frame->document());
2326 if (!target)
2327 return false;
2328
2329 if (FrameView* view = m_frame->view())
2330 view->resetDeferredRepaintDelay();
2331
2332 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text);
2333 event->setUnderlyingEvent(underlyingEvent);
2334 event->setIsLineBreak(isLineBreak);
2335 event->setIsBackTab(isBackTab);
2336 ExceptionCode ec;
2337 target->dispatchEvent(event, ec);
2338 return event->defaultHandled();
2339 }
2340
2341
2342 #if !PLATFORM(MAC) && !PLATFORM(QT)
invertSenseOfTabsToLinks(KeyboardEvent *) const2343 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const
2344 {
2345 return false;
2346 }
2347 #endif
2348
tabsToLinks(KeyboardEvent * event) const2349 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
2350 {
2351 Page* page = m_frame->page();
2352 if (!page)
2353 return false;
2354
2355 if (page->chrome()->client()->tabsToLinks())
2356 return !invertSenseOfTabsToLinks(event);
2357
2358 return invertSenseOfTabsToLinks(event);
2359 }
2360
defaultTextInputEventHandler(TextEvent * event)2361 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
2362 {
2363 String data = event->data();
2364 if (data == "\n") {
2365 if (event->isLineBreak()) {
2366 if (m_frame->editor()->insertLineBreak())
2367 event->setDefaultHandled();
2368 } else {
2369 if (m_frame->editor()->insertParagraphSeparator())
2370 event->setDefaultHandled();
2371 }
2372 } else {
2373 if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, event))
2374 event->setDefaultHandled();
2375 }
2376 }
2377
2378 #if PLATFORM(QT) || PLATFORM(MAC) || PLATFORM(ANDROID)
2379
2380 // These two platforms handle the space event in the platform-specific WebKit code.
2381 // Eventually it would be good to eliminate that and use the code here instead, but
2382 // the Qt version is inside an ifdef and the Mac version has some extra behavior
2383 // so we can't unify everything yet.
defaultSpaceEventHandler(KeyboardEvent *)2384 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
2385 {
2386 }
2387
2388 #else
2389
defaultSpaceEventHandler(KeyboardEvent * event)2390 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
2391 {
2392 ScrollDirection direction = event->shiftKey() ? ScrollUp : ScrollDown;
2393 if (scrollOverflow(direction, ScrollByPage)) {
2394 event->setDefaultHandled();
2395 return;
2396 }
2397
2398 FrameView* view = m_frame->view();
2399 if (!view)
2400 return;
2401
2402 if (view->scroll(direction, ScrollByPage))
2403 event->setDefaultHandled();
2404 }
2405
2406 #endif
2407
defaultTabEventHandler(KeyboardEvent * event)2408 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
2409 {
2410 // We should only advance focus on tabs if no special modifier keys are held down.
2411 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
2412 return;
2413
2414 Page* page = m_frame->page();
2415 if (!page)
2416 return;
2417 if (!page->tabKeyCyclesThroughElements())
2418 return;
2419
2420 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
2421
2422 // Tabs can be used in design mode editing.
2423 if (m_frame->document()->inDesignMode())
2424 return;
2425
2426 if (page->focusController()->advanceFocus(focusDirection, event))
2427 event->setDefaultHandled();
2428 }
2429
capsLockStateMayHaveChanged()2430 void EventHandler::capsLockStateMayHaveChanged()
2431 {
2432 Document* d = m_frame->document();
2433 if (Node* node = d->focusedNode()) {
2434 if (RenderObject* r = node->renderer()) {
2435 if (r->isTextField())
2436 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
2437 }
2438 }
2439 }
2440
sendResizeEvent()2441 void EventHandler::sendResizeEvent()
2442 {
2443 m_frame->document()->dispatchWindowEvent(eventNames().resizeEvent, false, false);
2444 }
2445
sendScrollEvent()2446 void EventHandler::sendScrollEvent()
2447 {
2448 FrameView* v = m_frame->view();
2449 if (!v)
2450 return;
2451 v->setWasScrolledByUser(true);
2452 m_frame->document()->dispatchEvent(eventNames().scrollEvent, true, false);
2453 }
2454
passMousePressEventToScrollbar(MouseEventWithHitTestResults & mev,Scrollbar * scrollbar)2455 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
2456 {
2457 if (!scrollbar || !scrollbar->enabled())
2458 return false;
2459 return scrollbar->mouseDown(mev.event());
2460 }
2461
2462 #if ENABLE(TOUCH_EVENTS) // Android
handleTouchEvent(const PlatformTouchEvent & e)2463 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e)
2464 {
2465 // only handle the touch event in the top frame handler
2466 if (m_frame->tree()->parent(true))
2467 return m_frame->tree()->parent()->eventHandler()->handleTouchEvent(e);
2468
2469 Document* doc = m_frame->document();
2470 if (!doc)
2471 return false;
2472
2473 RenderObject* docRenderer = doc->renderer();
2474 if (!docRenderer)
2475 return false;
2476
2477 if (doc->touchEventListeners().size() == 0)
2478 return false;
2479
2480 TouchEventType type = e.eventType();
2481 if (type == TouchEventStart) {
2482 Frame* frame = m_frame;
2483 IntPoint vPoint = frame->view()->windowToContents(e.pos());
2484 HitTestRequest request(HitTestRequest::ReadOnly);
2485 HitTestResult result(vPoint);
2486 frame->contentRenderer()->layer()->hitTest(request, result);
2487 Node* node = result.innerNode();
2488 if (node) {
2489 RenderObject* target = node->renderer();
2490 while (target && target->isWidget()) {
2491 Widget* widget = static_cast<RenderWidget*>(target)->widget();
2492 if (widget->isFrameView()) {
2493 frame = static_cast<FrameView*>(widget)->frame();
2494 vPoint = frame->view()->windowToContents(e.pos());
2495 HitTestResult ret(vPoint);
2496 frame->contentRenderer()->layer()->hitTest(request, ret);
2497 node = ret.innerNode();
2498 if (!node)
2499 break;
2500 else
2501 target = node->renderer();
2502 } else
2503 // plugin view??
2504 break;
2505 }
2506 }
2507
2508 if (!node) {
2509 // reset to the top document node
2510 node = doc;
2511 frame = m_frame;
2512 vPoint = frame->view()->windowToContents(e.pos());
2513 }
2514
2515 m_touch = Touch::create(frame, node, 0,
2516 e.x(), e.y(), vPoint.x(), vPoint.y());
2517 } else if (m_touch) {
2518 if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) &&
2519 (e.y() == m_touch->screenY())) {
2520 // don't trigger the event if it hasn't really moved
2521 return false;
2522 }
2523
2524 IntPoint vPoint = m_touch->frame()->view()->windowToContents(e.pos());
2525 m_touch->updateLocation(e.x(), e.y(), vPoint.x(), vPoint.y());
2526 } else {
2527 return false;
2528 }
2529
2530 RefPtr<TouchList> touchList = TouchList::create();
2531 touchList->append(m_touch);
2532 // For TouchEventEnd, touches and targetTouches are empty list
2533 RefPtr<TouchList> emptyList = TouchList::create();
2534 RefPtr<TouchEvent> te;
2535 switch(type) {
2536 case TouchEventStart:
2537 te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
2538 eventNames().touchstartEvent, m_touch->frame()->document()->defaultView(),
2539 m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
2540 break;
2541
2542 case TouchEventEnd:
2543 te = TouchEvent::create(emptyList.get(), emptyList.get(), touchList.get(),
2544 eventNames().touchendEvent, m_touch->frame()->document()->defaultView(),
2545 m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
2546 break;
2547
2548 case TouchEventMove:
2549 te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
2550 eventNames().touchmoveEvent, m_touch->frame()->document()->defaultView(),
2551 m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
2552 break;
2553
2554 case TouchEventCancel:
2555 te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
2556 eventNames().touchcancelEvent, m_touch->frame()->document()->defaultView(),
2557 m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
2558 break;
2559
2560 default:
2561 return false;
2562 }
2563 ExceptionCode ec = 0;
2564 m_touch->target()->dispatchEvent(te.get(), ec);
2565 if (type == TouchEventEnd || type == TouchEventCancel) {
2566 m_touch = 0;
2567 }
2568 return te->defaultPrevented();
2569 }
2570 #endif
2571
2572 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
2573 // last to scrollbar if setLast is true; else set last to 0.
updateLastScrollbarUnderMouse(Scrollbar * scrollbar,bool setLast)2574 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
2575 {
2576 if (m_lastScrollbarUnderMouse != scrollbar) {
2577 // Send mouse exited to the old scrollbar.
2578 if (m_lastScrollbarUnderMouse)
2579 m_lastScrollbarUnderMouse->mouseExited();
2580 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
2581 }
2582 }
2583
2584 }
2585