1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 "Chrome.h"
33 #include "ChromeClient.h"
34 #include "Cursor.h"
35 #include "CursorList.h"
36 #include "Document.h"
37 #include "DragController.h"
38 #include "Editor.h"
39 #include "EventNames.h"
40 #include "EventQueue.h"
41 #include "FloatPoint.h"
42 #include "FloatRect.h"
43 #include "FocusController.h"
44 #include "Frame.h"
45 #include "FrameLoader.h"
46 #include "FrameTree.h"
47 #include "FrameView.h"
48 #include "htmlediting.h"
49 #include "HTMLFrameElementBase.h"
50 #include "HTMLFrameSetElement.h"
51 #include "HTMLInputElement.h"
52 #include "HTMLNames.h"
53 #include "HitTestRequest.h"
54 #include "HitTestResult.h"
55 #include "Image.h"
56 #include "InspectorInstrumentation.h"
57 #include "KeyboardEvent.h"
58 #include "MouseEvent.h"
59 #include "MouseEventWithHitTestResults.h"
60 #include "Page.h"
61 #include "PlatformKeyboardEvent.h"
62 #include "PlatformWheelEvent.h"
63 #include "PluginDocument.h"
64 #include "RenderFrameSet.h"
65 #include "RenderLayer.h"
66 #include "RenderTextControlSingleLine.h"
67 #include "RenderView.h"
68 #include "RenderWidget.h"
69 #include "ScrollAnimator.h"
70 #include "Scrollbar.h"
71 #include "SelectionController.h"
72 #include "Settings.h"
73 #include "StyleCachedImage.h"
74 #include "TextEvent.h"
75 #include "TextIterator.h"
76 #include "UserGestureIndicator.h"
77 #include "UserTypingGestureIndicator.h"
78 #include "WheelEvent.h"
79 #include "WindowsKeyboardCodes.h"
80 #include <wtf/CurrentTime.h>
81 #include <wtf/StdLibExtras.h>
82
83 #if ENABLE(GESTURE_EVENTS)
84 #include "PlatformGestureEvent.h"
85 #endif
86
87 #if ENABLE(SVG)
88 #include "SVGDocument.h"
89 #include "SVGElementInstance.h"
90 #include "SVGNames.h"
91 #include "SVGUseElement.h"
92 #endif
93
94 #if ENABLE(TOUCH_EVENTS)
95 #include "PlatformTouchEvent.h"
96 #include "TouchEvent.h"
97 #endif
98
99 #if ENABLE(GESTURE_RECOGNIZER)
100 #include "PlatformGestureRecognizer.h"
101 #endif
102
103 namespace WebCore {
104
105 using namespace HTMLNames;
106
107 #if ENABLE(DRAG_SUPPORT)
108 // The link drag hysteresis is much larger than the others because there
109 // needs to be enough space to cancel the link press without starting a link drag,
110 // and because dragging links is rare.
111 const int LinkDragHysteresis = 40;
112 const int ImageDragHysteresis = 5;
113 const int TextDragHysteresis = 3;
114 const int GeneralDragHysteresis = 3;
115 #endif // ENABLE(DRAG_SUPPORT)
116
117 // Match key code of composition keydown event on windows.
118 // IE sends VK_PROCESSKEY which has value 229;
119 const int CompositionEventKeyCode = 229;
120
121 #if ENABLE(SVG)
122 using namespace SVGNames;
123 #endif
124
125 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
126 const double autoscrollInterval = 0.05;
127
128 const double fakeMouseMoveInterval = 0.1;
129
scrollNode(float delta,WheelEvent::Granularity granularity,ScrollDirection positiveDirection,ScrollDirection negativeDirection,Node * node,Node ** stopNode)130 static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
131 {
132 if (!delta)
133 return false;
134
135 if (!node->renderer())
136 return false;
137
138 // Find the nearest enclosing box.
139 RenderBox* enclosingBox = node->renderer()->enclosingBox();
140
141 float absDelta = delta > 0 ? delta : -delta;
142
143 if (granularity == WheelEvent::Page)
144 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode);
145
146 if (granularity == WheelEvent::Line)
147 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode);
148
149 if (granularity == WheelEvent::Pixel)
150 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode);
151
152 return false;
153 }
154
155 #if !PLATFORM(MAC)
156
eventLoopHandleMouseUp(const MouseEventWithHitTestResults &)157 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
158 {
159 return false;
160 }
161
162 #if ENABLE(DRAG_SUPPORT)
eventLoopHandleMouseDragged(const MouseEventWithHitTestResults &)163 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
164 {
165 return false;
166 }
167 #endif
168
169 #endif
170
EventHandler(Frame * frame)171 EventHandler::EventHandler(Frame* frame)
172 : m_frame(frame)
173 , m_mousePressed(false)
174 , m_capturesDragging(false)
175 , m_mouseDownMayStartSelect(false)
176 #if ENABLE(DRAG_SUPPORT)
177 , m_mouseDownMayStartDrag(false)
178 #endif
179 , m_mouseDownWasSingleClickInSelection(false)
180 , m_beganSelectingText(false)
181 , m_panScrollInProgress(false)
182 , m_panScrollButtonPressed(false)
183 , m_springLoadedPanScrollInProgress(false)
184 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
185 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
186 , m_autoscrollRenderer(0)
187 , m_autoscrollInProgress(false)
188 , m_mouseDownMayStartAutoscroll(false)
189 , m_mouseDownWasInSubframe(false)
190 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
191 #if ENABLE(SVG)
192 , m_svgPan(false)
193 #endif
194 , m_resizeLayer(0)
195 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
196 , m_clickCount(0)
197 , m_mouseDownTimestamp(0)
198 , m_useLatchedWheelEventNode(false)
199 , m_widgetIsLatched(false)
200 #if PLATFORM(MAC)
201 , m_mouseDownView(nil)
202 , m_sendingEventToSubview(false)
203 , m_activationEventNumber(-1)
204 #endif
205 #if ENABLE(TOUCH_EVENTS)
206 , m_touchPressed(false)
207 #endif
208 #if ENABLE(GESTURE_RECOGNIZER)
209 , m_gestureRecognizer(PlatformGestureRecognizer::create())
210 #endif
211 {
212 }
213
~EventHandler()214 EventHandler::~EventHandler()
215 {
216 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
217 }
218
219 #if ENABLE(DRAG_SUPPORT)
dragState()220 EventHandler::EventHandlerDragState& EventHandler::dragState()
221 {
222 DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
223 return state;
224 }
225 #endif // ENABLE(DRAG_SUPPORT)
226
clear()227 void EventHandler::clear()
228 {
229 m_hoverTimer.stop();
230 m_fakeMouseMoveEventTimer.stop();
231 m_resizeLayer = 0;
232 m_nodeUnderMouse = 0;
233 m_lastNodeUnderMouse = 0;
234 #if ENABLE(SVG)
235 m_instanceUnderMouse = 0;
236 m_lastInstanceUnderMouse = 0;
237 #endif
238 m_lastMouseMoveEventSubframe = 0;
239 m_lastScrollbarUnderMouse = 0;
240 m_clickCount = 0;
241 m_clickNode = 0;
242 m_frameSetBeingResized = 0;
243 #if ENABLE(DRAG_SUPPORT)
244 m_dragTarget = 0;
245 m_shouldOnlyFireDragOverEvent = false;
246 #endif
247 m_currentMousePosition = IntPoint();
248 m_mousePressNode = 0;
249 m_mousePressed = false;
250 m_capturesDragging = false;
251 m_capturingMouseEventsNode = 0;
252 m_latchedWheelEventNode = 0;
253 m_previousWheelScrolledNode = 0;
254 #if ENABLE(TOUCH_EVENTS)
255 m_originatingTouchPointTargets.clear();
256 #endif
257 }
258
setSelectionIfNeeded(SelectionController * selection,const VisibleSelection & newSelection)259 static void setSelectionIfNeeded(SelectionController* selection, const VisibleSelection& newSelection)
260 {
261 ASSERT(selection);
262 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
263 selection->setSelection(newSelection);
264 }
265
setNonDirectionalSelectionIfNeeded(SelectionController * selection,const VisibleSelection & newSelection,TextGranularity granularity)266 static void setNonDirectionalSelectionIfNeeded(SelectionController* selection, const VisibleSelection& newSelection, TextGranularity granularity)
267 {
268 ASSERT(selection);
269 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
270 selection->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
271 }
272
selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults & result)273 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
274 {
275 Node* innerNode = targetNode(result);
276 VisibleSelection newSelection;
277
278 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
279 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
280 TextGranularity granularity = CharacterGranularity;
281 if (pos.isNotNull()) {
282 newSelection = VisibleSelection(pos);
283 newSelection.expandUsingGranularity(WordGranularity);
284 }
285
286 if (newSelection.isRange()) {
287 granularity = WordGranularity;
288 m_beganSelectingText = true;
289 if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
290 newSelection.appendTrailingWhitespace();
291 }
292
293 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
294 }
295 }
296
selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults & result)297 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
298 {
299 if (!result.hitTestResult().isLiveLink())
300 return selectClosestWordFromMouseEvent(result);
301
302 Node* innerNode = targetNode(result);
303
304 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
305 VisibleSelection newSelection;
306 Element* URLElement = result.hitTestResult().URLElement();
307 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
308 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
309 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
310
311 TextGranularity granularity = CharacterGranularity;
312 if (newSelection.isRange()) {
313 granularity = WordGranularity;
314 m_beganSelectingText = true;
315 }
316
317 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
318 }
319 }
320
handleMousePressEventDoubleClick(const MouseEventWithHitTestResults & event)321 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
322 {
323 if (event.event().button() != LeftButton)
324 return false;
325
326 if (m_frame->selection()->isRange())
327 // A double-click when range is already selected
328 // should not change the selection. So, do not call
329 // selectClosestWordFromMouseEvent, but do set
330 // m_beganSelectingText to prevent handleMouseReleaseEvent
331 // from setting caret selection.
332 m_beganSelectingText = true;
333 else
334 selectClosestWordFromMouseEvent(event);
335
336 return true;
337 }
338
handleMousePressEventTripleClick(const MouseEventWithHitTestResults & event)339 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
340 {
341 if (event.event().button() != LeftButton)
342 return false;
343
344 Node* innerNode = targetNode(event);
345 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
346 return false;
347
348 VisibleSelection newSelection;
349 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
350 if (pos.isNotNull()) {
351 newSelection = VisibleSelection(pos);
352 newSelection.expandUsingGranularity(ParagraphGranularity);
353 }
354
355 TextGranularity granularity = CharacterGranularity;
356 if (newSelection.isRange()) {
357 granularity = ParagraphGranularity;
358 m_beganSelectingText = true;
359 }
360
361 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
362
363 return true;
364 }
365
textDistance(const Position & start,const Position & end)366 static int textDistance(const Position& start, const Position& end)
367 {
368 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
369 return TextIterator::rangeLength(range.get(), true);
370 }
371
handleMousePressEventSingleClick(const MouseEventWithHitTestResults & event)372 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
373 {
374 Node* innerNode = targetNode(event);
375 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
376 return false;
377
378 // Extend the selection if the Shift key is down, unless the click is in a link.
379 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
380
381 // Don't restart the selection when the mouse is pressed on an
382 // existing selection so we can allow for text dragging.
383 if (FrameView* view = m_frame->view()) {
384 IntPoint vPoint = view->windowToContents(event.event().pos());
385 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
386 m_mouseDownWasSingleClickInSelection = true;
387 return false;
388 }
389 }
390
391 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
392 if (visiblePos.isNull())
393 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
394 Position pos = visiblePos.deepEquivalent();
395
396 VisibleSelection newSelection = m_frame->selection()->selection();
397 TextGranularity granularity = CharacterGranularity;
398
399 if (extendSelection && newSelection.isCaretOrRange()) {
400 m_frame->selection()->setIsDirectional(false);
401
402 ASSERT(m_frame->settings());
403 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
404 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
405 // was created right-to-left
406 Position start = newSelection.start();
407 Position end = newSelection.end();
408 int distanceToStart = textDistance(start, pos);
409 int distanceToEnd = textDistance(pos, end);
410 if (distanceToStart <= distanceToEnd)
411 newSelection = VisibleSelection(end, pos);
412 else
413 newSelection = VisibleSelection(start, pos);
414 } else {
415 newSelection.setExtent(pos);
416 }
417
418 if (m_frame->selection()->granularity() != CharacterGranularity) {
419 granularity = m_frame->selection()->granularity();
420 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
421 }
422
423 m_beganSelectingText = true;
424 } else
425 newSelection = VisibleSelection(visiblePos);
426
427 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
428
429 return true;
430 }
431
handleMousePressEvent(const MouseEventWithHitTestResults & event)432 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
433 {
434 #if ENABLE(DRAG_SUPPORT)
435 // Reset drag state.
436 dragState().m_dragSrc = 0;
437 #endif
438
439 cancelFakeMouseMoveEvent();
440
441 if (ScrollView* scrollView = m_frame->view()) {
442 if (scrollView->isPointInScrollbarCorner(event.event().pos()))
443 return false;
444 }
445
446 bool singleClick = event.event().clickCount() <= 1;
447
448 // If we got the event back, that must mean it wasn't prevented,
449 // so it's allowed to start a drag or selection.
450 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
451
452 #if ENABLE(DRAG_SUPPORT)
453 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
454 m_mouseDownMayStartDrag = singleClick;
455 #endif
456
457 m_mouseDownWasSingleClickInSelection = false;
458
459 m_mouseDown = event.event();
460
461 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
462 return true;
463
464 #if ENABLE(SVG)
465 if (m_frame->document()->isSVGDocument()
466 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
467 if (event.event().shiftKey() && singleClick) {
468 m_svgPan = true;
469 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
470 return true;
471 }
472 }
473 #endif
474
475 // We don't do this at the start of mouse down handling,
476 // because we don't want to do it until we know we didn't hit a widget.
477 if (singleClick)
478 focusDocumentView();
479
480 Node* innerNode = targetNode(event);
481
482 m_mousePressNode = innerNode;
483 #if ENABLE(DRAG_SUPPORT)
484 m_dragStartPos = event.event().pos();
485 #endif
486
487 bool swallowEvent = false;
488 m_mousePressed = true;
489 m_beganSelectingText = false;
490
491 if (event.event().clickCount() == 2)
492 swallowEvent = handleMousePressEventDoubleClick(event);
493 else if (event.event().clickCount() >= 3)
494 swallowEvent = handleMousePressEventTripleClick(event);
495 else
496 swallowEvent = handleMousePressEventSingleClick(event);
497
498 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
499 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
500
501 return swallowEvent;
502 }
503
504 // There are two kinds of renderer that can autoscroll.
canAutoscroll(RenderObject * renderer)505 static bool canAutoscroll(RenderObject* renderer)
506 {
507 if (!renderer->isBox())
508 return false;
509
510 // Check for a box that can be scrolled in its own right.
511 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
512 return true;
513
514 // Check for a box that represents the top level of a web page.
515 // This can be scrolled by calling Chrome::scrollRectIntoView.
516 // This only has an effect on the Mac platform in applications
517 // that put web views into scrolling containers, such as Mac OS X Mail.
518 // The code for this is in RenderLayer::scrollRectToVisible.
519 if (renderer->node() != renderer->document())
520 return false;
521 Frame* frame = renderer->frame();
522 if (!frame)
523 return false;
524 Page* page = frame->page();
525 return page && page->mainFrame() == frame;
526 }
527
528 #if ENABLE(DRAG_SUPPORT)
handleMouseDraggedEvent(const MouseEventWithHitTestResults & event)529 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
530 {
531 if (handleDrag(event))
532 return true;
533
534 if (!m_mousePressed)
535 return false;
536
537 Node* targetNode = EventHandler::targetNode(event);
538 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
539 return false;
540
541 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
542 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
543 #endif
544
545 m_mouseDownMayStartDrag = false;
546
547 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
548 // Find a renderer that can autoscroll.
549 RenderObject* renderer = targetNode->renderer();
550 while (renderer && !canAutoscroll(renderer)) {
551 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
552 renderer = renderer->document()->ownerElement()->renderer();
553 else
554 renderer = renderer->parent();
555 }
556
557 if (renderer) {
558 m_autoscrollInProgress = true;
559 handleAutoscroll(renderer);
560 }
561
562 m_mouseDownMayStartAutoscroll = false;
563 }
564
565 if (!m_beganSelectingText) {
566 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
567 HitTestResult result(m_mouseDownPos);
568 m_frame->document()->renderView()->layer()->hitTest(request, result);
569
570 updateSelectionForMouseDrag(result);
571 }
572 updateSelectionForMouseDrag(event.hitTestResult());
573 return true;
574 }
575
eventMayStartDrag(const PlatformMouseEvent & event) const576 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
577 {
578 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
579 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
580 // in handleMousePressEvent
581
582 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
583 return false;
584
585 if (event.button() != LeftButton || event.clickCount() != 1)
586 return false;
587
588 bool DHTMLFlag;
589 bool UAFlag;
590 allowDHTMLDrag(DHTMLFlag, UAFlag);
591 if (!DHTMLFlag && !UAFlag)
592 return false;
593
594 FrameView* view = m_frame->view();
595 if (!view)
596 return false;
597
598 HitTestRequest request(HitTestRequest::ReadOnly);
599 HitTestResult result(view->windowToContents(event.pos()));
600 m_frame->contentRenderer()->layer()->hitTest(request, result);
601 bool srcIsDHTML;
602 return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
603 }
604
updateSelectionForMouseDrag()605 void EventHandler::updateSelectionForMouseDrag()
606 {
607 FrameView* view = m_frame->view();
608 if (!view)
609 return;
610 RenderView* renderer = m_frame->contentRenderer();
611 if (!renderer)
612 return;
613 RenderLayer* layer = renderer->layer();
614 if (!layer)
615 return;
616
617 HitTestRequest request(HitTestRequest::ReadOnly |
618 HitTestRequest::Active |
619 HitTestRequest::MouseMove);
620 HitTestResult result(view->windowToContents(m_currentMousePosition));
621 layer->hitTest(request, result);
622 updateSelectionForMouseDrag(result);
623 }
624
selectionExtentRespectingEditingBoundary(const VisibleSelection & selection,const IntPoint & localPoint,Node * targetNode)625 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const IntPoint& localPoint, Node* targetNode)
626 {
627 IntPoint selectionEndPoint = localPoint;
628 Element* editableElement = selection.rootEditableElement();
629
630 if (!targetNode->renderer())
631 return VisiblePosition();
632
633 if (editableElement && !editableElement->contains(targetNode)) {
634 if (!editableElement->renderer())
635 return VisiblePosition();
636
637 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
638 selectionEndPoint = roundedIntPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
639 targetNode = editableElement;
640 }
641
642 return targetNode->renderer()->positionForPoint(selectionEndPoint);
643 }
644
updateSelectionForMouseDrag(const HitTestResult & hitTestResult)645 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
646 {
647 if (!m_mouseDownMayStartSelect)
648 return;
649
650 Node* target = targetNode(hitTestResult);
651 if (!target)
652 return;
653
654 if (!canMouseDragExtendSelect(target))
655 return;
656
657 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
658
659 // Don't modify the selection if we're not on a node.
660 if (targetPosition.isNull())
661 return;
662
663 // Restart the selection if this is the first mouse move. This work is usually
664 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
665 VisibleSelection newSelection = m_frame->selection()->selection();
666
667 #if ENABLE(SVG)
668 // Special case to limit selection to the containing block for SVG text.
669 // FIXME: Isn't there a better non-SVG-specific way to do this?
670 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
671 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
672 if (selectionBaseRenderer->isSVGText())
673 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
674 return;
675 #endif
676
677 if (!m_beganSelectingText) {
678 m_beganSelectingText = true;
679 newSelection = VisibleSelection(targetPosition);
680 }
681
682 newSelection.setExtent(targetPosition);
683 if (m_frame->selection()->granularity() != CharacterGranularity)
684 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
685
686 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, m_frame->selection()->granularity());
687 }
688 #endif // ENABLE(DRAG_SUPPORT)
689
lostMouseCapture()690 void EventHandler::lostMouseCapture()
691 {
692 m_frame->selection()->setCaretBlinkingSuspended(false);
693 }
694
handleMouseUp(const MouseEventWithHitTestResults & event)695 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
696 {
697 if (eventLoopHandleMouseUp(event))
698 return true;
699
700 // If this was the first click in the window, we don't even want to clear the selection.
701 // This case occurs when the user clicks on a draggable element, since we have to process
702 // the mouse down and drag events to see if we might start a drag. For other first clicks
703 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
704 // ignored upstream of this layer.
705 return eventActivatedView(event.event());
706 }
707
handleMouseReleaseEvent(const MouseEventWithHitTestResults & event)708 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
709 {
710 if (m_autoscrollInProgress)
711 stopAutoscrollTimer();
712
713 if (handleMouseUp(event))
714 return true;
715
716 // Used to prevent mouseMoveEvent from initiating a drag before
717 // the mouse is pressed again.
718 m_frame->selection()->setCaretBlinkingSuspended(false);
719 m_mousePressed = false;
720 m_capturesDragging = false;
721 #if ENABLE(DRAG_SUPPORT)
722 m_mouseDownMayStartDrag = false;
723 #endif
724 m_mouseDownMayStartSelect = false;
725 m_mouseDownMayStartAutoscroll = false;
726 m_mouseDownWasInSubframe = false;
727
728 bool handled = false;
729
730 // Clear the selection if the mouse didn't move after the last mouse
731 // press and it's not a context menu click. We do this so when clicking
732 // on the selection, the selection goes away. However, if we are
733 // editing, place the caret.
734 if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
735 #if ENABLE(DRAG_SUPPORT)
736 && m_dragStartPos == event.event().pos()
737 #endif
738 && m_frame->selection()->isRange()
739 && event.event().button() != RightButton) {
740 VisibleSelection newSelection;
741 Node* node = targetNode(event);
742 bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
743 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
744 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
745 newSelection = VisibleSelection(pos);
746 }
747
748 setSelectionIfNeeded(m_frame->selection(), newSelection);
749
750 handled = true;
751 }
752
753 m_frame->selection()->notifyRendererOfSelectionChange(true);
754
755 m_frame->selection()->selectFrameElementInParentIfFullySelected();
756
757 return handled;
758 }
759
handleAutoscroll(RenderObject * renderer)760 void EventHandler::handleAutoscroll(RenderObject* renderer)
761 {
762 // We don't want to trigger the autoscroll or the panScroll if it's already active
763 if (m_autoscrollTimer.isActive())
764 return;
765
766 setAutoscrollRenderer(renderer);
767
768 #if ENABLE(PAN_SCROLLING)
769 if (m_panScrollInProgress) {
770 m_panScrollStartPos = currentMousePosition();
771 if (FrameView* view = m_frame->view())
772 view->addPanScrollIcon(m_panScrollStartPos);
773 // If we're not in the top frame we notify it that we doing a panScroll.
774 if (Page* page = m_frame->page()) {
775 Frame* mainFrame = page->mainFrame();
776 if (m_frame != mainFrame)
777 mainFrame->eventHandler()->m_panScrollInProgress = true;
778 }
779 }
780 #endif
781
782 startAutoscrollTimer();
783 }
784
autoscrollTimerFired(Timer<EventHandler> *)785 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
786 {
787 RenderObject* r = autoscrollRenderer();
788 if (!r || !r->isBox()) {
789 stopAutoscrollTimer();
790 return;
791 }
792
793 if (m_autoscrollInProgress) {
794 if (!m_mousePressed) {
795 stopAutoscrollTimer();
796 return;
797 }
798 toRenderBox(r)->autoscroll();
799 } else {
800 // we verify that the main frame hasn't received the order to stop the panScroll
801 if (Page* page = m_frame->page()) {
802 if (!page->mainFrame()->eventHandler()->m_panScrollInProgress) {
803 stopAutoscrollTimer();
804 return;
805 }
806 }
807 #if ENABLE(PAN_SCROLLING)
808 updatePanScrollState();
809 toRenderBox(r)->panScroll(m_panScrollStartPos);
810 #endif
811 }
812 }
813
814 #if ENABLE(PAN_SCROLLING)
815
startPanScrolling(RenderObject * renderer)816 void EventHandler::startPanScrolling(RenderObject* renderer)
817 {
818 m_panScrollInProgress = true;
819 m_panScrollButtonPressed = true;
820 handleAutoscroll(renderer);
821 invalidateClick();
822 }
823
updatePanScrollState()824 void EventHandler::updatePanScrollState()
825 {
826 FrameView* view = m_frame->view();
827 if (!view)
828 return;
829
830 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
831 // So we don't want to change the cursor over this area
832 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
833 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
834 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
835 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
836
837 if ((east || west || north || south) && m_panScrollButtonPressed)
838 m_springLoadedPanScrollInProgress = true;
839
840 if (north) {
841 if (east)
842 view->setCursor(northEastPanningCursor());
843 else if (west)
844 view->setCursor(northWestPanningCursor());
845 else
846 view->setCursor(northPanningCursor());
847 } else if (south) {
848 if (east)
849 view->setCursor(southEastPanningCursor());
850 else if (west)
851 view->setCursor(southWestPanningCursor());
852 else
853 view->setCursor(southPanningCursor());
854 } else if (east)
855 view->setCursor(eastPanningCursor());
856 else if (west)
857 view->setCursor(westPanningCursor());
858 else
859 view->setCursor(middlePanningCursor());
860 }
861
862 #endif // ENABLE(PAN_SCROLLING)
863
autoscrollRenderer() const864 RenderObject* EventHandler::autoscrollRenderer() const
865 {
866 return m_autoscrollRenderer;
867 }
868
updateAutoscrollRenderer()869 void EventHandler::updateAutoscrollRenderer()
870 {
871 if (!m_autoscrollRenderer)
872 return;
873
874 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
875
876 if (Node* nodeAtPoint = hitTest.innerNode())
877 m_autoscrollRenderer = nodeAtPoint->renderer();
878
879 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
880 m_autoscrollRenderer = m_autoscrollRenderer->parent();
881 }
882
setAutoscrollRenderer(RenderObject * renderer)883 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
884 {
885 m_autoscrollRenderer = renderer;
886 }
887
888 #if ENABLE(DRAG_SUPPORT)
allowDHTMLDrag(bool & flagDHTML,bool & flagUA) const889 void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
890 {
891 flagDHTML = false;
892 flagUA = false;
893
894 if (!m_frame)
895 return;
896
897 Page* page = m_frame->page();
898 if (!page)
899 return;
900
901 FrameView* view = m_frame->view();
902 if (!view)
903 return;
904
905 unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
906 flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
907 flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
908 }
909 #endif // ENABLE(DRAG_SUPPORT)
910
hitTestResultAtPoint(const IntPoint & point,bool allowShadowContent,bool ignoreClipping,HitTestScrollbars testScrollbars,HitTestRequest::HitTestRequestType hitType,const IntSize & padding)911 HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const IntSize& padding)
912 {
913 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
914 if (!m_frame->contentRenderer())
915 return result;
916 if (ignoreClipping)
917 hitType |= HitTestRequest::IgnoreClipping;
918 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
919
920 while (true) {
921 Node* n = result.innerNode();
922 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
923 break;
924 RenderWidget* renderWidget = toRenderWidget(n->renderer());
925 Widget* widget = renderWidget->widget();
926 if (!widget || !widget->isFrameView())
927 break;
928 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
929 if (!frame || !frame->contentRenderer())
930 break;
931 FrameView* view = static_cast<FrameView*>(widget);
932 IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
933 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
934 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width());
935 frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
936 result = widgetHitTestResult;
937
938 if (testScrollbars == ShouldHitTestScrollbars) {
939 Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
940 if (eventScrollbar)
941 result.setScrollbar(eventScrollbar);
942 }
943 }
944
945 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
946 // Another hit test at the main frame level should get us the correct visible result.
947 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
948 if (Page* page = m_frame->page()) {
949 Frame* mainFrame = page->mainFrame();
950 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
951 FrameView* resultView = resultFrame->view();
952 FrameView* mainView = mainFrame->view();
953 if (resultView && mainView) {
954 IntPoint windowPoint = resultView->contentsToWindow(result.point());
955 IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
956 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
957 }
958 }
959 }
960
961 if (!allowShadowContent)
962 result.setToNonShadowAncestor();
963
964 return result;
965 }
966
967
startAutoscrollTimer()968 void EventHandler::startAutoscrollTimer()
969 {
970 m_autoscrollTimer.startRepeating(autoscrollInterval);
971 }
972
stopAutoscrollTimer(bool rendererIsBeingDestroyed)973 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
974 {
975 if (m_autoscrollInProgress) {
976 if (m_mouseDownWasInSubframe) {
977 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
978 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
979 return;
980 }
981 }
982
983 if (autoscrollRenderer()) {
984 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
985 toRenderBox(autoscrollRenderer())->stopAutoscroll();
986 #if ENABLE(PAN_SCROLLING)
987 if (m_panScrollInProgress) {
988 if (FrameView* view = m_frame->view()) {
989 view->removePanScrollIcon();
990 view->setCursor(pointerCursor());
991 }
992 }
993 #endif
994
995 setAutoscrollRenderer(0);
996 }
997
998 m_autoscrollTimer.stop();
999
1000 m_panScrollInProgress = false;
1001 m_springLoadedPanScrollInProgress = false;
1002
1003 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1004 if (Page* page = m_frame->page()) {
1005 Frame* mainFrame = page->mainFrame();
1006 if (m_frame != mainFrame)
1007 mainFrame->eventHandler()->m_panScrollInProgress = false;
1008 }
1009
1010 m_autoscrollInProgress = false;
1011 }
1012
mousePressNode() const1013 Node* EventHandler::mousePressNode() const
1014 {
1015 return m_mousePressNode.get();
1016 }
1017
setMousePressNode(PassRefPtr<Node> node)1018 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1019 {
1020 m_mousePressNode = node;
1021 }
1022
scrollOverflow(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)1023 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1024 {
1025 Node* node = startingNode;
1026
1027 if (!node)
1028 node = m_frame->document()->focusedNode();
1029
1030 if (!node)
1031 node = m_mousePressNode.get();
1032
1033 if (node) {
1034 RenderObject* r = node->renderer();
1035 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1036 setFrameWasScrolledByUser();
1037 return true;
1038 }
1039 }
1040
1041 return false;
1042 }
1043
logicalScrollOverflow(ScrollLogicalDirection direction,ScrollGranularity granularity,Node * startingNode)1044 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1045 {
1046 Node* node = startingNode;
1047
1048 if (!node)
1049 node = m_frame->document()->focusedNode();
1050
1051 if (!node)
1052 node = m_mousePressNode.get();
1053
1054 if (node) {
1055 RenderObject* r = node->renderer();
1056 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1057 setFrameWasScrolledByUser();
1058 return true;
1059 }
1060 }
1061
1062 return false;
1063 }
1064
scrollRecursively(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)1065 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1066 {
1067 // The layout needs to be up to date to determine if we can scroll. We may be
1068 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1069 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1070 if (scrollOverflow(direction, granularity, startingNode))
1071 return true;
1072 Frame* frame = m_frame;
1073 FrameView* view = frame->view();
1074 if (view && view->scroll(direction, granularity))
1075 return true;
1076 frame = frame->tree()->parent();
1077 if (!frame)
1078 return false;
1079 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1080 }
1081
logicalScrollRecursively(ScrollLogicalDirection direction,ScrollGranularity granularity,Node * startingNode)1082 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1083 {
1084 // The layout needs to be up to date to determine if we can scroll. We may be
1085 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1086 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1087 if (logicalScrollOverflow(direction, granularity, startingNode))
1088 return true;
1089 Frame* frame = m_frame;
1090 FrameView* view = frame->view();
1091
1092 bool scrolled = false;
1093 #if PLATFORM(MAC)
1094 // Mac also resets the scroll position in the inline direction.
1095 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1096 scrolled = true;
1097 #endif
1098 if (view && view->logicalScroll(direction, granularity))
1099 scrolled = true;
1100
1101 if (scrolled)
1102 return true;
1103
1104 frame = frame->tree()->parent();
1105 if (!frame)
1106 return false;
1107
1108 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1109 }
1110
currentMousePosition() const1111 IntPoint EventHandler::currentMousePosition() const
1112 {
1113 return m_currentMousePosition;
1114 }
1115
subframeForHitTestResult(const MouseEventWithHitTestResults & hitTestResult)1116 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1117 {
1118 if (!hitTestResult.isOverWidget())
1119 return 0;
1120 return subframeForTargetNode(targetNode(hitTestResult));
1121 }
1122
subframeForTargetNode(Node * node)1123 Frame* EventHandler::subframeForTargetNode(Node* node)
1124 {
1125 if (!node)
1126 return 0;
1127
1128 RenderObject* renderer = node->renderer();
1129 if (!renderer || !renderer->isWidget())
1130 return 0;
1131
1132 Widget* widget = toRenderWidget(renderer)->widget();
1133 if (!widget || !widget->isFrameView())
1134 return 0;
1135
1136 return static_cast<FrameView*>(widget)->frame();
1137 }
1138
isSubmitImage(Node * node)1139 static bool isSubmitImage(Node* node)
1140 {
1141 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1142 }
1143
1144 // Returns true if the node's editable block is not current focused for editing
nodeIsNotBeingEdited(Node * node,Frame * frame)1145 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1146 {
1147 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1148 }
1149
selectCursor(const MouseEventWithHitTestResults & event,Scrollbar * scrollbar)1150 Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1151 {
1152 Node* node = targetNode(event);
1153 RenderObject* renderer = node ? node->renderer() : 0;
1154 RenderStyle* style = renderer ? renderer->style() : 0;
1155
1156 bool horizontalText = !style || style->isHorizontalWritingMode();
1157 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1158
1159 // During selection, use an I-beam no matter what we're over.
1160 // If you're capturing mouse events for a particular node, don't treat this as a selection.
1161 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1162 return iBeam;
1163
1164 if (renderer && renderer->isFrameSet()) {
1165 RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer);
1166 if (frameSetRenderer->canResizeRow(event.localPoint()))
1167 return rowResizeCursor();
1168 if (frameSetRenderer->canResizeColumn(event.localPoint()))
1169 return columnResizeCursor();
1170 }
1171
1172 if (style && style->cursors()) {
1173 const CursorList* cursors = style->cursors();
1174 for (unsigned i = 0; i < cursors->size(); ++i) {
1175 const CachedImage* cimage = 0;
1176 StyleImage* image = (*cursors)[i].image();
1177 if (image && image->isCachedImage())
1178 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1179 if (!cimage)
1180 continue;
1181 IntPoint hotSpot = (*cursors)[i].hotSpot();
1182 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1183 IntSize size = cimage->image()->size();
1184 if (size.width() > 128 || size.height() > 128)
1185 continue;
1186 if (cimage->image()->isNull())
1187 break;
1188 if (!cimage->errorOccurred())
1189 return Cursor(cimage->image(), hotSpot);
1190 }
1191 }
1192
1193 switch (style ? style->cursor() : CURSOR_AUTO) {
1194 case CURSOR_AUTO: {
1195 bool editable = (node && node->rendererIsEditable());
1196 bool editableLinkEnabled = false;
1197
1198 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1199 if (editable) {
1200 ASSERT(m_frame->settings());
1201 switch (m_frame->settings()->editableLinkBehavior()) {
1202 default:
1203 case EditableLinkDefaultBehavior:
1204 case EditableLinkAlwaysLive:
1205 editableLinkEnabled = true;
1206 break;
1207
1208 case EditableLinkNeverLive:
1209 editableLinkEnabled = false;
1210 break;
1211
1212 case EditableLinkLiveWhenNotFocused:
1213 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1214 break;
1215
1216 case EditableLinkOnlyLiveWithShiftKey:
1217 editableLinkEnabled = event.event().shiftKey();
1218 break;
1219 }
1220 }
1221
1222 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1223 return handCursor();
1224 bool inResizer = false;
1225 if (renderer) {
1226 if (RenderLayer* layer = renderer->enclosingLayer()) {
1227 if (FrameView* view = m_frame->view())
1228 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos()));
1229 }
1230 }
1231 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1232 return iBeam;
1233 return pointerCursor();
1234 }
1235 case CURSOR_CROSS:
1236 return crossCursor();
1237 case CURSOR_POINTER:
1238 return handCursor();
1239 case CURSOR_MOVE:
1240 return moveCursor();
1241 case CURSOR_ALL_SCROLL:
1242 return moveCursor();
1243 case CURSOR_E_RESIZE:
1244 return eastResizeCursor();
1245 case CURSOR_W_RESIZE:
1246 return westResizeCursor();
1247 case CURSOR_N_RESIZE:
1248 return northResizeCursor();
1249 case CURSOR_S_RESIZE:
1250 return southResizeCursor();
1251 case CURSOR_NE_RESIZE:
1252 return northEastResizeCursor();
1253 case CURSOR_SW_RESIZE:
1254 return southWestResizeCursor();
1255 case CURSOR_NW_RESIZE:
1256 return northWestResizeCursor();
1257 case CURSOR_SE_RESIZE:
1258 return southEastResizeCursor();
1259 case CURSOR_NS_RESIZE:
1260 return northSouthResizeCursor();
1261 case CURSOR_EW_RESIZE:
1262 return eastWestResizeCursor();
1263 case CURSOR_NESW_RESIZE:
1264 return northEastSouthWestResizeCursor();
1265 case CURSOR_NWSE_RESIZE:
1266 return northWestSouthEastResizeCursor();
1267 case CURSOR_COL_RESIZE:
1268 return columnResizeCursor();
1269 case CURSOR_ROW_RESIZE:
1270 return rowResizeCursor();
1271 case CURSOR_TEXT:
1272 return iBeamCursor();
1273 case CURSOR_WAIT:
1274 return waitCursor();
1275 case CURSOR_HELP:
1276 return helpCursor();
1277 case CURSOR_VERTICAL_TEXT:
1278 return verticalTextCursor();
1279 case CURSOR_CELL:
1280 return cellCursor();
1281 case CURSOR_CONTEXT_MENU:
1282 return contextMenuCursor();
1283 case CURSOR_PROGRESS:
1284 return progressCursor();
1285 case CURSOR_NO_DROP:
1286 return noDropCursor();
1287 case CURSOR_ALIAS:
1288 return aliasCursor();
1289 case CURSOR_COPY:
1290 return copyCursor();
1291 case CURSOR_NONE:
1292 return noneCursor();
1293 case CURSOR_NOT_ALLOWED:
1294 return notAllowedCursor();
1295 case CURSOR_DEFAULT:
1296 return pointerCursor();
1297 case CURSOR_WEBKIT_ZOOM_IN:
1298 return zoomInCursor();
1299 case CURSOR_WEBKIT_ZOOM_OUT:
1300 return zoomOutCursor();
1301 case CURSOR_WEBKIT_GRAB:
1302 return grabCursor();
1303 case CURSOR_WEBKIT_GRABBING:
1304 return grabbingCursor();
1305 }
1306 return pointerCursor();
1307 }
1308
documentPointForWindowPoint(Frame * frame,const IntPoint & windowPoint)1309 static IntPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1310 {
1311 FrameView* view = frame->view();
1312 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1313 // Historically the code would just crash; this is clearly no worse than that.
1314 return view ? view->windowToContents(windowPoint) : windowPoint;
1315 }
1316
targetNode(const MouseEventWithHitTestResults & event)1317 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1318 {
1319 return targetNode(event.hitTestResult());
1320 }
1321
targetNode(const HitTestResult & hitTestResult)1322 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1323 {
1324 Node* node = hitTestResult.innerNode();
1325 if (!node)
1326 return 0;
1327 if (node->inDocument())
1328 return node;
1329
1330 Element* element = node->parentElement();
1331 if (element && element->inDocument())
1332 return element;
1333
1334 return node;
1335
1336 }
1337
handleMousePressEvent(const PlatformMouseEvent & mouseEvent)1338 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1339 {
1340 RefPtr<FrameView> protector(m_frame->view());
1341
1342 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1343
1344 cancelFakeMouseMoveEvent();
1345 m_mousePressed = true;
1346 m_capturesDragging = true;
1347 m_currentMousePosition = mouseEvent.pos();
1348 m_mouseDownTimestamp = mouseEvent.timestamp();
1349 #if ENABLE(DRAG_SUPPORT)
1350 m_mouseDownMayStartDrag = false;
1351 #endif
1352 m_mouseDownMayStartSelect = false;
1353 m_mouseDownMayStartAutoscroll = false;
1354 if (FrameView* view = m_frame->view())
1355 m_mouseDownPos = view->windowToContents(mouseEvent.pos());
1356 else {
1357 invalidateClick();
1358 return false;
1359 }
1360 m_mouseDownWasInSubframe = false;
1361
1362 HitTestRequest request(HitTestRequest::Active);
1363 // Save the document point we generate in case the window coordinate is invalidated by what happens
1364 // when we dispatch the event.
1365 IntPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos());
1366 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1367
1368 if (!targetNode(mev)) {
1369 invalidateClick();
1370 return false;
1371 }
1372
1373 m_mousePressNode = targetNode(mev);
1374
1375 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1376 invalidateClick();
1377 return true;
1378 }
1379
1380 Frame* subframe = subframeForHitTestResult(mev);
1381 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1382 // Start capturing future events for this frame. We only do this if we didn't clear
1383 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1384 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1385 if (m_mousePressed && m_capturesDragging) {
1386 m_capturingMouseEventsNode = targetNode(mev);
1387 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1388 }
1389 invalidateClick();
1390 return true;
1391 }
1392
1393 #if ENABLE(PAN_SCROLLING)
1394 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1395 // because it will set m_panScrollInProgress to false on return.
1396 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->m_panScrollInProgress;
1397 if (isPanScrollInProgress || m_autoscrollInProgress)
1398 stopAutoscrollTimer();
1399 if (isPanScrollInProgress) {
1400 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1401 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1402 invalidateClick();
1403 return true;
1404 }
1405 #endif
1406
1407 m_clickCount = mouseEvent.clickCount();
1408 m_clickNode = targetNode(mev);
1409
1410 if (FrameView* view = m_frame->view()) {
1411 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1412 IntPoint p = view->windowToContents(mouseEvent.pos());
1413 if (layer && layer->isPointInResizeControl(p)) {
1414 layer->setInResizeMode(true);
1415 m_resizeLayer = layer;
1416 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1417 invalidateClick();
1418 return true;
1419 }
1420 }
1421
1422 m_frame->selection()->setCaretBlinkingSuspended(true);
1423
1424 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1425 m_capturesDragging = !swallowEvent;
1426
1427 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1428 // in case the scrollbar widget was destroyed when the mouse event was handled.
1429 if (mev.scrollbar()) {
1430 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1431 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1432 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1433 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1434 m_lastScrollbarUnderMouse = 0;
1435 }
1436
1437 if (swallowEvent) {
1438 // scrollbars should get events anyway, even disabled controls might be scrollable
1439 Scrollbar* scrollbar = mev.scrollbar();
1440
1441 updateLastScrollbarUnderMouse(scrollbar, true);
1442
1443 if (scrollbar)
1444 passMousePressEventToScrollbar(mev, scrollbar);
1445 } else {
1446 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1447 // If a mouse event handler changes the input element type to one that has a widget associated,
1448 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1449 // event target node can't still be the shadow node.
1450 if (targetNode(mev)->isShadowRoot() && targetNode(mev)->shadowHost()->hasTagName(inputTag)) {
1451 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1452 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1453 }
1454
1455 FrameView* view = m_frame->view();
1456 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0;
1457 if (!scrollbar)
1458 scrollbar = mev.scrollbar();
1459
1460 updateLastScrollbarUnderMouse(scrollbar, true);
1461
1462 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1463 swallowEvent = true;
1464 else
1465 swallowEvent = handleMousePressEvent(mev);
1466 }
1467
1468 return swallowEvent;
1469 }
1470
1471 // This method only exists for platforms that don't know how to deliver
handleMouseDoubleClickEvent(const PlatformMouseEvent & mouseEvent)1472 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1473 {
1474 RefPtr<FrameView> protector(m_frame->view());
1475
1476 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1477
1478 // We get this instead of a second mouse-up
1479 m_mousePressed = false;
1480 m_currentMousePosition = mouseEvent.pos();
1481
1482 HitTestRequest request(HitTestRequest::Active);
1483 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1484 Frame* subframe = subframeForHitTestResult(mev);
1485 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1486 m_capturingMouseEventsNode = 0;
1487 if (subframe && passMousePressEventToSubframe(mev, subframe))
1488 return true;
1489
1490 m_clickCount = mouseEvent.clickCount();
1491 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1492
1493 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1494
1495 if (m_lastScrollbarUnderMouse)
1496 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
1497
1498 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1499
1500 invalidateClick();
1501
1502 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1503 }
1504
layerForNode(Node * node)1505 static RenderLayer* layerForNode(Node* node)
1506 {
1507 if (!node)
1508 return 0;
1509
1510 RenderObject* renderer = node->renderer();
1511 if (!renderer)
1512 return 0;
1513
1514 RenderLayer* layer = renderer->enclosingLayer();
1515 if (!layer)
1516 return 0;
1517
1518 return layer;
1519 }
1520
mouseMoved(const PlatformMouseEvent & event)1521 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1522 {
1523 HitTestResult hoveredNode = HitTestResult(IntPoint());
1524 bool result = handleMouseMoveEvent(event, &hoveredNode);
1525
1526 Page* page = m_frame->page();
1527 if (!page)
1528 return result;
1529
1530 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1531 if (page->containsScrollableArea(layer))
1532 layer->scrollAnimator()->mouseMovedInContentArea();
1533 }
1534
1535 if (FrameView* frameView = m_frame->view())
1536 frameView->scrollAnimator()->mouseMovedInContentArea();
1537
1538 hoveredNode.setToNonShadowAncestor();
1539 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1540 page->chrome()->setToolTip(hoveredNode);
1541 return result;
1542 }
1543
handleMouseMoveEvent(const PlatformMouseEvent & mouseEvent,HitTestResult * hoveredNode)1544 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode)
1545 {
1546 // in Radar 3703768 we saw frequent crashes apparently due to the
1547 // part being null here, which seems impossible, so check for nil
1548 // but also assert so that we can try to figure this out in debug
1549 // builds, if it happens.
1550 ASSERT(m_frame);
1551 if (!m_frame)
1552 return false;
1553
1554 RefPtr<FrameView> protector(m_frame->view());
1555 m_currentMousePosition = mouseEvent.pos();
1556
1557 if (m_hoverTimer.isActive())
1558 m_hoverTimer.stop();
1559
1560 cancelFakeMouseMoveEvent();
1561
1562 #if ENABLE(SVG)
1563 if (m_svgPan) {
1564 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1565 return true;
1566 }
1567 #endif
1568
1569 if (m_frameSetBeingResized)
1570 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1571
1572 // Send events right to a scrollbar if the mouse is pressed.
1573 if (m_lastScrollbarUnderMouse && m_mousePressed)
1574 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1575
1576 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
1577 // if we are allowed to select.
1578 // This means that :hover and :active freeze in the state they were in when the mouse
1579 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
1580 HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove;
1581 if (m_mousePressed && m_mouseDownMayStartSelect)
1582 hitType |= HitTestRequest::ReadOnly;
1583 if (m_mousePressed)
1584 hitType |= HitTestRequest::Active;
1585
1586 #if ENABLE(TOUCH_EVENTS)
1587 // Treat any mouse move events as readonly if the user is currently touching the screen.
1588 if (m_touchPressed)
1589 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1590 #endif
1591 HitTestRequest request(hitType);
1592 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1593 if (hoveredNode)
1594 *hoveredNode = mev.hitTestResult();
1595
1596 Scrollbar* scrollbar = 0;
1597
1598 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1599 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1600 else {
1601 if (FrameView* view = m_frame->view())
1602 scrollbar = view->scrollbarAtPoint(mouseEvent.pos());
1603
1604 if (!scrollbar)
1605 scrollbar = mev.scrollbar();
1606
1607 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1608 }
1609
1610 bool swallowEvent = false;
1611 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1612
1613 // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts.
1614 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1615 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1616
1617 if (newSubframe) {
1618 // Update over/out state before passing the event to the subframe.
1619 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1620
1621 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1622 // node to be detached from its FrameView, in which case the event should not be passed.
1623 if (newSubframe->view())
1624 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1625 } else {
1626 if (scrollbar && !m_mousePressed)
1627 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1628 if (Page* page = m_frame->page()) {
1629 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->m_panScrollInProgress) {
1630 // Plugins set cursor on their own. The only case WebKit intervenes is resetting cursor to arrow on mouse enter,
1631 // in case the particular plugin doesn't manipulate cursor at all. Thus, even a CSS cursor set on body has no
1632 // effect on plugins (which matches Firefox).
1633 bool overPluginElement = false;
1634 if (targetNode(mev) && targetNode(mev)->isHTMLElement()) {
1635 HTMLElement* el = toHTMLElement(targetNode(mev));
1636 overPluginElement = el->hasTagName(appletTag) || el->hasTagName(objectTag) || el->hasTagName(embedTag);
1637 }
1638 if (!overPluginElement) {
1639 if (FrameView* view = m_frame->view())
1640 view->setCursor(selectCursor(mev, scrollbar));
1641 }
1642 }
1643 }
1644 }
1645
1646 m_lastMouseMoveEventSubframe = newSubframe;
1647
1648 if (swallowEvent)
1649 return true;
1650
1651 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1652 #if ENABLE(DRAG_SUPPORT)
1653 if (!swallowEvent)
1654 swallowEvent = handleMouseDraggedEvent(mev);
1655 #endif // ENABLE(DRAG_SUPPORT)
1656
1657 return swallowEvent;
1658 }
1659
invalidateClick()1660 void EventHandler::invalidateClick()
1661 {
1662 m_clickCount = 0;
1663 m_clickNode = 0;
1664 }
1665
handleMouseReleaseEvent(const PlatformMouseEvent & mouseEvent)1666 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1667 {
1668 RefPtr<FrameView> protector(m_frame->view());
1669
1670 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1671
1672 #if ENABLE(PAN_SCROLLING)
1673 if (mouseEvent.button() == MiddleButton)
1674 m_panScrollButtonPressed = false;
1675 if (m_springLoadedPanScrollInProgress)
1676 stopAutoscrollTimer();
1677 #endif
1678
1679 m_mousePressed = false;
1680 m_currentMousePosition = mouseEvent.pos();
1681
1682 #if ENABLE(SVG)
1683 if (m_svgPan) {
1684 m_svgPan = false;
1685 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1686 return true;
1687 }
1688 #endif
1689
1690 if (m_frameSetBeingResized)
1691 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1692
1693 if (m_lastScrollbarUnderMouse) {
1694 invalidateClick();
1695 return m_lastScrollbarUnderMouse->mouseUp();
1696 }
1697
1698 HitTestRequest request(HitTestRequest::MouseUp);
1699 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1700 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1701 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1702 m_capturingMouseEventsNode = 0;
1703 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1704 return true;
1705
1706 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1707
1708 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1709
1710 if (m_resizeLayer) {
1711 m_resizeLayer->setInResizeMode(false);
1712 m_resizeLayer = 0;
1713 }
1714
1715 bool swallowMouseReleaseEvent = false;
1716 if (!swallowMouseUpEvent)
1717 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1718
1719 invalidateClick();
1720
1721 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1722 }
1723
1724 #if ENABLE(DRAG_SUPPORT)
dispatchDragEvent(const AtomicString & eventType,Node * dragTarget,const PlatformMouseEvent & event,Clipboard * clipboard)1725 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1726 {
1727 FrameView* view = m_frame->view();
1728
1729 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1730 if (!view)
1731 return false;
1732
1733 view->resetDeferredRepaintDelay();
1734 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1735 true, true, m_frame->document()->defaultView(),
1736 0, event.globalX(), event.globalY(), event.x(), event.y(),
1737 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1738 0, 0, clipboard);
1739
1740 ExceptionCode ec;
1741 dragTarget->dispatchEvent(me.get(), ec);
1742 return me->defaultPrevented();
1743 }
1744
canHandleDragAndDropForTarget(DragAndDropHandleType type,Node * target,const PlatformMouseEvent & event,Clipboard * clipboard,bool * accepted)1745 bool EventHandler::canHandleDragAndDropForTarget(DragAndDropHandleType type, Node* target, const PlatformMouseEvent& event, Clipboard* clipboard, bool* accepted)
1746 {
1747 bool canHandle = false;
1748 bool wasAccepted = false;
1749
1750 if (target->hasTagName(frameTag) || target->hasTagName(iframeTag)) {
1751 Frame* frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
1752 if (frame) {
1753 switch (type) {
1754 case UpdateDragAndDrop:
1755 wasAccepted = frame->eventHandler()->updateDragAndDrop(event, clipboard);
1756 break;
1757 case CancelDragAndDrop:
1758 frame->eventHandler()->cancelDragAndDrop(event, clipboard);
1759 break;
1760 case PerformDragAndDrop:
1761 wasAccepted = frame->eventHandler()->performDragAndDrop(event, clipboard);
1762 break;
1763 }
1764 }
1765 } else
1766 canHandle = true;
1767
1768 if (accepted)
1769 *accepted = wasAccepted;
1770
1771 return canHandle;
1772 }
1773
updateDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1774 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1775 {
1776 bool accept = false;
1777
1778 if (!m_frame->view())
1779 return false;
1780
1781 HitTestRequest request(HitTestRequest::ReadOnly);
1782 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1783
1784 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1785 Node* newTarget = targetNode(mev);
1786 if (newTarget && newTarget->isTextNode())
1787 newTarget = newTarget->parentNode();
1788 if (newTarget)
1789 newTarget = newTarget->shadowAncestorNode();
1790
1791 if (m_dragTarget != newTarget) {
1792 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1793 // it is sometimes incorrect when dragging within subframes, as seen with
1794 // LayoutTests/fast/events/drag-in-frames.html.
1795 //
1796 // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
1797 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
1798 // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event.
1799 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
1800 // for now we don't care if event handler cancels default behavior, since there is none
1801 dispatchDragSrcEvent(eventNames().dragEvent, event);
1802 }
1803 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
1804 }
1805
1806 if (m_dragTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
1807 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1808
1809 if (newTarget) {
1810 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1811 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1812 m_shouldOnlyFireDragOverEvent = true;
1813 }
1814 } else {
1815 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
1816 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1817 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
1818 // for now we don't care if event handler cancels default behavior, since there is none
1819 dispatchDragSrcEvent(eventNames().dragEvent, event);
1820 }
1821 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
1822 m_shouldOnlyFireDragOverEvent = false;
1823 }
1824 }
1825 m_dragTarget = newTarget;
1826
1827 return accept;
1828 }
1829
cancelDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1830 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1831 {
1832 if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) {
1833 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
1834 dispatchDragSrcEvent(eventNames().dragEvent, event);
1835 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1836 }
1837 clearDragState();
1838 }
1839
performDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1840 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1841 {
1842 bool accept = false;
1843 if (m_dragTarget && canHandleDragAndDropForTarget(PerformDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
1844 dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
1845 clearDragState();
1846 return accept;
1847 }
1848
clearDragState()1849 void EventHandler::clearDragState()
1850 {
1851 m_dragTarget = 0;
1852 m_capturingMouseEventsNode = 0;
1853 m_shouldOnlyFireDragOverEvent = false;
1854 #if PLATFORM(MAC)
1855 m_sendingEventToSubview = false;
1856 #endif
1857 }
1858 #endif // ENABLE(DRAG_SUPPORT)
1859
setCapturingMouseEventsNode(PassRefPtr<Node> n)1860 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1861 {
1862 m_capturingMouseEventsNode = n;
1863 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1864 }
1865
prepareMouseEvent(const HitTestRequest & request,const PlatformMouseEvent & mev)1866 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1867 {
1868 ASSERT(m_frame);
1869 ASSERT(m_frame->document());
1870
1871 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
1872 }
1873
1874 #if ENABLE(SVG)
instanceAssociatedWithShadowTreeElement(Node * referenceNode)1875 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1876 {
1877 if (!referenceNode || !referenceNode->isSVGElement())
1878 return 0;
1879
1880 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
1881 if (!shadowTreeElement)
1882 return 0;
1883
1884 Element* shadowTreeParentElement = shadowTreeElement->shadowHost();
1885 if (!shadowTreeParentElement)
1886 return 0;
1887
1888 ASSERT(shadowTreeParentElement->hasTagName(useTag));
1889 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1890 }
1891 #endif
1892
updateMouseEventTargetNode(Node * targetNode,const PlatformMouseEvent & mouseEvent,bool fireMouseOverOut)1893 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1894 {
1895 Node* result = targetNode;
1896
1897 // If we're capturing, we always go right to that node.
1898 if (m_capturingMouseEventsNode)
1899 result = m_capturingMouseEventsNode.get();
1900 else {
1901 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1902 if (result && result->isTextNode())
1903 result = result->parentNode();
1904 }
1905 m_nodeUnderMouse = result;
1906 #if ENABLE(SVG)
1907 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1908
1909 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1910 if (m_lastInstanceUnderMouse) {
1911 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1912 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1913
1914 if (lastCorrespondingElement && lastCorrespondingUseElement) {
1915 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1916
1917 // Locate the recloned shadow tree element for our corresponding instance
1918 HashSet<SVGElementInstance*>::iterator end = instances.end();
1919 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1920 SVGElementInstance* instance = (*it);
1921 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1922
1923 if (instance == m_lastInstanceUnderMouse)
1924 continue;
1925
1926 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1927 continue;
1928
1929 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1930 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1931 continue;
1932
1933 m_lastNodeUnderMouse = shadowTreeElement;
1934 m_lastInstanceUnderMouse = instance;
1935 break;
1936 }
1937 }
1938 }
1939 #endif
1940
1941 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1942 if (fireMouseOverOut) {
1943 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1944 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1945 Page* page = m_frame->page();
1946
1947 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1948 // The mouse has moved between frames.
1949 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
1950 if (FrameView* frameView = frame->view())
1951 frameView->scrollAnimator()->mouseExitedContentArea();
1952 }
1953 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1954 // The mouse has moved between layers.
1955 if (page->containsScrollableArea(layerForLastNode))
1956 layerForLastNode->scrollAnimator()->mouseExitedContentArea();
1957 }
1958
1959 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1960 // The mouse has moved between frames.
1961 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
1962 if (FrameView* frameView = frame->view())
1963 frameView->scrollAnimator()->mouseEnteredContentArea();
1964 }
1965 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1966 // The mouse has moved between layers.
1967 if (page->containsScrollableArea(layerForNodeUnderMouse))
1968 layerForNodeUnderMouse->scrollAnimator()->mouseEnteredContentArea();
1969 }
1970
1971 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1972 m_lastNodeUnderMouse = 0;
1973 m_lastScrollbarUnderMouse = 0;
1974 #if ENABLE(SVG)
1975 m_lastInstanceUnderMouse = 0;
1976 #endif
1977 }
1978
1979 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1980 // send mouseout event to the old node
1981 if (m_lastNodeUnderMouse)
1982 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
1983 // send mouseover event to the new node
1984 if (m_nodeUnderMouse)
1985 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
1986 }
1987 m_lastNodeUnderMouse = m_nodeUnderMouse;
1988 #if ENABLE(SVG)
1989 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
1990 #endif
1991 }
1992 }
1993
dispatchMouseEvent(const AtomicString & eventType,Node * targetNode,bool,int clickCount,const PlatformMouseEvent & mouseEvent,bool setUnder)1994 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1995 {
1996 if (FrameView* view = m_frame->view())
1997 view->resetDeferredRepaintDelay();
1998
1999 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2000
2001 bool swallowEvent = false;
2002
2003 if (m_nodeUnderMouse)
2004 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2005
2006 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2007
2008 // If clicking on a frame scrollbar, do not mess up with content focus.
2009 if (FrameView* view = m_frame->view()) {
2010 if (view->scrollbarAtPoint(mouseEvent.pos()))
2011 return false;
2012 }
2013
2014 // The layout needs to be up to date to determine if an element is focusable.
2015 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2016
2017 // Blur current focus node when a link/button is clicked; this
2018 // is expected by some sites that rely on onChange handlers running
2019 // from form fields before the button click is processed.
2020 Node* node = m_nodeUnderMouse.get();
2021
2022 // Walk up the DOM tree to search for a node to focus.
2023 while (node) {
2024 if (node->isMouseFocusable()) {
2025 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2026 // node on mouse down if it's selected and inside a focused node. It will be
2027 // focused if the user does a mouseup over it, however, because the mouseup
2028 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2029 ExceptionCode ec = 0;
2030 Node* n = node->isShadowRoot() ? node->shadowHost() : node;
2031 if (m_frame->selection()->isRange()
2032 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2033 && n->isDescendantOf(m_frame->document()->focusedNode()))
2034 return false;
2035
2036 break;
2037 }
2038 node = node->parentOrHostNode();
2039 }
2040
2041 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2042 // if the page already set it (e.g., by canceling default behavior).
2043 if (Page* page = m_frame->page()) {
2044 if (node && node->isMouseFocusable()) {
2045 if (!page->focusController()->setFocusedNode(node, m_frame))
2046 swallowEvent = true;
2047 } else if (!node || !node->focused()) {
2048 if (!page->focusController()->setFocusedNode(0, m_frame))
2049 swallowEvent = true;
2050 }
2051 }
2052 }
2053
2054 return swallowEvent;
2055 }
2056
2057 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(UNIX) && !OS(DARWIN)))
shouldTurnVerticalTicksIntoHorizontal(const HitTestResult &) const2058 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const
2059 {
2060 return false;
2061 }
2062 #endif
2063
handleWheelEvent(PlatformWheelEvent & e)2064 bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
2065 {
2066 Document* doc = m_frame->document();
2067
2068 RenderObject* docRenderer = doc->renderer();
2069 if (!docRenderer)
2070 return false;
2071
2072 RefPtr<FrameView> protector(m_frame->view());
2073
2074 FrameView* view = m_frame->view();
2075 if (!view)
2076 return false;
2077 setFrameWasScrolledByUser();
2078 IntPoint vPoint = view->windowToContents(e.pos());
2079
2080 Node* node;
2081 bool isOverWidget;
2082
2083 HitTestRequest request(HitTestRequest::ReadOnly);
2084 HitTestResult result(vPoint);
2085 doc->renderView()->layer()->hitTest(request, result);
2086
2087 #if PLATFORM(MAC)
2088 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2089 #endif
2090
2091 if (m_useLatchedWheelEventNode) {
2092 if (!m_latchedWheelEventNode) {
2093 m_latchedWheelEventNode = result.innerNode();
2094 m_widgetIsLatched = result.isOverWidget();
2095 }
2096
2097 node = m_latchedWheelEventNode.get();
2098 isOverWidget = m_widgetIsLatched;
2099 } else {
2100 if (m_latchedWheelEventNode)
2101 m_latchedWheelEventNode = 0;
2102 if (m_previousWheelScrolledNode)
2103 m_previousWheelScrolledNode = 0;
2104
2105 node = result.innerNode();
2106 isOverWidget = result.isOverWidget();
2107 }
2108
2109 if (shouldTurnVerticalTicksIntoHorizontal(result))
2110 e.turnVerticalTicksIntoHorizontal();
2111
2112 if (node) {
2113 // Figure out which view to send the event to.
2114 RenderObject* target = node->renderer();
2115
2116 if (isOverWidget && target && target->isWidget()) {
2117 Widget* widget = toRenderWidget(target)->widget();
2118 if (widget && passWheelEventToWidget(e, widget)) {
2119 e.accept();
2120 return true;
2121 }
2122 }
2123
2124 node = node->shadowAncestorNode();
2125 if (node && !node->dispatchWheelEvent(e)) {
2126 e.accept();
2127 return true;
2128 }
2129 }
2130
2131 if (e.isAccepted())
2132 return true;
2133
2134 view = m_frame->view();
2135 if (!view)
2136 return false;
2137
2138 view->wheelEvent(e);
2139 return e.isAccepted();
2140 }
2141
defaultWheelEventHandler(Node * startNode,WheelEvent * wheelEvent)2142 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2143 {
2144 if (!startNode || !wheelEvent)
2145 return;
2146
2147 Node* stopNode = m_previousWheelScrolledNode.get();
2148
2149 // Break up into two scrolls if we need to. Diagonal movement on
2150 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2151 if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode))
2152 wheelEvent->setDefaultHandled();
2153
2154 if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode))
2155 wheelEvent->setDefaultHandled();
2156
2157 if (!m_useLatchedWheelEventNode)
2158 m_previousWheelScrolledNode = stopNode;
2159 }
2160
2161 #if ENABLE(GESTURE_EVENTS)
handleGestureEvent(const PlatformGestureEvent & gestureEvent)2162 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2163 {
2164 // FIXME: This should hit test and go to the correct subframe rather than
2165 // always sending gestures to the main frame only. We should also ensure
2166 // that if a frame gets a gesture begin gesture, it gets the corresponding
2167 // end gesture as well.
2168
2169 FrameView* view = m_frame->view();
2170 if (!view)
2171 return false;
2172
2173 view->handleGestureEvent(gestureEvent);
2174 return true;
2175 }
2176 #endif
2177
2178 #if ENABLE(CONTEXT_MENUS)
sendContextMenuEvent(const PlatformMouseEvent & event)2179 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2180 {
2181 Document* doc = m_frame->document();
2182 FrameView* v = m_frame->view();
2183 if (!v)
2184 return false;
2185
2186 bool swallowEvent;
2187 IntPoint viewportPos = v->windowToContents(event.pos());
2188 HitTestRequest request(HitTestRequest::Active);
2189 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2190
2191 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2192 && !m_frame->selection()->contains(viewportPos)
2193 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2194 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2195 // available for text selections. But only if we're above text.
2196 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2197 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2198 selectClosestWordOrLinkFromMouseEvent(mev);
2199 }
2200
2201 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2202
2203 return swallowEvent;
2204 }
2205
sendContextMenuEventForKey()2206 bool EventHandler::sendContextMenuEventForKey()
2207 {
2208 FrameView* view = m_frame->view();
2209 if (!view)
2210 return false;
2211
2212 Document* doc = m_frame->document();
2213 if (!doc)
2214 return false;
2215
2216 static const int kContextMenuMargin = 1;
2217
2218 #if OS(WINDOWS) && !OS(WINCE)
2219 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2220 #else
2221 int rightAligned = 0;
2222 #endif
2223 IntPoint location;
2224
2225 Node* focusedNode = doc->focusedNode();
2226 SelectionController* selectionController = m_frame->selection();
2227 Position start = selectionController->selection().start();
2228
2229 if (start.deprecatedNode() && (selectionController->rootEditableElement() || selectionController->isRange())) {
2230 RefPtr<Range> selection = selectionController->toNormalizedRange();
2231 IntRect firstRect = m_frame->editor()->firstRectForRange(selection.get());
2232
2233 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2234 location = IntPoint(x, firstRect.maxY());
2235 } else if (focusedNode) {
2236 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2237 if (!box)
2238 return false;
2239 IntRect clippedRect = box->absoluteClippedOverflowRect();
2240 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2241 } else {
2242 location = IntPoint(
2243 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2244 kContextMenuMargin);
2245 }
2246
2247 m_frame->view()->setCursor(pointerCursor());
2248
2249 IntPoint position = view->contentsToWindow(location);
2250 IntPoint globalPosition = view->contentsToScreen(IntRect(location, IntSize())).location();
2251
2252 Node* targetNode = doc->focusedNode();
2253 if (!targetNode)
2254 targetNode = doc;
2255
2256 // Use the focused node as the target for hover and active.
2257 HitTestResult result(position);
2258 result.setInnerNode(targetNode);
2259 HitTestRequest request(HitTestRequest::Active);
2260 doc->renderView()->layer()->updateHoverActiveState(request, result);
2261 doc->updateStyleIfNeeded();
2262
2263 // The contextmenu event is a mouse event even when invoked using the keyboard.
2264 // This is required for web compatibility.
2265
2266 #if OS(WINDOWS)
2267 MouseEventType eventType = MouseEventReleased;
2268 #else
2269 MouseEventType eventType = MouseEventPressed;
2270 #endif
2271
2272 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2273
2274 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2275 }
2276
2277 #endif // ENABLE(CONTEXT_MENUS)
2278
scheduleHoverStateUpdate()2279 void EventHandler::scheduleHoverStateUpdate()
2280 {
2281 if (!m_hoverTimer.isActive())
2282 m_hoverTimer.startOneShot(0);
2283 }
2284
dispatchFakeMouseMoveEventSoon()2285 void EventHandler::dispatchFakeMouseMoveEventSoon()
2286 {
2287 if (m_mousePressed)
2288 return;
2289
2290 if (!m_fakeMouseMoveEventTimer.isActive())
2291 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2292 }
2293
dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad & quad)2294 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2295 {
2296 FrameView* view = m_frame->view();
2297 if (!view)
2298 return;
2299
2300 if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2301 return;
2302
2303 if (!m_fakeMouseMoveEventTimer.isActive())
2304 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2305 }
2306
cancelFakeMouseMoveEvent()2307 void EventHandler::cancelFakeMouseMoveEvent()
2308 {
2309 m_fakeMouseMoveEventTimer.stop();
2310 }
2311
fakeMouseMoveEventTimerFired(Timer<EventHandler> * timer)2312 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2313 {
2314 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2315 ASSERT(!m_mousePressed);
2316
2317 FrameView* view = m_frame->view();
2318 if (!view)
2319 return;
2320
2321 bool shiftKey;
2322 bool ctrlKey;
2323 bool altKey;
2324 bool metaKey;
2325 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2326 IntPoint globalPoint = view->contentsToScreen(IntRect(view->windowToContents(m_currentMousePosition), IntSize())).location();
2327 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2328 mouseMoved(fakeMouseMoveEvent);
2329 }
2330
2331 // Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
canMouseDownStartSelect(Node * node)2332 bool EventHandler::canMouseDownStartSelect(Node* node)
2333 {
2334 if (!node || !node->renderer())
2335 return true;
2336
2337 // Some controls and images can't start a select on a mouse down.
2338 if (!node->canStartSelection())
2339 return false;
2340
2341 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
2342 }
2343
2344 #if ENABLE(DRAG_SUPPORT)
canMouseDragExtendSelect(Node * node)2345 bool EventHandler::canMouseDragExtendSelect(Node* node)
2346 {
2347 if (!node || !node->renderer())
2348 return true;
2349
2350 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
2351 }
2352 #endif // ENABLE(DRAG_SUPPORT)
2353
setResizingFrameSet(HTMLFrameSetElement * frameSet)2354 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2355 {
2356 m_frameSetBeingResized = frameSet;
2357 }
2358
resizeLayerDestroyed()2359 void EventHandler::resizeLayerDestroyed()
2360 {
2361 ASSERT(m_resizeLayer);
2362 m_resizeLayer = 0;
2363 }
2364
hoverTimerFired(Timer<EventHandler> *)2365 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2366 {
2367 m_hoverTimer.stop();
2368
2369 ASSERT(m_frame);
2370 ASSERT(m_frame->document());
2371
2372 if (RenderView* renderer = m_frame->contentRenderer()) {
2373 if (FrameView* view = m_frame->view()) {
2374 HitTestRequest request(HitTestRequest::MouseMove);
2375 HitTestResult result(view->windowToContents(m_currentMousePosition));
2376 renderer->layer()->hitTest(request, result);
2377 m_frame->document()->updateStyleIfNeeded();
2378 }
2379 }
2380 }
2381
eventTargetNodeForDocument(Document * doc)2382 static Node* eventTargetNodeForDocument(Document* doc)
2383 {
2384 if (!doc)
2385 return 0;
2386 Node* node = doc->focusedNode();
2387 if (!node && doc->isPluginDocument()) {
2388 PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
2389 node = pluginDocument->pluginNode();
2390 }
2391 if (!node && doc->isHTMLDocument())
2392 node = doc->body();
2393 if (!node)
2394 node = doc->documentElement();
2395 return node;
2396 }
2397
handleAccessKey(const PlatformKeyboardEvent & evt)2398 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2399 {
2400 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2401 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2402 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2403 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2404 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey));
2405 if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers())
2406 return false;
2407 String key = evt.unmodifiedText();
2408 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2409 if (!elem)
2410 return false;
2411 elem->accessKeyAction(false);
2412 return true;
2413 }
2414
2415 #if !PLATFORM(MAC)
needsKeyboardEventDisambiguationQuirks() const2416 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2417 {
2418 return false;
2419 }
2420 #endif
2421
keyEvent(const PlatformKeyboardEvent & initialKeyEvent)2422 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2423 {
2424 RefPtr<FrameView> protector(m_frame->view());
2425
2426 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2427 capsLockStateMayHaveChanged();
2428
2429 #if ENABLE(PAN_SCROLLING)
2430 if (Page* page = m_frame->page()) {
2431 if (page->mainFrame()->eventHandler()->m_panScrollInProgress || m_autoscrollInProgress) {
2432 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
2433 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown)
2434 stopAutoscrollTimer();
2435
2436 // If we were in autoscroll/panscroll mode, we swallow the key event
2437 return true;
2438 }
2439 }
2440 #endif
2441
2442 // Check for cases where we are too early for events -- possible unmatched key up
2443 // from pressing return in the location bar.
2444 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2445 if (!node)
2446 return false;
2447
2448 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2449 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2450
2451 if (FrameView* view = m_frame->view())
2452 view->resetDeferredRepaintDelay();
2453
2454 // FIXME: what is this doing here, in keyboard event handler?
2455 m_frame->loader()->resetMultipleFormSubmissionProtection();
2456
2457 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2458 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2459 // with access keys. Then we dispatch keydown, but suppress its default handling.
2460 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2461 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2462 bool matchedAnAccessKey = false;
2463 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
2464 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2465
2466 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2467 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
2468 return !node->dispatchKeyEvent(initialKeyEvent);
2469
2470 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2471
2472 ExceptionCode ec;
2473 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2474 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
2475 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
2476 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2477 if (matchedAnAccessKey)
2478 keydown->setDefaultPrevented(true);
2479 keydown->setTarget(node);
2480
2481 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
2482 node->dispatchEvent(keydown, ec);
2483 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2484 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2485 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2486 }
2487
2488 // Run input method in advance of DOM event handling. This may result in the IM
2489 // modifying the page prior the keydown event, but this behaviour is necessary
2490 // in order to match IE:
2491 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2492 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2493 m_frame->editor()->handleInputMethodKeydown(keydown.get());
2494
2495 bool handledByInputMethod = keydown->defaultHandled();
2496
2497 if (handledByInputMethod) {
2498 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2499 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2500 keydown->setTarget(node);
2501 keydown->setDefaultHandled();
2502 }
2503
2504 node->dispatchEvent(keydown, ec);
2505 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2506 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2507 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2508 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2509 return keydownResult;
2510
2511 // Focus may have changed during keydown handling, so refetch node.
2512 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2513 if (!keydownResult) {
2514 node = eventTargetNodeForDocument(m_frame->document());
2515 if (!node)
2516 return false;
2517 }
2518
2519 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2520 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
2521 if (keyPressEvent.text().isEmpty())
2522 return keydownResult;
2523 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
2524 keypress->setTarget(node);
2525 if (keydownResult)
2526 keypress->setDefaultPrevented(true);
2527 #if PLATFORM(MAC)
2528 keypress->keypressCommands() = keydown->keypressCommands();
2529 #endif
2530 node->dispatchEvent(keypress, ec);
2531
2532 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2533 }
2534
handleKeyboardSelectionMovement(KeyboardEvent * event)2535 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
2536 {
2537 if (!event)
2538 return;
2539
2540 const String& key = event->keyIdentifier();
2541 bool isShifted = event->getModifierState("Shift");
2542 bool isOptioned = event->getModifierState("Alt");
2543 bool isCommanded = event->getModifierState("Meta");
2544
2545 if (key == "Up") {
2546 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionBackward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2547 event->setDefaultHandled();
2548 } else if (key == "Down") {
2549 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionForward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2550 event->setDefaultHandled();
2551 } else if (key == "Left") {
2552 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionLeft, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2553 event->setDefaultHandled();
2554 } else if (key == "Right") {
2555 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionRight, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2556 event->setDefaultHandled();
2557 }
2558 }
2559
defaultKeyboardEventHandler(KeyboardEvent * event)2560 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2561 {
2562 if (event->type() == eventNames().keydownEvent) {
2563 m_frame->editor()->handleKeyboardEvent(event);
2564 if (event->defaultHandled())
2565 return;
2566 if (event->keyIdentifier() == "U+0009")
2567 defaultTabEventHandler(event);
2568 else if (event->keyIdentifier() == "U+0008")
2569 defaultBackspaceEventHandler(event);
2570 else {
2571 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
2572 if (direction != FocusDirectionNone)
2573 defaultArrowEventHandler(direction, event);
2574 }
2575
2576 // provides KB navigation and selection for enhanced accessibility users
2577 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2578 handleKeyboardSelectionMovement(event);
2579 }
2580 if (event->type() == eventNames().keypressEvent) {
2581 m_frame->editor()->handleKeyboardEvent(event);
2582 if (event->defaultHandled())
2583 return;
2584 if (event->charCode() == ' ')
2585 defaultSpaceEventHandler(event);
2586 }
2587 }
2588
focusDirectionForKey(const AtomicString & keyIdentifier) const2589 FocusDirection EventHandler::focusDirectionForKey(const AtomicString& keyIdentifier) const
2590 {
2591 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
2592 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
2593 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
2594 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
2595
2596 FocusDirection retVal = FocusDirectionNone;
2597
2598 if (keyIdentifier == Down)
2599 retVal = FocusDirectionDown;
2600 else if (keyIdentifier == Up)
2601 retVal = FocusDirectionUp;
2602 else if (keyIdentifier == Left)
2603 retVal = FocusDirectionLeft;
2604 else if (keyIdentifier == Right)
2605 retVal = FocusDirectionRight;
2606
2607 return retVal;
2608 }
2609
2610 #if ENABLE(DRAG_SUPPORT)
dragHysteresisExceeded(const FloatPoint & floatDragViewportLocation) const2611 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
2612 {
2613 IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y());
2614 return dragHysteresisExceeded(dragViewportLocation);
2615 }
2616
dragHysteresisExceeded(const IntPoint & dragViewportLocation) const2617 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
2618 {
2619 FrameView* view = m_frame->view();
2620 if (!view)
2621 return false;
2622 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
2623 IntSize delta = dragLocation - m_mouseDownPos;
2624
2625 int threshold = GeneralDragHysteresis;
2626 if (dragState().m_dragSrcIsImage)
2627 threshold = ImageDragHysteresis;
2628 else if (dragState().m_dragSrcIsLink)
2629 threshold = LinkDragHysteresis;
2630 else if (dragState().m_dragSrcInSelection)
2631 threshold = TextDragHysteresis;
2632
2633 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
2634 }
2635
freeClipboard()2636 void EventHandler::freeClipboard()
2637 {
2638 if (dragState().m_dragClipboard)
2639 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
2640 }
2641
shouldDragAutoNode(Node * node,const IntPoint & point) const2642 bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const
2643 {
2644 if (!node || !m_frame->view())
2645 return false;
2646 Page* page = m_frame->page();
2647 return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point, node);
2648 }
2649
dragSourceEndedAt(const PlatformMouseEvent & event,DragOperation operation)2650 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
2651 {
2652 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
2653 dragState().m_dragClipboard->setDestinationOperation(operation);
2654 // for now we don't care if event handler cancels default behavior, since there is none
2655 dispatchDragSrcEvent(eventNames().dragendEvent, event);
2656 }
2657 freeClipboard();
2658 dragState().m_dragSrc = 0;
2659 // In case the drag was ended due to an escape key press we need to ensure
2660 // that consecutive mousemove events don't reinitiate the drag and drop.
2661 m_mouseDownMayStartDrag = false;
2662 }
2663
2664 // returns if we should continue "default processing", i.e., whether eventhandler canceled
dispatchDragSrcEvent(const AtomicString & eventType,const PlatformMouseEvent & event)2665 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
2666 {
2667 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
2668 }
2669
handleDrag(const MouseEventWithHitTestResults & event)2670 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
2671 {
2672 if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) {
2673 // If we allowed the other side of the bridge to handle a drag
2674 // last time, then m_mousePressed might still be set. So we
2675 // clear it now to make sure the next move after a drag
2676 // doesn't look like a drag.
2677 m_mousePressed = false;
2678 return false;
2679 }
2680
2681 if (eventLoopHandleMouseDragged(event))
2682 return true;
2683
2684 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
2685
2686 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2687 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA);
2688 if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA)
2689 m_mouseDownMayStartDrag = false; // no element is draggable
2690 }
2691
2692 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2693 // try to find an element that wants to be dragged
2694 HitTestRequest request(HitTestRequest::ReadOnly);
2695 HitTestResult result(m_mouseDownPos);
2696 m_frame->contentRenderer()->layer()->hitTest(request, result);
2697 Node* node = result.innerNode();
2698 if (node && node->renderer())
2699 dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
2700 m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML);
2701 else
2702 dragState().m_dragSrc = 0;
2703
2704 if (!dragState().m_dragSrc)
2705 m_mouseDownMayStartDrag = false; // no element is draggable
2706 else {
2707 // remember some facts about this source, while we have a HitTestResult handy
2708 node = result.URLElement();
2709 dragState().m_dragSrcIsLink = node && node->isLink();
2710
2711 node = result.innerNonSharedNode();
2712 dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
2713
2714 dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
2715 }
2716 }
2717
2718 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
2719 // or else we bail on the dragging stuff and allow selection to occur
2720 if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
2721 m_mouseDownMayStartDrag = false;
2722 dragState().m_dragSrc = 0;
2723 // ...but if this was the first click in the window, we don't even want to start selection
2724 if (eventActivatedView(event.event()))
2725 m_mouseDownMayStartSelect = false;
2726 }
2727
2728 if (!m_mouseDownMayStartDrag)
2729 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
2730
2731 // We are starting a text/image/url drag, so the cursor should be an arrow
2732 if (FrameView* view = m_frame->view()) {
2733 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
2734 view->setCursor(pointerCursor());
2735 }
2736
2737 if (!dragHysteresisExceeded(event.event().pos()))
2738 return true;
2739
2740 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2741 invalidateClick();
2742
2743 DragOperation srcOp = DragOperationNone;
2744
2745 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
2746 // to make sure it gets numbified
2747 dragState().m_dragClipboard = createDraggingClipboard();
2748
2749 if (dragState().m_dragSrcMayBeDHTML) {
2750 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
2751 // image and offset
2752 if (dragState().m_dragSrcIsDHTML) {
2753 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
2754 // FIXME: This doesn't work correctly with transforms.
2755 FloatPoint absPos = renderer->localToAbsolute();
2756 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
2757 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
2758 } else {
2759 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
2760 // the element in some way. In this case we just kill the drag.
2761 m_mouseDownMayStartDrag = false;
2762 goto cleanupDrag;
2763 }
2764 }
2765
2766 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
2767 && !m_frame->selection()->isInPasswordField();
2768
2769 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
2770 // image can still be changed as we drag, but not the pasteboard data.
2771 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
2772
2773 if (m_mouseDownMayStartDrag) {
2774 // gather values from DHTML element, if it set any
2775 srcOp = dragState().m_dragClipboard->sourceOperation();
2776
2777 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
2778 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
2779 // started the drag when that happens. So we have to assume it's started before we
2780 // kick it off.
2781 dragState().m_dragClipboard->setDragHasStarted();
2782 }
2783 }
2784
2785 if (m_mouseDownMayStartDrag) {
2786 Page* page = m_frame->page();
2787 DragController* dragController = page ? page->dragController() : 0;
2788 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
2789 if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
2790 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
2791 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
2792 m_mouseDownMayStartDrag = false;
2793 }
2794 }
2795
2796 cleanupDrag:
2797 if (!m_mouseDownMayStartDrag) {
2798 // something failed to start the drag, cleanup
2799 freeClipboard();
2800 dragState().m_dragSrc = 0;
2801 }
2802
2803 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2804 return true;
2805 }
2806 #endif // ENABLE(DRAG_SUPPORT)
2807
handleTextInputEvent(const String & text,Event * underlyingEvent,TextEventInputType inputType)2808 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
2809 {
2810 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
2811 // and avoid dispatching text input events from keydown default handlers.
2812 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
2813
2814 if (!m_frame)
2815 return false;
2816
2817 EventTarget* target;
2818 if (underlyingEvent)
2819 target = underlyingEvent->target();
2820 else
2821 target = eventTargetNodeForDocument(m_frame->document());
2822 if (!target)
2823 return false;
2824
2825 if (FrameView* view = m_frame->view())
2826 view->resetDeferredRepaintDelay();
2827
2828 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
2829 event->setUnderlyingEvent(underlyingEvent);
2830
2831 ExceptionCode ec;
2832 target->dispatchEvent(event, ec);
2833 return event->defaultHandled();
2834 }
2835
isKeyboardOptionTab(KeyboardEvent * event)2836 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
2837 {
2838 return event
2839 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
2840 && event->altKey()
2841 && event->keyIdentifier() == "U+0009";
2842 }
2843
eventInvertsTabsToLinksClientCallResult(KeyboardEvent * event)2844 bool EventHandler::eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
2845 {
2846 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(HAIKU) || PLATFORM(EFL)
2847 return EventHandler::isKeyboardOptionTab(event);
2848 #else
2849 return false;
2850 #endif
2851 }
2852
tabsToLinks(KeyboardEvent * event) const2853 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
2854 {
2855 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
2856
2857 Page* page = m_frame->page();
2858 if (!page)
2859 return false;
2860
2861 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
2862 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
2863 }
2864
defaultTextInputEventHandler(TextEvent * event)2865 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
2866 {
2867 if (m_frame->editor()->handleTextEvent(event))
2868 event->setDefaultHandled();
2869 }
2870
2871 #if PLATFORM(QT)
2872 // Qt handles the space event in platform-specific WebKit code.
2873 // Eventually it would be good to eliminate that and use the code here instead.
defaultSpaceEventHandler(KeyboardEvent *)2874 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
2875 {
2876 }
2877 #else
2878
defaultSpaceEventHandler(KeyboardEvent * event)2879 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
2880 {
2881 ASSERT(event->type() == eventNames().keypressEvent);
2882
2883 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
2884 return;
2885
2886 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
2887 if (logicalScrollOverflow(direction, ScrollByPage)) {
2888 event->setDefaultHandled();
2889 return;
2890 }
2891
2892 FrameView* view = m_frame->view();
2893 if (!view)
2894 return;
2895
2896 if (view->logicalScroll(direction, ScrollByPage))
2897 event->setDefaultHandled();
2898 }
2899
2900 #endif
2901
defaultBackspaceEventHandler(KeyboardEvent * event)2902 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
2903 {
2904 ASSERT(event->type() == eventNames().keydownEvent);
2905
2906 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
2907 return;
2908
2909 Page* page = m_frame->page();
2910 if (!page)
2911 return;
2912
2913 bool handledEvent = false;
2914
2915 if (event->shiftKey())
2916 handledEvent = page->goForward();
2917 else
2918 handledEvent = page->goBack();
2919
2920 if (handledEvent)
2921 event->setDefaultHandled();
2922 }
2923
2924
defaultArrowEventHandler(FocusDirection focusDirection,KeyboardEvent * event)2925 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
2926 {
2927 ASSERT(event->type() == eventNames().keydownEvent);
2928
2929 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
2930 return;
2931
2932 Page* page = m_frame->page();
2933 if (!page)
2934 return;
2935
2936 if (!isSpatialNavigationEnabled(m_frame))
2937 return;
2938
2939 // Arrows and other possible directional navigation keys can be used in design
2940 // mode editing.
2941 if (m_frame->document()->inDesignMode())
2942 return;
2943
2944 if (page->focusController()->advanceFocus(focusDirection, event))
2945 event->setDefaultHandled();
2946 }
2947
defaultTabEventHandler(KeyboardEvent * event)2948 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
2949 {
2950 ASSERT(event->type() == eventNames().keydownEvent);
2951
2952 // We should only advance focus on tabs if no special modifier keys are held down.
2953 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
2954 return;
2955
2956 Page* page = m_frame->page();
2957 if (!page)
2958 return;
2959 if (!page->tabKeyCyclesThroughElements())
2960 return;
2961
2962 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
2963
2964 // Tabs can be used in design mode editing.
2965 if (m_frame->document()->inDesignMode())
2966 return;
2967
2968 if (page->focusController()->advanceFocus(focusDirection, event))
2969 event->setDefaultHandled();
2970 }
2971
capsLockStateMayHaveChanged()2972 void EventHandler::capsLockStateMayHaveChanged()
2973 {
2974 Document* d = m_frame->document();
2975 if (Node* node = d->focusedNode()) {
2976 if (RenderObject* r = node->renderer()) {
2977 if (r->isTextField())
2978 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
2979 }
2980 }
2981 }
2982
sendResizeEvent()2983 void EventHandler::sendResizeEvent()
2984 {
2985 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
2986 }
2987
sendScrollEvent()2988 void EventHandler::sendScrollEvent()
2989 {
2990 setFrameWasScrolledByUser();
2991 if (m_frame->view() && m_frame->document())
2992 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), EventQueue::ScrollEventDocumentTarget);
2993 }
2994
setFrameWasScrolledByUser()2995 void EventHandler::setFrameWasScrolledByUser()
2996 {
2997 FrameView* v = m_frame->view();
2998 if (v)
2999 v->setWasScrolledByUser(true);
3000 }
3001
passMousePressEventToScrollbar(MouseEventWithHitTestResults & mev,Scrollbar * scrollbar)3002 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3003 {
3004 if (!scrollbar || !scrollbar->enabled())
3005 return false;
3006 setFrameWasScrolledByUser();
3007 return scrollbar->mouseDown(mev.event());
3008 }
3009
3010 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3011 // last to scrollbar if setLast is true; else set last to 0.
updateLastScrollbarUnderMouse(Scrollbar * scrollbar,bool setLast)3012 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3013 {
3014 if (m_lastScrollbarUnderMouse != scrollbar) {
3015 // Send mouse exited to the old scrollbar.
3016 if (m_lastScrollbarUnderMouse)
3017 m_lastScrollbarUnderMouse->mouseExited();
3018 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3019 }
3020 }
3021
3022 #if ENABLE(TOUCH_EVENTS)
3023
eventNameForTouchPointState(PlatformTouchPoint::State state)3024 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3025 {
3026 switch (state) {
3027 case PlatformTouchPoint::TouchReleased:
3028 return eventNames().touchendEvent;
3029 case PlatformTouchPoint::TouchCancelled:
3030 return eventNames().touchcancelEvent;
3031 case PlatformTouchPoint::TouchPressed:
3032 return eventNames().touchstartEvent;
3033 case PlatformTouchPoint::TouchMoved:
3034 return eventNames().touchmoveEvent;
3035 default:
3036 ASSERT_NOT_REACHED();
3037 return emptyAtom;
3038 }
3039 }
3040
handleTouchEvent(const PlatformTouchEvent & event)3041 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3042 {
3043 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3044 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3045 // for an overview of how these lists fit together.
3046
3047 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3048 RefPtr<TouchList> touches = TouchList::create();
3049
3050 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3051 // 'targetTouches' list in the JS event.
3052 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3053 TargetTouchesMap touchesByTarget;
3054
3055 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3056 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3057 struct {
3058 // The touches corresponding to the particular change state this struct instance represents.
3059 RefPtr<TouchList> m_touches;
3060 // Set of targets involved in m_touches.
3061 EventTargetSet m_targets;
3062 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3063
3064 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3065
3066 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3067
3068 for (unsigned i = 0; i < points.size(); ++i) {
3069 const PlatformTouchPoint& point = points[i];
3070 PlatformTouchPoint::State pointState = point.state();
3071 IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3072
3073 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ReadOnly;
3074 // The HitTestRequest types used for mouse events map quite adequately
3075 // to touch events. Note that in addition to meaning that the hit test
3076 // should affect the active state of the current node if necessary,
3077 // HitTestRequest::Active signifies that the hit test is taking place
3078 // with the mouse (or finger in this case) being pressed.
3079 switch (pointState) {
3080 case PlatformTouchPoint::TouchPressed:
3081 hitType = HitTestRequest::Active;
3082 break;
3083 case PlatformTouchPoint::TouchMoved:
3084 hitType = HitTestRequest::Active | HitTestRequest::MouseMove | HitTestRequest::ReadOnly;
3085 break;
3086 case PlatformTouchPoint::TouchReleased:
3087 case PlatformTouchPoint::TouchCancelled:
3088 hitType = HitTestRequest::MouseUp;
3089 break;
3090 default:
3091 break;
3092 }
3093
3094 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3095 Node* node = result.innerNode();
3096 ASSERT(node);
3097
3098 // Touch events should not go to text nodes
3099 if (node->isTextNode())
3100 node = node->parentNode();
3101
3102 Document* doc = node->document();
3103 if (!doc)
3104 continue;
3105 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3106 continue;
3107
3108 if (m_frame != doc->frame()) {
3109 // pagePoint should always be relative to the target elements containing frame.
3110 pagePoint = documentPointForWindowPoint(doc->frame(), point.pos());
3111 }
3112
3113 int adjustedPageX = lroundf(pagePoint.x() / m_frame->pageZoomFactor());
3114 int adjustedPageY = lroundf(pagePoint.y() / m_frame->pageZoomFactor());
3115
3116 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3117 unsigned touchPointTargetKey = point.id() + 1;
3118 RefPtr<EventTarget> touchTarget;
3119 if (pointState == PlatformTouchPoint::TouchPressed) {
3120 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3121 touchTarget = node;
3122 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3123 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3124 // we also remove it from the map.
3125 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3126 } else
3127 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3128
3129 if (!touchTarget.get())
3130 continue;
3131
3132 RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget.get(), point.id(),
3133 point.screenPos().x(), point.screenPos().y(),
3134 adjustedPageX, adjustedPageY);
3135
3136 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3137 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3138 if (targetTouchesIterator == touchesByTarget.end())
3139 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).first;
3140
3141 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3142 // released or cancelled it will only appear in the changedTouches list.
3143 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3144 touches->append(touch);
3145 targetTouchesIterator->second->append(touch);
3146 }
3147
3148 // Now build up the correct list for changedTouches.
3149 // Note that any touches that are in the TouchStationary state (e.g. if
3150 // the user had several points touched but did not move them all) should
3151 // never be in the changedTouches list so we do not handle them explicitly here.
3152 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3153 // about the TouchStationary state.
3154 if (pointState != PlatformTouchPoint::TouchStationary) {
3155 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3156 if (!changedTouches[pointState].m_touches)
3157 changedTouches[pointState].m_touches = TouchList::create();
3158 changedTouches[pointState].m_touches->append(touch);
3159 changedTouches[pointState].m_targets.add(touchTarget);
3160 }
3161 }
3162 m_touchPressed = touches->length() > 0;
3163
3164 // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3165 bool defaultPrevented = false;
3166 RefPtr<TouchList> emptyList = TouchList::create();
3167 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3168 if (!changedTouches[state].m_touches)
3169 continue;
3170
3171 // When sending a touch cancel event, use empty touches and targetTouches lists.
3172 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3173 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3174 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3175 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3176
3177 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3178 EventTarget* touchEventTarget = it->get();
3179 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3180 ASSERT(targetTouches);
3181
3182 RefPtr<TouchEvent> touchEvent =
3183 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3184 stateName, touchEventTarget->toNode()->document()->defaultView(),
3185 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3186 ExceptionCode ec = 0;
3187 touchEventTarget->dispatchEvent(touchEvent.get(), ec);
3188 defaultPrevented |= touchEvent->defaultPrevented();
3189 }
3190 }
3191
3192 #if ENABLE(GESTURE_RECOGNIZER)
3193 if (m_gestureRecognizer)
3194 m_gestureRecognizer->processTouchEventForGesture(event, this, defaultPrevented);
3195 #endif
3196
3197 return defaultPrevented;
3198 }
3199 #endif
3200
3201 }
3202