• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 #include "core/page/EventHandler.h"
30 
31 #include "HTMLNames.h"
32 #include "RuntimeEnabledFeatures.h"
33 #include "SVGNames.h"
34 #include "bindings/v8/ExceptionStatePlaceholder.h"
35 #include "core/dom/Clipboard.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/DocumentMarkerController.h"
38 #include "core/dom/FullscreenElementStack.h"
39 #include "core/dom/NodeRenderingTraversal.h"
40 #include "core/dom/TouchList.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/editing/Editor.h"
43 #include "core/editing/FrameSelection.h"
44 #include "core/editing/TextIterator.h"
45 #include "core/editing/htmlediting.h"
46 #include "core/events/DOMWindowEventQueue.h"
47 #include "core/events/EventPath.h"
48 #include "core/events/KeyboardEvent.h"
49 #include "core/events/MouseEvent.h"
50 #include "core/events/TextEvent.h"
51 #include "core/events/ThreadLocalEventNames.h"
52 #include "core/events/TouchEvent.h"
53 #include "core/events/WheelEvent.h"
54 #include "core/fetch/ImageResource.h"
55 #include "core/html/HTMLDialogElement.h"
56 #include "core/html/HTMLFrameElementBase.h"
57 #include "core/html/HTMLFrameSetElement.h"
58 #include "core/html/HTMLInputElement.h"
59 #include "core/loader/FrameLoader.h"
60 #include "core/loader/FrameLoaderClient.h"
61 #include "core/page/AutoscrollController.h"
62 #include "core/page/BackForwardClient.h"
63 #include "core/page/Chrome.h"
64 #include "core/page/ChromeClient.h"
65 #include "core/page/DragController.h"
66 #include "core/page/DragState.h"
67 #include "core/page/EditorClient.h"
68 #include "core/page/FocusController.h"
69 #include "core/frame/Frame.h"
70 #include "core/page/FrameTree.h"
71 #include "core/frame/FrameView.h"
72 #include "core/inspector/InspectorController.h"
73 #include "core/page/MouseEventWithHitTestResults.h"
74 #include "core/page/Page.h"
75 #include "core/frame/Settings.h"
76 #include "core/page/SpatialNavigation.h"
77 #include "core/page/TouchAdjustment.h"
78 #include "core/platform/chromium/ChromiumDataObject.h"
79 #include "core/rendering/HitTestRequest.h"
80 #include "core/rendering/HitTestResult.h"
81 #include "core/rendering/RenderFlowThread.h"
82 #include "core/rendering/RenderLayer.h"
83 #include "core/rendering/RenderRegion.h"
84 #include "core/rendering/RenderTextControlSingleLine.h"
85 #include "core/rendering/RenderView.h"
86 #include "core/rendering/RenderWidget.h"
87 #include "core/rendering/style/CursorList.h"
88 #include "core/rendering/style/RenderStyle.h"
89 #include "core/svg/SVGDocument.h"
90 #include "core/svg/SVGElementInstance.h"
91 #include "core/svg/SVGUseElement.h"
92 #include "platform/PlatformGestureEvent.h"
93 #include "platform/PlatformKeyboardEvent.h"
94 #include "platform/PlatformTouchEvent.h"
95 #include "platform/PlatformWheelEvent.h"
96 #include "platform/WindowsKeyboardCodes.h"
97 #include "platform/geometry/FloatPoint.h"
98 #include "platform/graphics/Image.h"
99 #include "platform/scroll/ScrollAnimator.h"
100 #include "platform/scroll/Scrollbar.h"
101 #include "wtf/Assertions.h"
102 #include "wtf/CurrentTime.h"
103 #include "wtf/StdLibExtras.h"
104 #include "wtf/TemporaryChange.h"
105 
106 namespace WebCore {
107 
108 using namespace HTMLNames;
109 using namespace SVGNames;
110 
111 // The link drag hysteresis is much larger than the others because there
112 // needs to be enough space to cancel the link press without starting a link drag,
113 // and because dragging links is rare.
114 static const int LinkDragHysteresis = 40;
115 static const int ImageDragHysteresis = 5;
116 static const int TextDragHysteresis = 3;
117 static const int GeneralDragHysteresis = 3;
118 
119 // The amount of time to wait before sending a fake mouse event, triggered
120 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
121 // otherwise the long interval is used.
122 static const double fakeMouseMoveShortInterval = 0.1;
123 static const double fakeMouseMoveLongInterval = 0.250;
124 
125 // The amount of time to wait for a cursor update on style and layout changes
126 // Set to 50Hz, no need to be faster than common screen refresh rate
127 static const double cursorUpdateInterval = 0.02;
128 
129 static const int maximumCursorSize = 128;
130 
131 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
132 // need to ensure here is that the scale isn't so small that integer overflow can occur when
133 // dividing cursor sizes (limited above) by the scale.
134 static const double minimumCursorScale = 0.001;
135 
136 // The minimum amount of time an element stays active after a ShowPress
137 // This is roughly 2 frames, which should be long enough to be noticeable.
138 static const double minimumActiveInterval = 0.032;
139 
140 #if OS(MACOSX)
141 static const double TextDragDelay = 0.15;
142 #else
143 static const double TextDragDelay = 0.0;
144 #endif
145 
146 enum NoCursorChangeType { NoCursorChange };
147 
148 class OptionalCursor {
149 public:
OptionalCursor(NoCursorChangeType)150     OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
OptionalCursor(const Cursor & cursor)151     OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
152 
isCursorChange() const153     bool isCursorChange() const { return m_isCursorChange; }
cursor() const154     const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
155 
156 private:
157     bool m_isCursorChange;
158     Cursor m_cursor;
159 };
160 
161 class MaximumDurationTracker {
162 public:
MaximumDurationTracker(double * maxDuration)163     explicit MaximumDurationTracker(double *maxDuration)
164         : m_maxDuration(maxDuration)
165         , m_start(monotonicallyIncreasingTime())
166     {
167     }
168 
~MaximumDurationTracker()169     ~MaximumDurationTracker()
170     {
171         *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
172     }
173 
174 private:
175     double* m_maxDuration;
176     double m_start;
177 };
178 
179 class SyntheticTouchPoint : public PlatformTouchPoint {
180 public:
181 
182     // The default values are based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
SyntheticTouchPoint(const PlatformMouseEvent & event)183     explicit SyntheticTouchPoint(const PlatformMouseEvent& event)
184     {
185         const static int idDefaultValue = 0;
186         const static int radiusYDefaultValue = 1;
187         const static int radiusXDefaultValue = 1;
188         const static float rotationAngleDefaultValue = 0.0f;
189         const static float forceDefaultValue = 1.0f;
190 
191         m_id = idDefaultValue; // There is only one active TouchPoint.
192         m_screenPos = event.globalPosition();
193         m_pos = event.position();
194         m_radiusY = radiusYDefaultValue;
195         m_radiusX = radiusXDefaultValue;
196         m_rotationAngle = rotationAngleDefaultValue;
197         m_force = forceDefaultValue;
198 
199         PlatformEvent::Type type = event.type();
200         ASSERT(type == PlatformEvent::MouseMoved || type == PlatformEvent::MousePressed || type == PlatformEvent::MouseReleased);
201 
202         switch (type) {
203         case PlatformEvent::MouseMoved:
204             m_state = TouchMoved;
205             break;
206         case PlatformEvent::MousePressed:
207             m_state = TouchPressed;
208             break;
209         case PlatformEvent::MouseReleased:
210             m_state = TouchReleased;
211             break;
212         default:
213             ASSERT_NOT_REACHED();
214             break;
215         }
216     }
217 };
218 
219 class SyntheticSingleTouchEvent : public PlatformTouchEvent {
220 public:
SyntheticSingleTouchEvent(const PlatformMouseEvent & event)221     explicit SyntheticSingleTouchEvent(const PlatformMouseEvent& event)
222     {
223         switch (event.type()) {
224         case PlatformEvent::MouseMoved:
225             m_type = TouchMove;
226             break;
227         case PlatformEvent::MousePressed:
228             m_type = TouchStart;
229             break;
230         case PlatformEvent::MouseReleased:
231             m_type = TouchEnd;
232             break;
233         default:
234             ASSERT_NOT_REACHED();
235             m_type = NoType;
236             break;
237         }
238         m_timestamp = event.timestamp();
239         m_modifiers = event.modifiers();
240         m_touchPoints.append(SyntheticTouchPoint(event));
241     }
242 };
243 
wheelGranularityToScrollGranularity(unsigned deltaMode)244 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
245 {
246     switch (deltaMode) {
247     case WheelEvent::DOM_DELTA_PAGE:
248         return ScrollByPage;
249     case WheelEvent::DOM_DELTA_LINE:
250         return ScrollByLine;
251     case WheelEvent::DOM_DELTA_PIXEL:
252         return ScrollByPixel;
253     default:
254         return ScrollByPixel;
255     }
256 }
257 
scrollNode(float delta,ScrollGranularity granularity,ScrollDirection direction,Node * node,Node ** stopNode,IntPoint absolutePoint=IntPoint ())258 static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection direction, Node* node, Node** stopNode, IntPoint absolutePoint = IntPoint())
259 {
260     if (!delta)
261         return false;
262     if (!node->renderer())
263         return false;
264 
265     RenderBox* curBox = node->renderer()->enclosingBox();
266 
267     while (curBox && !curBox->isRenderView()) {
268         ScrollDirection physicalDirection = toPhysicalDirection(
269             direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode());
270 
271         if (curBox->scroll(physicalDirection, granularity, delta)) {
272             if (stopNode)
273                 *stopNode = curBox->node();
274             return true;
275         }
276 
277         if (stopNode && *stopNode && curBox->node() == *stopNode)
278             return true;
279 
280         // FIXME: This should probably move to a virtual method on RenderBox, something like RenderBox::scrollAncestor, and specialized for RenderFlowThread
281         curBox = curBox->containingBlock();
282         if (curBox && curBox->isRenderNamedFlowThread()) {
283             RenderBox* flowedBox = curBox;
284 
285             if (RenderBox* startBox = node->renderBox())
286                 flowedBox = startBox;
287 
288             curBox = toRenderFlowThread(curBox)->regionFromAbsolutePointAndBox(absolutePoint, flowedBox);
289         }
290     }
291 
292     return false;
293 }
294 
295 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
296 // If a mouse event handler changes the input element type to one that has a widget associated,
297 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
298 // event target node can't still be the shadow node.
shouldRefetchEventTarget(const MouseEventWithHitTestResults & mev)299 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
300 {
301     Node* targetNode = mev.targetNode();
302     if (!targetNode || !targetNode->parentNode())
303         return true;
304     return targetNode->isShadowRoot() && toShadowRoot(targetNode)->host()->hasTagName(inputTag);
305 }
306 
EventHandler(Frame * frame)307 EventHandler::EventHandler(Frame* frame)
308     : m_frame(frame)
309     , m_mousePressed(false)
310     , m_capturesDragging(false)
311     , m_mouseDownMayStartSelect(false)
312     , m_mouseDownMayStartDrag(false)
313     , m_mouseDownWasSingleClickInSelection(false)
314     , m_selectionInitiationState(HaveNotStartedSelection)
315     , m_panScrollButtonPressed(false)
316     , m_hoverTimer(this, &EventHandler::hoverTimerFired)
317     , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
318     , m_mouseDownMayStartAutoscroll(false)
319     , m_mouseDownWasInSubframe(false)
320     , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
321     , m_svgPan(false)
322     , m_resizeScrollableArea(0)
323     , m_eventHandlerWillResetCapturingMouseEventsNode(0)
324     , m_clickCount(0)
325     , m_shouldOnlyFireDragOverEvent(false)
326     , m_mousePositionIsUnknown(true)
327     , m_mouseDownTimestamp(0)
328     , m_widgetIsLatched(false)
329     , m_originatingTouchPointTargetKey(0)
330     , m_touchPressed(false)
331     , m_scrollGestureHandlingNode(0)
332     , m_lastHitTestResultOverWidget(false)
333     , m_maxMouseMovedDuration(0)
334     , m_baseEventType(PlatformEvent::NoType)
335     , m_didStartDrag(false)
336     , m_longTapShouldInvokeContextMenu(false)
337     , m_syntheticPageScaleFactor(0)
338     , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
339     , m_lastShowPressTimestamp(0)
340 {
341 }
342 
~EventHandler()343 EventHandler::~EventHandler()
344 {
345     ASSERT(!m_fakeMouseMoveEventTimer.isActive());
346 }
347 
dragState()348 DragState& EventHandler::dragState()
349 {
350     DEFINE_STATIC_LOCAL(DragState, state, ());
351     return state;
352 }
353 
clear()354 void EventHandler::clear()
355 {
356     m_hoverTimer.stop();
357     m_cursorUpdateTimer.stop();
358     m_fakeMouseMoveEventTimer.stop();
359     m_activeIntervalTimer.stop();
360     m_resizeScrollableArea = 0;
361     m_nodeUnderMouse = 0;
362     m_lastNodeUnderMouse = 0;
363     m_instanceUnderMouse = 0;
364     m_lastInstanceUnderMouse = 0;
365     m_lastMouseMoveEventSubframe = 0;
366     m_lastScrollbarUnderMouse = 0;
367     m_clickCount = 0;
368     m_clickNode = 0;
369     m_frameSetBeingResized = 0;
370     m_dragTarget = 0;
371     m_shouldOnlyFireDragOverEvent = false;
372     m_mousePositionIsUnknown = true;
373     m_lastKnownMousePosition = IntPoint();
374     m_lastKnownMouseGlobalPosition = IntPoint();
375     m_lastMouseDownUserGestureToken.clear();
376     m_mousePressNode = 0;
377     m_mousePressed = false;
378     m_capturesDragging = false;
379     m_capturingMouseEventsNode = 0;
380     m_latchedWheelEventNode = 0;
381     m_previousWheelScrolledNode = 0;
382     m_originatingTouchPointTargets.clear();
383     m_originatingTouchPointDocument.clear();
384     m_originatingTouchPointTargetKey = 0;
385     m_scrollGestureHandlingNode = 0;
386     m_lastHitTestResultOverWidget = false;
387     m_previousGestureScrolledNode = 0;
388     m_scrollbarHandlingScrollGesture = 0;
389     m_maxMouseMovedDuration = 0;
390     m_baseEventType = PlatformEvent::NoType;
391     m_didStartDrag = false;
392     m_touchPressed = false;
393     m_mouseDownMayStartSelect = false;
394     m_mouseDownMayStartDrag = false;
395     m_lastShowPressTimestamp = 0;
396     m_lastDeferredTapElement = 0;
397 }
398 
nodeWillBeRemoved(Node & nodeToBeRemoved)399 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
400 {
401     if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
402         return;
403     if (nodeToBeRemoved.isInShadowTree()) {
404         m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
405     } else {
406         // We don't dispatch click events if the mousedown node is removed
407         // before a mouseup event. It is compatible with IE and Firefox.
408         m_clickNode = 0;
409     }
410 }
411 
setSelectionIfNeeded(FrameSelection & selection,const VisibleSelection & newSelection)412 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
413 {
414     if (selection.selection() != newSelection)
415         selection.setSelection(newSelection);
416 }
417 
dispatchSelectStart(Node * node)418 static inline bool dispatchSelectStart(Node* node)
419 {
420     if (!node || !node->renderer())
421         return true;
422 
423     return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
424 }
425 
expandSelectionToRespectUserSelectAll(Node * targetNode,const VisibleSelection & selection)426 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
427 {
428     Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
429     if (!rootUserSelectAll)
430         return selection;
431 
432     VisibleSelection newSelection(selection);
433     newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
434     newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
435 
436     return newSelection;
437 }
438 
updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode,const VisibleSelection & selection,TextGranularity granularity)439 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
440 {
441     if (Position::nodeIsUserSelectNone(targetNode))
442         return false;
443 
444     if (!dispatchSelectStart(targetNode))
445         return false;
446 
447     if (selection.isRange())
448         m_selectionInitiationState = ExtendedSelection;
449     else {
450         granularity = CharacterGranularity;
451         m_selectionInitiationState = PlacedCaret;
452     }
453 
454     m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
455 
456     return true;
457 }
458 
selectClosestWordFromHitTestResult(const HitTestResult & result,AppendTrailingWhitespace appendTrailingWhitespace)459 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
460 {
461     Node* innerNode = result.targetNode();
462     VisibleSelection newSelection;
463 
464     if (innerNode && innerNode->renderer()) {
465         VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
466         if (pos.isNotNull()) {
467             newSelection = VisibleSelection(pos);
468             newSelection.expandUsingGranularity(WordGranularity);
469         }
470 
471         if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
472             newSelection.appendTrailingWhitespace();
473 
474         updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
475     }
476 }
477 
selectClosestMisspellingFromHitTestResult(const HitTestResult & result,AppendTrailingWhitespace appendTrailingWhitespace)478 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
479 {
480     Node* innerNode = result.targetNode();
481     VisibleSelection newSelection;
482 
483     if (innerNode && innerNode->renderer()) {
484         VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
485         Position start = pos.deepEquivalent();
486         Position end = pos.deepEquivalent();
487         if (pos.isNotNull()) {
488             Vector<DocumentMarker*> markers = innerNode->document().markers()->markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
489             if (markers.size() == 1) {
490                 start.moveToOffset(markers[0]->startOffset());
491                 end.moveToOffset(markers[0]->endOffset());
492                 newSelection = VisibleSelection(start, end);
493             }
494         }
495 
496         if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
497             newSelection.appendTrailingWhitespace();
498 
499         updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
500     }
501 }
502 
selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults & result)503 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
504 {
505     if (m_mouseDownMayStartSelect) {
506         selectClosestWordFromHitTestResult(result.hitTestResult(),
507             (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
508     }
509 }
510 
selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults & result)511 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
512 {
513     if (m_mouseDownMayStartSelect) {
514         selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
515             (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
516     }
517 }
518 
selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults & result)519 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
520 {
521     if (!result.hitTestResult().isLiveLink())
522         return selectClosestWordFromMouseEvent(result);
523 
524     Node* innerNode = result.targetNode();
525 
526     if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
527         VisibleSelection newSelection;
528         Element* URLElement = result.hitTestResult().URLElement();
529         VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
530         if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
531             newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
532 
533         updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
534     }
535 }
536 
handleMousePressEventDoubleClick(const MouseEventWithHitTestResults & event)537 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
538 {
539     if (event.event().button() != LeftButton)
540         return false;
541 
542     if (m_frame->selection().isRange()) {
543         // A double-click when range is already selected
544         // should not change the selection.  So, do not call
545         // selectClosestWordFromMouseEvent, but do set
546         // m_beganSelectingText to prevent handleMouseReleaseEvent
547         // from setting caret selection.
548         m_selectionInitiationState = ExtendedSelection;
549     } else {
550         selectClosestWordFromMouseEvent(event);
551     }
552     return true;
553 }
554 
handleMousePressEventTripleClick(const MouseEventWithHitTestResults & event)555 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
556 {
557     if (event.event().button() != LeftButton)
558         return false;
559 
560     Node* innerNode = event.targetNode();
561     if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
562         return false;
563 
564     VisibleSelection newSelection;
565     VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
566     if (pos.isNotNull()) {
567         newSelection = VisibleSelection(pos);
568         newSelection.expandUsingGranularity(ParagraphGranularity);
569     }
570 
571     return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
572 }
573 
textDistance(const Position & start,const Position & end)574 static int textDistance(const Position& start, const Position& end)
575 {
576     RefPtr<Range> range = Range::create(*start.document(), start, end);
577     return TextIterator::rangeLength(range.get(), true);
578 }
579 
handleMousePressEventSingleClick(const MouseEventWithHitTestResults & event)580 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
581 {
582     m_frame->document()->updateLayoutIgnorePendingStylesheets();
583     Node* innerNode = event.targetNode();
584     if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
585         return false;
586 
587     // Extend the selection if the Shift key is down, unless the click is in a link.
588     bool extendSelection = event.event().shiftKey() && !event.isOverLink();
589 
590     // Don't restart the selection when the mouse is pressed on an
591     // existing selection so we can allow for text dragging.
592     if (FrameView* view = m_frame->view()) {
593         LayoutPoint vPoint = view->windowToContents(event.event().position());
594         if (!extendSelection && m_frame->selection().contains(vPoint)) {
595             m_mouseDownWasSingleClickInSelection = true;
596             return false;
597         }
598     }
599 
600     VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
601     if (visiblePos.isNull())
602         visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
603     Position pos = visiblePos.deepEquivalent();
604 
605     VisibleSelection newSelection = m_frame->selection().selection();
606     TextGranularity granularity = CharacterGranularity;
607 
608     if (extendSelection && newSelection.isCaretOrRange()) {
609         VisibleSelection selectionInUserSelectAll = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(pos));
610         if (selectionInUserSelectAll.isRange()) {
611             if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
612                 pos = selectionInUserSelectAll.start();
613             else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
614                 pos = selectionInUserSelectAll.end();
615         }
616 
617         if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
618             // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
619             // was created right-to-left
620             Position start = newSelection.start();
621             Position end = newSelection.end();
622             int distanceToStart = textDistance(start, pos);
623             int distanceToEnd = textDistance(pos, end);
624             if (distanceToStart <= distanceToEnd)
625                 newSelection = VisibleSelection(end, pos);
626             else
627                 newSelection = VisibleSelection(start, pos);
628         } else
629             newSelection.setExtent(pos);
630 
631         if (m_frame->selection().granularity() != CharacterGranularity) {
632             granularity = m_frame->selection().granularity();
633             newSelection.expandUsingGranularity(m_frame->selection().granularity());
634         }
635     } else
636         newSelection = expandSelectionToRespectUserSelectAll(innerNode, visiblePos);
637 
638     bool handled = updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
639     return handled;
640 }
641 
canMouseDownStartSelect(Node * node)642 static inline bool canMouseDownStartSelect(Node* node)
643 {
644     if (!node || !node->renderer())
645         return true;
646 
647     if (!node->canStartSelection())
648         return false;
649 
650     return true;
651 }
652 
handleMousePressEvent(const MouseEventWithHitTestResults & event)653 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
654 {
655     // Reset drag state.
656     dragState().m_dragSrc = 0;
657 
658     cancelFakeMouseMoveEvent();
659 
660     m_frame->document()->updateLayoutIgnorePendingStylesheets();
661 
662     if (ScrollView* scrollView = m_frame->view()) {
663         if (scrollView->isPointInScrollbarCorner(event.event().position()))
664             return false;
665     }
666 
667     bool singleClick = event.event().clickCount() <= 1;
668 
669     // If we got the event back, that must mean it wasn't prevented,
670     // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
671     m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
672 
673     m_mouseDownMayStartDrag = singleClick;
674 
675     m_mouseDownWasSingleClickInSelection = false;
676 
677     m_mouseDown = event.event();
678 
679     if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
680         return true;
681 
682     if (m_frame->document()->isSVGDocument()
683         && toSVGDocument(m_frame->document())->zoomAndPanEnabled()) {
684         if (event.event().shiftKey() && singleClick) {
685             m_svgPan = true;
686             toSVGDocument(m_frame->document())->startPan(m_frame->view()->windowToContents(event.event().position()));
687             return true;
688         }
689     }
690 
691     // We don't do this at the start of mouse down handling,
692     // because we don't want to do it until we know we didn't hit a widget.
693     if (singleClick)
694         focusDocumentView();
695 
696     Node* innerNode = event.targetNode();
697 
698     m_mousePressNode = innerNode;
699     m_dragStartPos = event.event().position();
700 
701     bool swallowEvent = false;
702     m_mousePressed = true;
703     m_selectionInitiationState = HaveNotStartedSelection;
704 
705     if (event.event().clickCount() == 2)
706         swallowEvent = handleMousePressEventDoubleClick(event);
707     else if (event.event().clickCount() >= 3)
708         swallowEvent = handleMousePressEventTripleClick(event);
709     else
710         swallowEvent = handleMousePressEventSingleClick(event);
711 
712     m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
713         || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
714 
715     return swallowEvent;
716 }
717 
handleMouseDraggedEvent(const MouseEventWithHitTestResults & event)718 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
719 {
720     if (!m_mousePressed)
721         return false;
722 
723     if (handleDrag(event, ShouldCheckDragHysteresis))
724         return true;
725 
726     Node* targetNode = event.targetNode();
727     if (event.event().button() != LeftButton || !targetNode)
728         return false;
729 
730     RenderObject* renderer = targetNode->renderer();
731     if (!renderer) {
732         Node* parent = EventPath::parent(targetNode);
733         if (!parent)
734             return false;
735 
736         renderer = parent->renderer();
737         if (!renderer || !renderer->isListBox())
738             return false;
739     }
740 
741     m_mouseDownMayStartDrag = false;
742 
743     if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
744         if (AutoscrollController* controller = autoscrollController()) {
745             controller->startAutoscrollForSelection(renderer);
746             m_mouseDownMayStartAutoscroll = false;
747         }
748     }
749 
750     if (m_selectionInitiationState != ExtendedSelection) {
751         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
752         HitTestResult result(m_mouseDownPos);
753         m_frame->document()->renderView()->hitTest(request, result);
754 
755         updateSelectionForMouseDrag(result);
756     }
757     updateSelectionForMouseDrag(event.hitTestResult());
758     return true;
759 }
760 
updateSelectionForMouseDrag()761 void EventHandler::updateSelectionForMouseDrag()
762 {
763     FrameView* view = m_frame->view();
764     if (!view)
765         return;
766     RenderView* renderer = m_frame->contentRenderer();
767     if (!renderer)
768         return;
769 
770     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
771     HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
772     renderer->hitTest(request, result);
773     updateSelectionForMouseDrag(result);
774 }
775 
updateSelectionForMouseDrag(const HitTestResult & hitTestResult)776 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
777 {
778     if (!m_mouseDownMayStartSelect)
779         return;
780 
781     Node* target = hitTestResult.targetNode();
782     if (!target)
783         return;
784 
785     VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
786     // Don't modify the selection if we're not on a node.
787     if (targetPosition.isNull())
788         return;
789 
790     // Restart the selection if this is the first mouse move. This work is usually
791     // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
792     VisibleSelection newSelection = m_frame->selection().selection();
793 
794     // Special case to limit selection to the containing block for SVG text.
795     // FIXME: Isn't there a better non-SVG-specific way to do this?
796     if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
797         if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
798             if (selectionBaseRenderer->isSVGText())
799                 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
800                     return;
801 
802     if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
803         return;
804 
805     if (m_selectionInitiationState != ExtendedSelection) {
806         // Always extend selection here because it's caused by a mouse drag
807         m_selectionInitiationState = ExtendedSelection;
808         newSelection = VisibleSelection(targetPosition);
809     }
810 
811     if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
812         Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
813         if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
814             newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
815             newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
816         } else {
817             // Reset base for user select all when base is inside user-select-all area and extent < base.
818             if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
819                 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
820 
821             Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
822             if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
823                 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
824             else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
825                 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
826             else
827                 newSelection.setExtent(targetPosition);
828         }
829     } else {
830         newSelection.setExtent(targetPosition);
831     }
832 
833     if (m_frame->selection().granularity() != CharacterGranularity)
834         newSelection.expandUsingGranularity(m_frame->selection().granularity());
835 
836     m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
837         FrameSelection::AdjustEndpointsAtBidiBoundary);
838 }
839 
handleMouseReleaseEvent(const MouseEventWithHitTestResults & event)840 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
841 {
842     AutoscrollController* controller = autoscrollController();
843     if (controller && controller->autoscrollInProgress())
844         stopAutoscroll();
845 
846     // Used to prevent mouseMoveEvent from initiating a drag before
847     // the mouse is pressed again.
848     m_mousePressed = false;
849     m_capturesDragging = false;
850     m_mouseDownMayStartDrag = false;
851     m_mouseDownMayStartSelect = false;
852     m_mouseDownMayStartAutoscroll = false;
853     m_mouseDownWasInSubframe = false;
854 
855     bool handled = false;
856 
857     // Clear the selection if the mouse didn't move after the last mouse
858     // press and it's not a context menu click.  We do this so when clicking
859     // on the selection, the selection goes away.  However, if we are
860     // editing, place the caret.
861     if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
862             && m_dragStartPos == event.event().position()
863             && m_frame->selection().isRange()
864             && event.event().button() != RightButton) {
865         VisibleSelection newSelection;
866         Node* node = event.targetNode();
867         bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
868         if (node && node->renderer() && (caretBrowsing || node->rendererIsEditable())) {
869             VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
870             newSelection = VisibleSelection(pos);
871         }
872 
873         setSelectionIfNeeded(m_frame->selection(), newSelection);
874 
875         handled = true;
876     }
877 
878     m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
879 
880     m_frame->selection().selectFrameElementInParentIfFullySelected();
881 
882     if (event.event().button() == MiddleButton && !event.isOverLink()) {
883         // Ignore handled, since we want to paste to where the caret was placed anyway.
884         handled = handlePasteGlobalSelection(event.event()) || handled;
885     }
886 
887     return handled;
888 }
889 
890 #if OS(WIN)
891 
startPanScrolling(RenderObject * renderer)892 void EventHandler::startPanScrolling(RenderObject* renderer)
893 {
894     if (!renderer->isBox())
895         return;
896     AutoscrollController* controller = autoscrollController();
897     if (!controller)
898         return;
899     controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
900     invalidateClick();
901 }
902 
903 #endif // OS(WIN)
904 
autoscrollController() const905 AutoscrollController* EventHandler::autoscrollController() const
906 {
907     if (Page* page = m_frame->page())
908         return &page->autoscrollController();
909     return 0;
910 }
911 
panScrollInProgress() const912 bool EventHandler::panScrollInProgress() const
913 {
914     return autoscrollController() && autoscrollController()->panScrollInProgress();
915 }
916 
hitTestResultAtPoint(const LayoutPoint & point,HitTestRequest::HitTestRequestType hitType,const LayoutSize & padding)917 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
918 {
919     // We always send hitTestResultAtPoint to the main frame if we have one,
920     // otherwise we might hit areas that are obscured by higher frames.
921     if (Page* page = m_frame->page()) {
922         Frame* mainFrame = page->mainFrame();
923         if (m_frame != mainFrame) {
924             FrameView* frameView = m_frame->view();
925             FrameView* mainView = mainFrame->view();
926             if (frameView && mainView) {
927                 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
928                 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
929             }
930         }
931     }
932 
933     HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
934 
935     // RenderView::hitTest causes a layout, and we don't want to hit that until the first
936     // layout because until then, there is nothing shown on the screen - the user can't
937     // have intentionally clicked on something belonging to this page. Furthermore,
938     // mousemove events before the first layout should not lead to a premature layout()
939     // happening, which could show a flash of white.
940     // See also the similar code in Document::prepareMouseEvent.
941     if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
942         return result;
943 
944     // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
945     HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
946     m_frame->contentRenderer()->hitTest(request, result);
947     if (!request.readOnly())
948         m_frame->document()->updateHoverActiveState(request, result.innerElement());
949 
950     if (request.disallowsShadowContent())
951         result.setToNodesInDocumentTreeScope();
952 
953     return result;
954 }
955 
stopAutoscroll()956 void EventHandler::stopAutoscroll()
957 {
958     if (AutoscrollController* controller = autoscrollController())
959         controller->stopAutoscroll();
960 }
961 
mousePressNode() const962 Node* EventHandler::mousePressNode() const
963 {
964     return m_mousePressNode.get();
965 }
966 
scrollOverflow(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)967 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
968 {
969     Node* node = startingNode;
970 
971     if (!node)
972         node = m_frame->document()->focusedElement();
973 
974     if (!node)
975         node = m_mousePressNode.get();
976 
977     if (node) {
978         RenderObject* r = node->renderer();
979         if (r && !r->isListBox() && scrollNode(1.0f, granularity, direction, node, 0)) {
980             setFrameWasScrolledByUser();
981             return true;
982         }
983     }
984 
985     return false;
986 }
987 
scrollRecursively(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)988 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
989 {
990     // The layout needs to be up to date to determine if we can scroll. We may be
991     // here because of an onLoad event, in which case the final layout hasn't been performed yet.
992     m_frame->document()->updateLayoutIgnorePendingStylesheets();
993     if (scrollOverflow(direction, granularity, startingNode))
994         return true;
995     Frame* frame = m_frame;
996     FrameView* view = frame->view();
997     if (view && view->scroll(direction, granularity))
998         return true;
999     frame = frame->tree().parent();
1000     if (!frame)
1001         return false;
1002     return frame->eventHandler().scrollRecursively(direction, granularity, m_frame->ownerElement());
1003 }
1004 
lastKnownMousePosition() const1005 IntPoint EventHandler::lastKnownMousePosition() const
1006 {
1007     return m_lastKnownMousePosition;
1008 }
1009 
subframeForTargetNode(Node * node)1010 static Frame* subframeForTargetNode(Node* node)
1011 {
1012     if (!node)
1013         return 0;
1014 
1015     RenderObject* renderer = node->renderer();
1016     if (!renderer || !renderer->isWidget())
1017         return 0;
1018 
1019     Widget* widget = toRenderWidget(renderer)->widget();
1020     if (!widget || !widget->isFrameView())
1021         return 0;
1022 
1023     return &toFrameView(widget)->frame();
1024 }
1025 
subframeForHitTestResult(const MouseEventWithHitTestResults & hitTestResult)1026 static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1027 {
1028     if (!hitTestResult.isOverWidget())
1029         return 0;
1030     return subframeForTargetNode(hitTestResult.targetNode());
1031 }
1032 
isSubmitImage(Node * node)1033 static bool isSubmitImage(Node* node)
1034 {
1035     return node && node->hasTagName(inputTag) && toHTMLInputElement(node)->isImageButton();
1036 }
1037 
1038 // Returns true if the node's editable block is not current focused for editing
nodeIsNotBeingEdited(Node * node,Frame * frame)1039 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1040 {
1041     return frame->selection().rootEditableElement() != node->rootEditableElement();
1042 }
1043 
useHandCursor(Node * node,bool isOverLink,bool shiftKey)1044 bool EventHandler::useHandCursor(Node* node, bool isOverLink, bool shiftKey)
1045 {
1046     if (!node)
1047         return false;
1048 
1049     bool editable = node->rendererIsEditable();
1050     bool editableLinkEnabled = false;
1051 
1052     // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1053     if (editable) {
1054         ASSERT(m_frame->settings());
1055         switch (m_frame->settings()->editableLinkBehavior()) {
1056         default:
1057         case EditableLinkDefaultBehavior:
1058         case EditableLinkAlwaysLive:
1059             editableLinkEnabled = true;
1060             break;
1061 
1062         case EditableLinkNeverLive:
1063             editableLinkEnabled = false;
1064             break;
1065 
1066         case EditableLinkLiveWhenNotFocused:
1067             editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || shiftKey;
1068             break;
1069 
1070         case EditableLinkOnlyLiveWithShiftKey:
1071             editableLinkEnabled = shiftKey;
1072             break;
1073         }
1074     }
1075 
1076     return ((isOverLink || isSubmitImage(node)) && (!editable || editableLinkEnabled));
1077 }
1078 
cursorUpdateTimerFired(Timer<EventHandler> *)1079 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
1080 {
1081     ASSERT(m_frame);
1082     ASSERT(m_frame->document());
1083 
1084     updateCursor();
1085 }
1086 
updateCursor()1087 void EventHandler::updateCursor()
1088 {
1089     if (m_mousePositionIsUnknown)
1090         return;
1091 
1092     FrameView* view = m_frame->view();
1093     if (!view || !view->shouldSetCursor())
1094         return;
1095 
1096     RenderView* renderView = view->renderView();
1097     if (!renderView)
1098         return;
1099 
1100     bool shiftKey;
1101     bool ctrlKey;
1102     bool altKey;
1103     bool metaKey;
1104     PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
1105 
1106     m_frame->document()->updateLayout();
1107 
1108     HitTestRequest request(HitTestRequest::ReadOnly);
1109     HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1110     renderView->hitTest(request, result);
1111 
1112     OptionalCursor optionalCursor = selectCursor(result, shiftKey);
1113     if (optionalCursor.isCursorChange()) {
1114         m_currentMouseCursor = optionalCursor.cursor();
1115         view->setCursor(m_currentMouseCursor);
1116     }
1117 }
1118 
selectCursor(const HitTestResult & result,bool shiftKey)1119 OptionalCursor EventHandler::selectCursor(const HitTestResult& result, bool shiftKey)
1120 {
1121     if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1122         return NoCursorChange;
1123 
1124     Page* page = m_frame->page();
1125     if (!page)
1126         return NoCursorChange;
1127 #if OS(WIN)
1128     if (panScrollInProgress())
1129         return NoCursorChange;
1130 #endif
1131 
1132     Node* node = result.targetNode();
1133     if (!node)
1134         return selectAutoCursor(result, node, iBeamCursor(), shiftKey);
1135 
1136     RenderObject* renderer = node->renderer();
1137     RenderStyle* style = renderer ? renderer->style() : 0;
1138 
1139     if (renderer) {
1140         Cursor overrideCursor;
1141         switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1142         case SetCursorBasedOnStyle:
1143             break;
1144         case SetCursor:
1145             return overrideCursor;
1146         case DoNotSetCursor:
1147             return NoCursorChange;
1148         }
1149     }
1150 
1151     if (style && style->cursors()) {
1152         const CursorList* cursors = style->cursors();
1153         for (unsigned i = 0; i < cursors->size(); ++i) {
1154             StyleImage* styleImage = (*cursors)[i].image();
1155             if (!styleImage)
1156                 continue;
1157             ImageResource* cachedImage = styleImage->cachedImage();
1158             if (!cachedImage)
1159                 continue;
1160             float scale = styleImage->imageScaleFactor();
1161             // Get hotspot and convert from logical pixels to physical pixels.
1162             IntPoint hotSpot = (*cursors)[i].hotSpot();
1163             hotSpot.scale(scale, scale);
1164             IntSize size = cachedImage->imageForRenderer(renderer)->size();
1165             if (cachedImage->errorOccurred())
1166                 continue;
1167             // Limit the size of cursors (in UI pixels) so that they cannot be
1168             // used to cover UI elements in chrome.
1169             size.scale(1 / scale);
1170             if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1171                 continue;
1172 
1173             Image* image = cachedImage->imageForRenderer(renderer);
1174             // Ensure no overflow possible in calculations above.
1175             if (scale < minimumCursorScale)
1176                 continue;
1177             return Cursor(image, hotSpot, scale);
1178         }
1179     }
1180 
1181     switch (style ? style->cursor() : CURSOR_AUTO) {
1182     case CURSOR_AUTO: {
1183         bool horizontalText = !style || style->isHorizontalWritingMode();
1184         const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1185         return selectAutoCursor(result, node, iBeam, shiftKey);
1186     }
1187     case CURSOR_CROSS:
1188         return crossCursor();
1189     case CURSOR_POINTER:
1190         return handCursor();
1191     case CURSOR_MOVE:
1192         return moveCursor();
1193     case CURSOR_ALL_SCROLL:
1194         return moveCursor();
1195     case CURSOR_E_RESIZE:
1196         return eastResizeCursor();
1197     case CURSOR_W_RESIZE:
1198         return westResizeCursor();
1199     case CURSOR_N_RESIZE:
1200         return northResizeCursor();
1201     case CURSOR_S_RESIZE:
1202         return southResizeCursor();
1203     case CURSOR_NE_RESIZE:
1204         return northEastResizeCursor();
1205     case CURSOR_SW_RESIZE:
1206         return southWestResizeCursor();
1207     case CURSOR_NW_RESIZE:
1208         return northWestResizeCursor();
1209     case CURSOR_SE_RESIZE:
1210         return southEastResizeCursor();
1211     case CURSOR_NS_RESIZE:
1212         return northSouthResizeCursor();
1213     case CURSOR_EW_RESIZE:
1214         return eastWestResizeCursor();
1215     case CURSOR_NESW_RESIZE:
1216         return northEastSouthWestResizeCursor();
1217     case CURSOR_NWSE_RESIZE:
1218         return northWestSouthEastResizeCursor();
1219     case CURSOR_COL_RESIZE:
1220         return columnResizeCursor();
1221     case CURSOR_ROW_RESIZE:
1222         return rowResizeCursor();
1223     case CURSOR_TEXT:
1224         return iBeamCursor();
1225     case CURSOR_WAIT:
1226         return waitCursor();
1227     case CURSOR_HELP:
1228         return helpCursor();
1229     case CURSOR_VERTICAL_TEXT:
1230         return verticalTextCursor();
1231     case CURSOR_CELL:
1232         return cellCursor();
1233     case CURSOR_CONTEXT_MENU:
1234         return contextMenuCursor();
1235     case CURSOR_PROGRESS:
1236         return progressCursor();
1237     case CURSOR_NO_DROP:
1238         return noDropCursor();
1239     case CURSOR_ALIAS:
1240         return aliasCursor();
1241     case CURSOR_COPY:
1242         return copyCursor();
1243     case CURSOR_NONE:
1244         return noneCursor();
1245     case CURSOR_NOT_ALLOWED:
1246         return notAllowedCursor();
1247     case CURSOR_DEFAULT:
1248         return pointerCursor();
1249     case CURSOR_WEBKIT_ZOOM_IN:
1250         return zoomInCursor();
1251     case CURSOR_WEBKIT_ZOOM_OUT:
1252         return zoomOutCursor();
1253     case CURSOR_WEBKIT_GRAB:
1254         return grabCursor();
1255     case CURSOR_WEBKIT_GRABBING:
1256         return grabbingCursor();
1257     }
1258     return pointerCursor();
1259 }
1260 
selectAutoCursor(const HitTestResult & result,Node * node,const Cursor & iBeam,bool shiftKey)1261 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam, bool shiftKey)
1262 {
1263     bool editable = (node && node->rendererIsEditable());
1264 
1265     if (useHandCursor(node, result.isOverLink(), shiftKey))
1266         return handCursor();
1267 
1268     bool inResizer = false;
1269     RenderObject* renderer = node ? node->renderer() : 0;
1270     if (renderer) {
1271         if (RenderLayer* layer = renderer->enclosingLayer()) {
1272             if (m_frame->view())
1273                 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1274         }
1275     }
1276 
1277     // During selection, use an I-beam no matter what we're over.
1278     // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1279     if (m_mousePressed && m_mouseDownMayStartSelect
1280         && !m_mouseDownMayStartDrag
1281         && m_frame->selection().isCaretOrRange()
1282         && !m_capturingMouseEventsNode) {
1283         return iBeam;
1284     }
1285 
1286     if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1287         return iBeam;
1288     return pointerCursor();
1289 }
1290 
documentPointForWindowPoint(Frame * frame,const IntPoint & windowPoint)1291 static LayoutPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1292 {
1293     FrameView* view = frame->view();
1294     // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1295     // Historically the code would just crash; this is clearly no worse than that.
1296     return view ? view->windowToContents(windowPoint) : windowPoint;
1297 }
1298 
handleMousePressEvent(const PlatformMouseEvent & mouseEvent)1299 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1300 {
1301     RefPtr<FrameView> protector(m_frame->view());
1302 
1303     bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1304     if (defaultPrevented)
1305         return true;
1306 
1307     UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1308     m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1309 
1310     cancelFakeMouseMoveEvent();
1311     if (m_eventHandlerWillResetCapturingMouseEventsNode)
1312         m_capturingMouseEventsNode = 0;
1313     m_mousePressed = true;
1314     m_capturesDragging = true;
1315     setLastKnownMousePosition(mouseEvent);
1316     m_mouseDownTimestamp = mouseEvent.timestamp();
1317     m_mouseDownMayStartDrag = false;
1318     m_mouseDownMayStartSelect = false;
1319     m_mouseDownMayStartAutoscroll = false;
1320     if (FrameView* view = m_frame->view())
1321         m_mouseDownPos = view->windowToContents(mouseEvent.position());
1322     else {
1323         invalidateClick();
1324         return false;
1325     }
1326     m_mouseDownWasInSubframe = false;
1327 
1328     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1329     if (mouseEvent.fromTouch())
1330         hitType |= HitTestRequest::ReadOnly;
1331     HitTestRequest request(hitType);
1332     // Save the document point we generate in case the window coordinate is invalidated by what happens
1333     // when we dispatch the event.
1334     LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1335     MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1336 
1337     if (!mev.targetNode()) {
1338         invalidateClick();
1339         return false;
1340     }
1341 
1342     m_mousePressNode = mev.targetNode();
1343 
1344     RefPtr<Frame> subframe = subframeForHitTestResult(mev);
1345     if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1346         // Start capturing future events for this frame.  We only do this if we didn't clear
1347         // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1348         m_capturesDragging = subframe->eventHandler().capturesDragging();
1349         if (m_mousePressed && m_capturesDragging) {
1350             m_capturingMouseEventsNode = mev.targetNode();
1351             m_eventHandlerWillResetCapturingMouseEventsNode = true;
1352         }
1353         invalidateClick();
1354         return true;
1355     }
1356 
1357 #if OS(WIN)
1358     // We store whether pan scrolling is in progress before calling stopAutoscroll()
1359     // because it will set m_autoscrollType to NoAutoscroll on return.
1360     bool isPanScrollInProgress = panScrollInProgress();
1361     stopAutoscroll();
1362     if (isPanScrollInProgress) {
1363         // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1364         // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1365         invalidateClick();
1366         return true;
1367     }
1368 #endif
1369 
1370     m_clickCount = mouseEvent.clickCount();
1371     m_clickNode = mev.targetNode()->isTextNode() ?  mev.targetNode()->parentOrShadowHostNode() : mev.targetNode();
1372 
1373     if (FrameView* view = m_frame->view()) {
1374         RenderLayer* layer = mev.targetNode()->renderer() ? mev.targetNode()->renderer()->enclosingLayer() : 0;
1375         IntPoint p = view->windowToContents(mouseEvent.position());
1376         if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1377             m_resizeScrollableArea = layer->scrollableArea();
1378             m_resizeScrollableArea->setInResizeMode(true);
1379             m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1380             invalidateClick();
1381             return true;
1382         }
1383     }
1384 
1385     m_frame->selection().setCaretBlinkingSuspended(true);
1386 
1387     bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.targetNode(), true, m_clickCount, mouseEvent, true);
1388     m_capturesDragging = !swallowEvent || mev.scrollbar();
1389 
1390     // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1391     // in case the scrollbar widget was destroyed when the mouse event was handled.
1392     if (mev.scrollbar()) {
1393         const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1394         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1395         mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1396         if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1397             m_lastScrollbarUnderMouse = 0;
1398     }
1399 
1400     if (swallowEvent) {
1401         // scrollbars should get events anyway, even disabled controls might be scrollable
1402         Scrollbar* scrollbar = mev.scrollbar();
1403 
1404         updateLastScrollbarUnderMouse(scrollbar, true);
1405 
1406         if (scrollbar)
1407             passMousePressEventToScrollbar(mev, scrollbar);
1408     } else {
1409         if (shouldRefetchEventTarget(mev)) {
1410             HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1411             mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1412         }
1413 
1414         FrameView* view = m_frame->view();
1415         Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.position()) : 0;
1416         if (!scrollbar)
1417             scrollbar = mev.scrollbar();
1418 
1419         updateLastScrollbarUnderMouse(scrollbar, true);
1420 
1421         if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1422             swallowEvent = true;
1423         else
1424             swallowEvent = handleMousePressEvent(mev);
1425     }
1426 
1427     return swallowEvent;
1428 }
1429 
layerForNode(Node * node)1430 static RenderLayer* layerForNode(Node* node)
1431 {
1432     if (!node)
1433         return 0;
1434 
1435     RenderObject* renderer = node->renderer();
1436     if (!renderer)
1437         return 0;
1438 
1439     RenderLayer* layer = renderer->enclosingLayer();
1440     if (!layer)
1441         return 0;
1442 
1443     return layer;
1444 }
1445 
associatedScrollableArea(const RenderLayer * layer) const1446 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1447 {
1448     ScrollableArea* layerScrollableArea = layer->scrollableArea();
1449     if (!layerScrollableArea)
1450         return 0;
1451 
1452     if (FrameView* frameView = m_frame->view()) {
1453         if (frameView->containsScrollableArea(layerScrollableArea))
1454             return layerScrollableArea;
1455     }
1456 
1457     return 0;
1458 }
1459 
handleMouseMoveEvent(const PlatformMouseEvent & event)1460 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1461 {
1462     RefPtr<FrameView> protector(m_frame->view());
1463     MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1464 
1465     HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1466     bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1467 
1468     Page* page = m_frame->page();
1469     if (!page)
1470         return result;
1471 
1472     if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1473         if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1474             layerScrollableArea->mouseMovedInContentArea();
1475     }
1476 
1477     if (FrameView* frameView = m_frame->view())
1478         frameView->mouseMovedInContentArea();
1479 
1480     hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1481     page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1482     page->chrome().setToolTip(hoveredNode);
1483 
1484     return result;
1485 }
1486 
handleMouseLeaveEvent(const PlatformMouseEvent & event)1487 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1488 {
1489     RefPtr<FrameView> protector(m_frame->view());
1490     handleMouseMoveOrLeaveEvent(event);
1491 }
1492 
syntheticTouchCursor()1493 static Cursor& syntheticTouchCursor()
1494 {
1495     DEFINE_STATIC_LOCAL(Cursor, c, (Image::loadPlatformResource("syntheticTouchCursor").get(), IntPoint(10, 10)));
1496     return c;
1497 }
1498 
handleMouseMoveOrLeaveEvent(const PlatformMouseEvent & mouseEvent,HitTestResult * hoveredNode,bool onlyUpdateScrollbars)1499 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1500 {
1501     ASSERT(m_frame);
1502     ASSERT(m_frame->view());
1503 
1504     bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1505     if (defaultPrevented) {
1506         m_frame->view()->setCursor(syntheticTouchCursor());
1507         return true;
1508     }
1509 
1510     setLastKnownMousePosition(mouseEvent);
1511 
1512     if (m_hoverTimer.isActive())
1513         m_hoverTimer.stop();
1514 
1515     m_cursorUpdateTimer.stop();
1516 
1517     cancelFakeMouseMoveEvent();
1518 
1519     if (m_svgPan) {
1520         toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1521         return true;
1522     }
1523 
1524     if (m_frameSetBeingResized)
1525         return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1526 
1527     // Send events right to a scrollbar if the mouse is pressed.
1528     if (m_lastScrollbarUnderMouse && m_mousePressed) {
1529         m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1530         return true;
1531     }
1532 
1533     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1534     if (mouseEvent.fromTouch())
1535         hitType |= HitTestRequest::ReadOnly;
1536 
1537     if (m_mousePressed)
1538         hitType |= HitTestRequest::Active;
1539     else if (onlyUpdateScrollbars) {
1540         // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1541         // means that :hover and :active freeze in the state they were in, rather than updating
1542         // for nodes the mouse moves while the window is not key (which will be the case if
1543         // onlyUpdateScrollbars is true).
1544         hitType |= HitTestRequest::ReadOnly;
1545     }
1546 
1547     // Treat any mouse move events as readonly if the user is currently touching the screen.
1548     if (m_touchPressed)
1549         hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1550     HitTestRequest request(hitType);
1551     MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1552     if (hoveredNode)
1553         *hoveredNode = mev.hitTestResult();
1554 
1555     Scrollbar* scrollbar = 0;
1556 
1557     if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1558         m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1559     else {
1560         if (FrameView* view = m_frame->view())
1561             scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1562 
1563         if (!scrollbar)
1564             scrollbar = mev.scrollbar();
1565 
1566         updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1567         if (onlyUpdateScrollbars)
1568             return true;
1569     }
1570 
1571     bool swallowEvent = false;
1572     RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1573 
1574     // 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.
1575     if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1576         passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1577 
1578     if (newSubframe) {
1579         // Update over/out state before passing the event to the subframe.
1580         updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1581 
1582         // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1583         // node to be detached from its FrameView, in which case the event should not be passed.
1584         if (newSubframe->view())
1585             swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1586     } else {
1587         if (scrollbar && !m_mousePressed)
1588             scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1589         if (FrameView* view = m_frame->view()) {
1590             OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey());
1591             if (optionalCursor.isCursorChange()) {
1592                 m_currentMouseCursor = optionalCursor.cursor();
1593                 view->setCursor(m_currentMouseCursor);
1594             }
1595         }
1596     }
1597 
1598     m_lastMouseMoveEventSubframe = newSubframe;
1599 
1600     if (swallowEvent)
1601         return true;
1602 
1603     swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.targetNode(), false, 0, mouseEvent, true);
1604     if (!swallowEvent)
1605         swallowEvent = handleMouseDraggedEvent(mev);
1606 
1607     return swallowEvent;
1608 }
1609 
invalidateClick()1610 void EventHandler::invalidateClick()
1611 {
1612     m_clickCount = 0;
1613     m_clickNode = 0;
1614 }
1615 
parentForClickEvent(const Node & node)1616 static Node* parentForClickEvent(const Node& node)
1617 {
1618     // IE doesn't dispatch click events for mousedown/mouseup events across form
1619     // controls.
1620     if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1621         return 0;
1622     return node.parentOrShadowHostNode();
1623 }
1624 
handleMouseReleaseEvent(const PlatformMouseEvent & mouseEvent)1625 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1626 {
1627     RefPtr<FrameView> protector(m_frame->view());
1628 
1629     m_frame->selection().setCaretBlinkingSuspended(false);
1630 
1631     bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(mouseEvent);
1632     if (defaultPrevented)
1633         return true;
1634 
1635     OwnPtr<UserGestureIndicator> gestureIndicator;
1636 
1637     if (m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken)
1638         gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->tree().top()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1639     else
1640         gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1641 
1642 #if OS(WIN)
1643     if (Page* page = m_frame->page())
1644         page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1645 #endif
1646 
1647     m_mousePressed = false;
1648     setLastKnownMousePosition(mouseEvent);
1649 
1650     if (m_svgPan) {
1651         m_svgPan = false;
1652         toSVGDocument(m_frame->document())->updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1653         return true;
1654     }
1655 
1656     if (m_frameSetBeingResized)
1657         return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1658 
1659     if (m_lastScrollbarUnderMouse) {
1660         invalidateClick();
1661         m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1662         bool cancelable = true;
1663         bool setUnder = false;
1664         return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), cancelable, m_clickCount, mouseEvent, setUnder);
1665     }
1666 
1667     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1668     if (mouseEvent.fromTouch())
1669         hitType |= HitTestRequest::ReadOnly;
1670     HitTestRequest request(hitType);
1671     MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1672     Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1673     if (m_eventHandlerWillResetCapturingMouseEventsNode)
1674         m_capturingMouseEventsNode = 0;
1675     if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1676         return true;
1677 
1678     bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.targetNode(), true, m_clickCount, mouseEvent, false);
1679 
1680     bool contextMenuEvent = mouseEvent.button() == RightButton;
1681 #if OS(MACOSX)
1682     // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1683     if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1684         contextMenuEvent = true;
1685 #endif
1686 
1687     bool swallowClickEvent = false;
1688     if (m_clickCount > 0 && !contextMenuEvent && mev.targetNode() && m_clickNode) {
1689         if (Node* clickTargetNode = mev.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1690             swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, true, m_clickCount, mouseEvent, true);
1691     }
1692 
1693     if (m_resizeScrollableArea) {
1694         m_resizeScrollableArea->setInResizeMode(false);
1695         m_resizeScrollableArea = 0;
1696     }
1697 
1698     bool swallowMouseReleaseEvent = false;
1699     if (!swallowMouseUpEvent)
1700         swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1701 
1702     invalidateClick();
1703 
1704     return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1705 }
1706 
handlePasteGlobalSelection(const PlatformMouseEvent & mouseEvent)1707 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1708 {
1709     // If the event was a middle click, attempt to copy global selection in after
1710     // the newly set caret position.
1711     //
1712     // This code is called from either the mouse up or mouse down handling. There
1713     // is some debate about when the global selection is pasted:
1714     //   xterm: pastes on up.
1715     //   GTK: pastes on down.
1716     //   Qt: pastes on up.
1717     //   Firefox: pastes on up.
1718     //   Chromium: pastes on up.
1719     //
1720     // There is something of a webcompat angle to this well, as highlighted by
1721     // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1722     // down then the text is pasted just before the onclick handler runs and
1723     // clears the text box. So it's important this happens after the event
1724     // handlers have been fired.
1725     if (mouseEvent.type() != PlatformEvent::MouseReleased)
1726         return false;
1727 
1728     if (!m_frame->page())
1729         return false;
1730     Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1731     // Do not paste here if the focus was moved somewhere else.
1732     if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1733         return m_frame->editor().command("PasteGlobalSelection").execute();
1734 
1735     return false;
1736 }
1737 
1738 
dispatchDragEvent(const AtomicString & eventType,Node * dragTarget,const PlatformMouseEvent & event,Clipboard * clipboard)1739 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1740 {
1741     FrameView* view = m_frame->view();
1742 
1743     // FIXME: We might want to dispatch a dragleave even if the view is gone.
1744     if (!view)
1745         return false;
1746 
1747     view->resetDeferredRepaintDelay();
1748     RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1749         true, true, m_frame->document()->domWindow(),
1750         0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1751         event.movementDelta().x(), event.movementDelta().y(),
1752         event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1753         0, 0, clipboard);
1754 
1755     dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1756     return me->defaultPrevented();
1757 }
1758 
targetIsFrame(Node * target,Frame * & frame)1759 static bool targetIsFrame(Node* target, Frame*& frame)
1760 {
1761     if (!target)
1762         return false;
1763 
1764     if (!target->hasTagName(frameTag) && !target->hasTagName(iframeTag))
1765         return false;
1766 
1767     frame = toHTMLFrameElementBase(target)->contentFrame();
1768     return true;
1769 }
1770 
findDropZone(Node * target,Clipboard * clipboard)1771 static bool findDropZone(Node* target, Clipboard* clipboard)
1772 {
1773     Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1774     for (; element; element = element->parentElement()) {
1775         bool matched = false;
1776         AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1777 
1778         if (dropZoneStr.isEmpty())
1779             continue;
1780 
1781         dropZoneStr = dropZoneStr.lower();
1782 
1783         SpaceSplitString keywords(dropZoneStr, false);
1784         if (keywords.isNull())
1785             continue;
1786 
1787         DragOperation dragOperation = DragOperationNone;
1788         for (unsigned int i = 0; i < keywords.size(); i++) {
1789             DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1790             if (op != DragOperationNone) {
1791                 if (dragOperation == DragOperationNone)
1792                     dragOperation = op;
1793             } else
1794                 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1795 
1796             if (matched && dragOperation != DragOperationNone)
1797                 break;
1798         }
1799         if (matched) {
1800             clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1801             return true;
1802         }
1803     }
1804     return false;
1805 }
1806 
updateDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1807 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1808 {
1809     bool accept = false;
1810 
1811     if (!m_frame->view())
1812         return false;
1813 
1814     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1815     MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1816 
1817     // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1818     RefPtr<Node> newTarget = mev.targetNode();
1819     if (newTarget && newTarget->isTextNode())
1820         newTarget = EventPath::parent(newTarget.get());
1821 
1822     if (AutoscrollController* controller = autoscrollController())
1823         controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1824 
1825     if (m_dragTarget != newTarget) {
1826         // FIXME: this ordering was explicitly chosen to match WinIE. However,
1827         // it is sometimes incorrect when dragging within subframes, as seen with
1828         // LayoutTests/fast/events/drag-in-frames.html.
1829         //
1830         // 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>.
1831         Frame* targetFrame;
1832         if (targetIsFrame(newTarget.get(), targetFrame)) {
1833             if (targetFrame)
1834                 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1835         } else if (newTarget) {
1836             // 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.
1837             if (dragState().m_dragSrc) {
1838                 // for now we don't care if event handler cancels default behavior, since there is none
1839                 dispatchDragSrcEvent(EventTypeNames::drag, event);
1840             }
1841             accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, clipboard);
1842             if (!accept)
1843                 accept = findDropZone(newTarget.get(), clipboard);
1844         }
1845 
1846         if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1847             if (targetFrame)
1848                 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1849         } else if (m_dragTarget)
1850             dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1851 
1852         if (newTarget) {
1853             // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1854             // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1855             m_shouldOnlyFireDragOverEvent = true;
1856         }
1857     } else {
1858         Frame* targetFrame;
1859         if (targetIsFrame(newTarget.get(), targetFrame)) {
1860             if (targetFrame)
1861                 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1862         } else if (newTarget) {
1863             // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1864             if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1865                 // for now we don't care if event handler cancels default behavior, since there is none
1866                 dispatchDragSrcEvent(EventTypeNames::drag, event);
1867             }
1868             accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, clipboard);
1869             if (!accept)
1870                 accept = findDropZone(newTarget.get(), clipboard);
1871             m_shouldOnlyFireDragOverEvent = false;
1872         }
1873     }
1874     m_dragTarget = newTarget;
1875 
1876     return accept;
1877 }
1878 
cancelDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1879 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1880 {
1881     Frame* targetFrame;
1882     if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1883         if (targetFrame)
1884             targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
1885     } else if (m_dragTarget.get()) {
1886         if (dragState().m_dragSrc)
1887             dispatchDragSrcEvent(EventTypeNames::drag, event);
1888         dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1889     }
1890     clearDragState();
1891 }
1892 
performDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1893 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1894 {
1895     Frame* targetFrame;
1896     bool preventedDefault = false;
1897     if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1898         if (targetFrame)
1899             preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
1900     } else if (m_dragTarget.get())
1901         preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, clipboard);
1902     clearDragState();
1903     return preventedDefault;
1904 }
1905 
clearDragState()1906 void EventHandler::clearDragState()
1907 {
1908     stopAutoscroll();
1909     m_dragTarget = 0;
1910     m_capturingMouseEventsNode = 0;
1911     m_shouldOnlyFireDragOverEvent = false;
1912 }
1913 
setCapturingMouseEventsNode(PassRefPtr<Node> n)1914 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1915 {
1916     m_capturingMouseEventsNode = n;
1917     m_eventHandlerWillResetCapturingMouseEventsNode = false;
1918 }
1919 
prepareMouseEvent(const HitTestRequest & request,const PlatformMouseEvent & mev)1920 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1921 {
1922     ASSERT(m_frame);
1923     ASSERT(m_frame->document());
1924 
1925     return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1926 }
1927 
instanceAssociatedWithShadowTreeElement(Node * referenceNode)1928 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1929 {
1930     if (!referenceNode || !referenceNode->isSVGElement())
1931         return 0;
1932 
1933     ShadowRoot* shadowRoot = referenceNode->containingShadowRoot();
1934     if (!shadowRoot)
1935         return 0;
1936 
1937     Element* shadowTreeParentElement = shadowRoot->host();
1938     if (!shadowTreeParentElement || !shadowTreeParentElement->hasTagName(useTag))
1939         return 0;
1940 
1941     return toSVGUseElement(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1942 }
1943 
updateMouseEventTargetNode(Node * targetNode,const PlatformMouseEvent & mouseEvent,bool fireMouseOverOut)1944 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1945 {
1946     Node* result = targetNode;
1947 
1948     // If we're capturing, we always go right to that node.
1949     if (m_capturingMouseEventsNode)
1950         result = m_capturingMouseEventsNode.get();
1951     else {
1952         // If the target node is a text node, dispatch on the parent node - rdar://4196646
1953         if (result && result->isTextNode())
1954             result = EventPath::parent(result);
1955     }
1956     m_nodeUnderMouse = result;
1957     m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1958 
1959     // <use> shadow tree elements may have been recloned, update node under mouse in any case
1960     if (m_lastInstanceUnderMouse) {
1961         SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1962         SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1963 
1964         if (lastCorrespondingElement && lastCorrespondingUseElement) {
1965             HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1966 
1967             // Locate the recloned shadow tree element for our corresponding instance
1968             HashSet<SVGElementInstance*>::iterator end = instances.end();
1969             for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1970                 SVGElementInstance* instance = (*it);
1971                 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1972 
1973                 if (instance == m_lastInstanceUnderMouse)
1974                     continue;
1975 
1976                 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1977                     continue;
1978 
1979                 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1980                 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1981                     continue;
1982 
1983                 m_lastNodeUnderMouse = shadowTreeElement;
1984                 m_lastInstanceUnderMouse = instance;
1985                 break;
1986             }
1987         }
1988     }
1989 
1990     // Fire mouseout/mouseover if the mouse has shifted to a different node.
1991     if (fireMouseOverOut) {
1992         RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1993         RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1994         Page* page = m_frame->page();
1995 
1996         if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1997             // The mouse has moved between frames.
1998             if (Frame* frame = m_lastNodeUnderMouse->document().frame()) {
1999                 if (FrameView* frameView = frame->view())
2000                     frameView->mouseExitedContentArea();
2001             }
2002         } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
2003             // The mouse has moved between layers.
2004             if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
2005                 scrollableAreaForLastNode->mouseExitedContentArea();
2006         }
2007 
2008         if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
2009             // The mouse has moved between frames.
2010             if (Frame* frame = m_nodeUnderMouse->document().frame()) {
2011                 if (FrameView* frameView = frame->view())
2012                     frameView->mouseEnteredContentArea();
2013             }
2014         } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
2015             // The mouse has moved between layers.
2016             if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
2017                 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
2018         }
2019 
2020         if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2021             m_lastNodeUnderMouse = 0;
2022             m_lastScrollbarUnderMouse = 0;
2023             m_lastInstanceUnderMouse = 0;
2024         }
2025 
2026         if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2027             // send mouseout event to the old node
2028             if (m_lastNodeUnderMouse)
2029                 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
2030             // send mouseover event to the new node
2031             if (m_nodeUnderMouse)
2032                 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
2033         }
2034         m_lastNodeUnderMouse = m_nodeUnderMouse;
2035         m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2036     }
2037 }
2038 
dispatchMouseEvent(const AtomicString & eventType,Node * targetNode,bool,int clickCount,const PlatformMouseEvent & mouseEvent,bool setUnder)2039 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2040 {
2041     if (FrameView* view = m_frame->view())
2042         view->resetDeferredRepaintDelay();
2043 
2044     updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2045 
2046     bool swallowEvent = false;
2047 
2048     if (m_nodeUnderMouse)
2049         swallowEvent = !(m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount));
2050 
2051     if (swallowEvent || eventType != EventTypeNames::mousedown)
2052         return !swallowEvent;
2053 
2054     // If clicking on a frame scrollbar, do not mess up with content focus.
2055     if (FrameView* view = m_frame->view()) {
2056         if (view->scrollbarAtPoint(mouseEvent.position()))
2057             return true;
2058     }
2059 
2060     // The layout needs to be up to date to determine if an element is focusable.
2061     m_frame->document()->updateLayoutIgnorePendingStylesheets();
2062 
2063     Element* element = 0;
2064     if (m_nodeUnderMouse)
2065         element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
2066     for (; element; element = element->parentOrShadowHostElement()) {
2067         if (element->isFocusable() && element->focused())
2068             return !swallowEvent;
2069         if (element->isMouseFocusable())
2070             break;
2071     }
2072     ASSERT(!element || element->isMouseFocusable());
2073 
2074     // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
2075     // a node on mouse down if it's selected and inside a focused node. It will
2076     // be focused if the user does a mouseup over it, however, because the
2077     // mouseup will set a selection inside it, which will call
2078     // FrameSelection::setFocusedNodeIfNeeded.
2079     if (element
2080         && m_frame->selection().isRange()
2081         && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
2082         && element->isDescendantOf(m_frame->document()->focusedElement()))
2083         return true;
2084 
2085     // Only change the focus when clicking scrollbars if it can transfered to a
2086     // mouse focusable node.
2087     if (!element && isInsideScrollbar(mouseEvent.position()))
2088         return false;
2089 
2090     if (Page* page = m_frame->page()) {
2091         // If focus shift is blocked, we eat the event. Note we should never
2092         // clear swallowEvent if the page already set it (e.g., by canceling
2093         // default behavior).
2094         if (element) {
2095             if (!page->focusController().setFocusedElement(element, m_frame, FocusDirectionMouse))
2096                 swallowEvent = true;
2097         } else {
2098             // We call setFocusedElement even with !element in order to blur
2099             // current focus element when a link is clicked; this is expected by
2100             // some sites that rely on onChange handlers running from form
2101             // fields before the button click is processed.
2102             if (!page->focusController().setFocusedElement(0, m_frame))
2103                 swallowEvent = true;
2104         }
2105     }
2106 
2107     return !swallowEvent;
2108 }
2109 
isInsideScrollbar(const IntPoint & windowPoint) const2110 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
2111 {
2112     if (RenderView* renderView = m_frame->contentRenderer()) {
2113         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2114         HitTestResult result(windowPoint);
2115         renderView->hitTest(request, result);
2116         return result.scrollbar();
2117     }
2118 
2119     return false;
2120 }
2121 
shouldTurnVerticalTicksIntoHorizontal(const HitTestResult & result,const PlatformWheelEvent & event) const2122 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result, const PlatformWheelEvent& event) const
2123 {
2124 #if OS(ANDROID) || OS(MACOSX) || OS(WIN)
2125     return false;
2126 #else
2127     // GTK+ must scroll horizontally if the mouse pointer is on top of the
2128     // horizontal scrollbar while scrolling with the wheel.
2129     // This code comes from gtk/EventHandlerGtk.cpp.
2130     return !event.hasPreciseScrollingDeltas() && result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar;
2131 #endif
2132 }
2133 
handleWheelEvent(const PlatformWheelEvent & e)2134 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
2135 {
2136 #define RETURN_WHEEL_EVENT_HANDLED() \
2137     { \
2138         setFrameWasScrolledByUser(); \
2139         return true; \
2140     }
2141 
2142     Document* doc = m_frame->document();
2143 
2144     if (!doc->renderer())
2145         return false;
2146 
2147     RefPtr<FrameView> protector(m_frame->view());
2148 
2149     FrameView* view = m_frame->view();
2150     if (!view)
2151         return false;
2152 
2153     if (handleWheelEventAsEmulatedGesture(e))
2154         return true;
2155 
2156     LayoutPoint vPoint = view->windowToContents(e.position());
2157 
2158     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2159     HitTestResult result(vPoint);
2160     doc->renderView()->hitTest(request, result);
2161 
2162     Node* node = result.innerNode();
2163     // Wheel events should not dispatch to text nodes.
2164     if (node && node->isTextNode())
2165         node = EventPath::parent(node);
2166 
2167     bool isOverWidget;
2168     if (e.useLatchedEventNode()) {
2169         if (!m_latchedWheelEventNode) {
2170             m_latchedWheelEventNode = node;
2171             m_widgetIsLatched = result.isOverWidget();
2172         } else
2173             node = m_latchedWheelEventNode.get();
2174 
2175         isOverWidget = m_widgetIsLatched;
2176     } else {
2177         if (m_latchedWheelEventNode)
2178             m_latchedWheelEventNode = 0;
2179         if (m_previousWheelScrolledNode)
2180             m_previousWheelScrolledNode = 0;
2181 
2182         isOverWidget = result.isOverWidget();
2183     }
2184 
2185     // FIXME: It should not be necessary to do this mutation here.
2186     // Instead, the handlers should know convert vertical scrolls
2187     // appropriately.
2188     PlatformWheelEvent event = e;
2189     if (m_baseEventType == PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result, e))
2190         event = event.copyTurningVerticalTicksIntoHorizontalTicks();
2191 
2192     if (node) {
2193         // Figure out which view to send the event to.
2194         RenderObject* target = node->renderer();
2195 
2196         if (isOverWidget && target && target->isWidget()) {
2197             Widget* widget = toRenderWidget(target)->widget();
2198             if (widget && passWheelEventToWidget(e, widget))
2199                 RETURN_WHEEL_EVENT_HANDLED();
2200         }
2201 
2202         if (node && !node->dispatchWheelEvent(event))
2203             RETURN_WHEEL_EVENT_HANDLED();
2204     }
2205 
2206 
2207     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2208     view = m_frame->view();
2209     if (!view || !view->wheelEvent(event))
2210         return false;
2211 
2212     RETURN_WHEEL_EVENT_HANDLED();
2213 
2214 #undef RETURN_WHEEL_EVENT_HANDLED
2215 }
2216 
defaultWheelEventHandler(Node * startNode,WheelEvent * wheelEvent)2217 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2218 {
2219     if (!startNode || !wheelEvent)
2220         return;
2221 
2222     Node* stopNode = m_previousWheelScrolledNode.get();
2223     ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2224 
2225     // Break up into two scrolls if we need to.  Diagonal movement on
2226     // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2227     if (scrollNode(wheelEvent->deltaX(), granularity, ScrollRight, startNode, &stopNode, roundedIntPoint(wheelEvent->absoluteLocation())))
2228         wheelEvent->setDefaultHandled();
2229 
2230     if (scrollNode(wheelEvent->deltaY(), granularity, ScrollDown, startNode, &stopNode, roundedIntPoint(wheelEvent->absoluteLocation())))
2231         wheelEvent->setDefaultHandled();
2232 
2233     if (!m_latchedWheelEventNode)
2234         m_previousWheelScrolledNode = stopNode;
2235 }
2236 
handleGestureShowPress()2237 bool EventHandler::handleGestureShowPress()
2238 {
2239     m_lastShowPressTimestamp = WTF::currentTime();
2240 
2241     FrameView* view = m_frame->view();
2242     if (!view)
2243         return false;
2244     if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2245         scrollAnimator->cancelAnimations();
2246     const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2247     if (!areas)
2248         return false;
2249     for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2250         ScrollableArea* sa = *it;
2251         ScrollAnimator* animator = sa->scrollAnimator();
2252         if (animator)
2253             animator->cancelAnimations();
2254     }
2255     return false;
2256 }
2257 
handleGestureEvent(const PlatformGestureEvent & gestureEvent)2258 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2259 {
2260     IntPoint adjustedPoint = gestureEvent.position();
2261     RefPtr<Frame> subframe = 0;
2262     switch (gestureEvent.type()) {
2263     case PlatformEvent::GestureScrollBegin:
2264     case PlatformEvent::GestureScrollUpdate:
2265     case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2266     case PlatformEvent::GestureScrollEnd:
2267     case PlatformEvent::GestureFlingStart:
2268         // Handle directly in main frame
2269         break;
2270 
2271     case PlatformEvent::GestureTap:
2272     case PlatformEvent::GestureTapUnconfirmed:
2273     case PlatformEvent::GestureTapDown:
2274     case PlatformEvent::GestureShowPress:
2275     case PlatformEvent::GestureTapDownCancel:
2276     case PlatformEvent::GestureTwoFingerTap:
2277     case PlatformEvent::GestureLongPress:
2278     case PlatformEvent::GestureLongTap:
2279     case PlatformEvent::GesturePinchBegin:
2280     case PlatformEvent::GesturePinchEnd:
2281     case PlatformEvent::GesturePinchUpdate:
2282         adjustGesturePosition(gestureEvent, adjustedPoint);
2283         subframe = getSubFrameForGestureEvent(adjustedPoint, gestureEvent);
2284         if (subframe)
2285             return subframe->eventHandler().handleGestureEvent(gestureEvent);
2286         break;
2287 
2288     default:
2289         ASSERT_NOT_REACHED();
2290     }
2291 
2292     Node* eventTarget = 0;
2293     Scrollbar* scrollbar = 0;
2294     if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2295         || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2296         || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation
2297         || gestureEvent.type() == PlatformEvent::GestureFlingStart) {
2298         scrollbar = m_scrollbarHandlingScrollGesture.get();
2299         eventTarget = m_scrollGestureHandlingNode.get();
2300     }
2301 
2302     HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2303     double activeInterval = 0;
2304     bool shouldKeepActiveForMinInterval = false;
2305     if (gestureEvent.type() == PlatformEvent::GestureShowPress
2306         || gestureEvent.type() == PlatformEvent::GestureTapUnconfirmed) {
2307         hitType |= HitTestRequest::Active;
2308     } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) {
2309         hitType |= HitTestRequest::Release;
2310         // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2311         if (!m_frame->document()->activeElement())
2312             hitType |= HitTestRequest::ReadOnly;
2313     } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2314         hitType |= HitTestRequest::Release;
2315         // If the Tap is received very shortly after ShowPress, we want to delay clearing
2316         // of the active state so that it's visible to the user for at least one frame.
2317         activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2318         shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2319         if (shouldKeepActiveForMinInterval)
2320             hitType |= HitTestRequest::ReadOnly;
2321     }
2322     else
2323         hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2324 
2325     if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2326         IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2327         HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2328 
2329         if (shouldKeepActiveForMinInterval) {
2330             m_lastDeferredTapElement = result.innerElement();
2331             m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval);
2332         }
2333 
2334         eventTarget = result.targetNode();
2335         if (!scrollbar) {
2336             FrameView* view = m_frame->view();
2337             scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2338         }
2339         if (!scrollbar)
2340             scrollbar = result.scrollbar();
2341     }
2342 
2343     if (scrollbar) {
2344         bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2345         if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed) {
2346             m_scrollbarHandlingScrollGesture = scrollbar;
2347         } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2348             || gestureEvent.type() == PlatformEvent::GestureFlingStart
2349             || !eventSwallowed) {
2350             m_scrollbarHandlingScrollGesture = 0;
2351         }
2352 
2353         if (eventSwallowed)
2354             return true;
2355     }
2356 
2357     if (eventTarget) {
2358         bool eventSwallowed = false;
2359         if (handleScrollGestureOnResizer(eventTarget, gestureEvent))
2360             eventSwallowed = true;
2361         else
2362             eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2363         if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2364             if (eventSwallowed)
2365                 m_scrollGestureHandlingNode = eventTarget;
2366         }
2367 
2368         if (eventSwallowed)
2369             return true;
2370     }
2371 
2372     // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2373     // eliminate the need for this.
2374     TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2375 
2376     switch (gestureEvent.type()) {
2377     case PlatformEvent::GestureScrollBegin:
2378         return handleGestureScrollBegin(gestureEvent);
2379     case PlatformEvent::GestureScrollUpdate:
2380     case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2381         return handleGestureScrollUpdate(gestureEvent);
2382     case PlatformEvent::GestureScrollEnd:
2383         return handleGestureScrollEnd(gestureEvent);
2384     case PlatformEvent::GestureTap:
2385         return handleGestureTap(gestureEvent, adjustedPoint);
2386     case PlatformEvent::GestureShowPress:
2387         return handleGestureShowPress();
2388     case PlatformEvent::GestureLongPress:
2389         return handleGestureLongPress(gestureEvent, adjustedPoint);
2390     case PlatformEvent::GestureLongTap:
2391         return handleGestureLongTap(gestureEvent, adjustedPoint);
2392     case PlatformEvent::GestureTwoFingerTap:
2393         return handleGestureTwoFingerTap(gestureEvent, adjustedPoint);
2394     case PlatformEvent::GestureTapDown:
2395     case PlatformEvent::GesturePinchBegin:
2396     case PlatformEvent::GesturePinchEnd:
2397     case PlatformEvent::GesturePinchUpdate:
2398     case PlatformEvent::GestureTapDownCancel:
2399     case PlatformEvent::GestureTapUnconfirmed:
2400     case PlatformEvent::GestureFlingStart:
2401         break;
2402     default:
2403         ASSERT_NOT_REACHED();
2404     }
2405 
2406     return false;
2407 }
2408 
handleGestureTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2409 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2410 {
2411     // FIXME: Refactor this code to not hit test multiple times. We use the adjusted position to ensure that the correct node is targeted by the later redundant hit tests.
2412 
2413     unsigned modifierFlags = 0;
2414     if (gestureEvent.altKey())
2415         modifierFlags |= PlatformEvent::AltKey;
2416     if (gestureEvent.ctrlKey())
2417         modifierFlags |= PlatformEvent::CtrlKey;
2418     if (gestureEvent.metaKey())
2419         modifierFlags |= PlatformEvent::MetaKey;
2420     if (gestureEvent.shiftKey())
2421         modifierFlags |= PlatformEvent::ShiftKey;
2422     PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2423 
2424     PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2425         NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2426         modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2427     handleMouseMoveEvent(fakeMouseMove);
2428 
2429     bool defaultPrevented = false;
2430     PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2431         LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2432         modifiers, PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
2433     defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2434 
2435     PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2436         LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2437         modifiers, PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
2438     defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2439 
2440     return defaultPrevented;
2441 }
2442 
handleGestureLongPress(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2443 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2444 {
2445     m_longTapShouldInvokeContextMenu = false;
2446     if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2447         PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2448             gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2449         m_mouseDown = mouseDownEvent;
2450 
2451         PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2452             gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2453         HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2454         MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2455         m_didStartDrag = false;
2456         m_mouseDownMayStartDrag = true;
2457         dragState().m_dragSrc = 0;
2458         m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2459         RefPtr<FrameView> protector(m_frame->view());
2460         handleDrag(mev, DontCheckDragHysteresis);
2461         if (m_didStartDrag) {
2462             m_longTapShouldInvokeContextMenu = true;
2463             return true;
2464         }
2465     }
2466 #if OS(ANDROID)
2467     bool shouldLongPressSelectWord = true;
2468 #else
2469     bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2470 #endif
2471     if (shouldLongPressSelectWord) {
2472         IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2473         HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2474         Node* innerNode = result.targetNode();
2475         if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2476             selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2477             if (m_frame->selection().isRange()) {
2478                 focusDocumentView();
2479                 return true;
2480             }
2481         }
2482     }
2483     return sendContextMenuEventForGesture(gestureEvent);
2484 }
2485 
handleGestureLongTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2486 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2487 {
2488 #if !OS(ANDROID)
2489     if (m_longTapShouldInvokeContextMenu) {
2490         m_longTapShouldInvokeContextMenu = false;
2491         return sendContextMenuEventForGesture(gestureEvent);
2492     }
2493 #endif
2494     return false;
2495 }
2496 
handleScrollGestureOnResizer(Node * eventTarget,const PlatformGestureEvent & gestureEvent)2497 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2498     if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2499         RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : 0;
2500         IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2501         if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2502             m_resizeScrollableArea = layer->scrollableArea();
2503             m_resizeScrollableArea->setInResizeMode(true);
2504             m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2505             return true;
2506         }
2507     } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2508                gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2509         if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2510             m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2511             return true;
2512         }
2513     } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2514         if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2515             m_resizeScrollableArea->setInResizeMode(false);
2516             m_resizeScrollableArea = 0;
2517             return false;
2518         }
2519     }
2520 
2521     return false;
2522 }
2523 
handleGestureTwoFingerTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2524 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2525 {
2526     return sendContextMenuEventForGesture(gestureEvent);
2527 }
2528 
passGestureEventToWidget(const PlatformGestureEvent & gestureEvent,Widget * widget)2529 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2530 {
2531     if (!widget)
2532         return false;
2533 
2534     if (!widget->isFrameView())
2535         return false;
2536 
2537     return toFrameView(widget)->frame().eventHandler().handleGestureEvent(gestureEvent);
2538 }
2539 
passGestureEventToWidgetIfPossible(const PlatformGestureEvent & gestureEvent,RenderObject * renderer)2540 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2541 {
2542     if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2543         Widget* widget = toRenderWidget(renderer)->widget();
2544         return widget && passGestureEventToWidget(gestureEvent, widget);
2545     }
2546     return false;
2547 }
2548 
handleGestureScrollEnd(const PlatformGestureEvent & gestureEvent)2549 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2550     RefPtr<Node> node = m_scrollGestureHandlingNode;
2551     clearGestureScrollNodes();
2552 
2553     if (node) {
2554         ASSERT(node->refCount() > 0);
2555         passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2556     }
2557 
2558     return false;
2559 }
2560 
handleGestureScrollBegin(const PlatformGestureEvent & gestureEvent)2561 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2562 {
2563     Document* document = m_frame->document();
2564     if (!document->renderView())
2565         return false;
2566 
2567     FrameView* view = m_frame->view();
2568     if (!view)
2569         return false;
2570 
2571     LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2572     HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2573     HitTestResult result(viewPoint);
2574     document->renderView()->hitTest(request, result);
2575 
2576     m_lastHitTestResultOverWidget = result.isOverWidget();
2577     m_scrollGestureHandlingNode = result.innerNode();
2578     m_previousGestureScrolledNode = 0;
2579 
2580     // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2581     // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2582     while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2583         m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2584 
2585     if (!m_scrollGestureHandlingNode)
2586         return false;
2587 
2588     passGestureEventToWidgetIfPossible(gestureEvent, m_scrollGestureHandlingNode->renderer());
2589 
2590     return true;
2591 }
2592 
handleGestureScrollUpdate(const PlatformGestureEvent & gestureEvent)2593 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2594 {
2595     FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2596     if (delta.isZero())
2597         return false;
2598 
2599     const float scaleFactor = m_frame->pageZoomFactor();
2600     delta.scale(1 / scaleFactor, 1 / scaleFactor);
2601 
2602     Node* node = m_scrollGestureHandlingNode.get();
2603     if (!node)
2604         return sendScrollEventToView(gestureEvent, delta);
2605 
2606     // Ignore this event if the targeted node does not have a valid renderer.
2607     RenderObject* renderer = node->renderer();
2608     if (!renderer)
2609         return false;
2610 
2611     RefPtr<FrameView> protector(m_frame->view());
2612 
2613     Node* stopNode = 0;
2614     bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2615 
2616     // Try to send the event to the correct view.
2617     if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) {
2618         if(scrollShouldNotPropagate)
2619               m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2620 
2621         return true;
2622     }
2623 
2624     if (scrollShouldNotPropagate)
2625         stopNode = m_previousGestureScrolledNode.get();
2626 
2627     // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2628     ScrollGranularity granularity = ScrollByPixel;
2629     bool horizontalScroll = scrollNode(delta.width(), granularity, ScrollLeft, node, &stopNode);
2630     bool verticalScroll = scrollNode(delta.height(), granularity, ScrollUp, node, &stopNode);
2631 
2632     if (scrollShouldNotPropagate)
2633         m_previousGestureScrolledNode = stopNode;
2634 
2635     if (horizontalScroll || verticalScroll) {
2636         setFrameWasScrolledByUser();
2637         return true;
2638     }
2639 
2640     // Otherwise try to scroll the view.
2641     return sendScrollEventToView(gestureEvent, delta);
2642 }
2643 
sendScrollEventToView(const PlatformGestureEvent & gestureEvent,const FloatSize & scaledDelta)2644 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2645 {
2646     FrameView* view = m_frame->view();
2647     if (!view)
2648         return false;
2649 
2650     const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2651     IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2652     IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2653     PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2654         scaledDelta.width(), scaledDelta.height(),
2655         scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2656         ScrollByPixelWheelEvent,
2657         gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2658     syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2659 
2660     bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2661     if (scrolledFrame)
2662         setFrameWasScrolledByUser();
2663 
2664     return scrolledFrame;
2665 }
2666 
getSubFrameForGestureEvent(const IntPoint & touchAdjustedPoint,const PlatformGestureEvent & gestureEvent)2667 Frame* EventHandler::getSubFrameForGestureEvent(const IntPoint& touchAdjustedPoint, const PlatformGestureEvent& gestureEvent)
2668 {
2669     PlatformMouseEvent mouseDown(touchAdjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2670         gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2671     HitTestRequest request(HitTestRequest::ReadOnly);
2672     MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDown);
2673     return subframeForHitTestResult(mev);
2674 }
2675 
clearGestureScrollNodes()2676 void EventHandler::clearGestureScrollNodes()
2677 {
2678     m_scrollGestureHandlingNode = 0;
2679     m_previousGestureScrolledNode = 0;
2680 }
2681 
isScrollbarHandlingGestures() const2682 bool EventHandler::isScrollbarHandlingGestures() const
2683 {
2684     return m_scrollbarHandlingScrollGesture.get();
2685 }
2686 
shouldApplyTouchAdjustment(const PlatformGestureEvent & event) const2687 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2688 {
2689     if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2690         return false;
2691     return !event.area().isEmpty();
2692 }
2693 
2694 
bestClickableNodeForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntPoint & targetPoint,Node * & targetNode)2695 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2696 {
2697     IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2698     HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2699 
2700     // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2701     // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2702     // scrollbars being untouchable.
2703     if (result.scrollbar())
2704         return false;
2705 
2706     IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2707     Vector<RefPtr<Node>, 11> nodes;
2708     copyToVector(result.rectBasedTestResult(), nodes);
2709 
2710     // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2711     // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2712     // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2713     // handle targetNode being a shadow DOM node.
2714 
2715     // FIXME: the explicit Vector conversion copies into a temporary and is
2716     // wasteful.
2717     bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> > (nodes));
2718     if (success && targetNode)
2719         targetNode = targetNode->deprecatedShadowAncestorNode();
2720     return success;
2721 }
2722 
bestContextMenuNodeForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntPoint & targetPoint,Node * & targetNode)2723 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2724 {
2725     IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2726     HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2727 
2728     IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2729     Vector<RefPtr<Node>, 11> nodes;
2730     copyToVector(result.rectBasedTestResult(), nodes);
2731 
2732     // FIXME: the explicit Vector conversion copies into a temporary and is
2733     // wasteful.
2734     return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2735 }
2736 
bestZoomableAreaForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntRect & targetArea,Node * & targetNode)2737 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2738 {
2739     IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2740     HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, touchRadius);
2741 
2742     IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2743     Vector<RefPtr<Node>, 11> nodes;
2744     copyToVector(result.rectBasedTestResult(), nodes);
2745 
2746     // FIXME: the explicit Vector conversion copies into a temporary and is
2747     // wasteful.
2748     return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, Vector<RefPtr<Node> >(nodes));
2749 }
2750 
adjustGesturePosition(const PlatformGestureEvent & gestureEvent,IntPoint & adjustedPoint)2751 bool EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2752 {
2753     if (!shouldApplyTouchAdjustment(gestureEvent))
2754         return false;
2755 
2756     Node* targetNode = 0;
2757     switch (gestureEvent.type()) {
2758     case PlatformEvent::GestureTap:
2759     case PlatformEvent::GestureTapUnconfirmed:
2760     case PlatformEvent::GestureTapDown:
2761     case PlatformEvent::GestureShowPress:
2762         bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2763         break;
2764     case PlatformEvent::GestureLongPress:
2765     case PlatformEvent::GestureLongTap:
2766     case PlatformEvent::GestureTwoFingerTap:
2767         bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2768         break;
2769     default:
2770         // FIXME: Implement handling for other types as needed.
2771         ASSERT_NOT_REACHED();
2772     }
2773     return targetNode;
2774 }
2775 
sendContextMenuEvent(const PlatformMouseEvent & event)2776 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2777 {
2778     Document* doc = m_frame->document();
2779     FrameView* v = m_frame->view();
2780     if (!v)
2781         return false;
2782 
2783     // Clear mouse press state to avoid initiating a drag while context menu is up.
2784     m_mousePressed = false;
2785     bool swallowEvent;
2786     LayoutPoint viewportPos = v->windowToContents(event.position());
2787     HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2788     MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2789 
2790     if (!m_frame->selection().contains(viewportPos)
2791         && !mev.scrollbar()
2792         // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2793         // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2794         // available for text selections.  But only if we're above text.
2795         && (m_frame->selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2796         m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2797 
2798         if (mev.hitTestResult().isMisspelled())
2799             selectClosestMisspellingFromMouseEvent(mev);
2800         else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2801             selectClosestWordOrLinkFromMouseEvent(mev);
2802     }
2803 
2804     swallowEvent = !dispatchMouseEvent(EventTypeNames::contextmenu, mev.targetNode(), true, 0, event, false);
2805 
2806     return swallowEvent;
2807 }
2808 
sendContextMenuEventForKey()2809 bool EventHandler::sendContextMenuEventForKey()
2810 {
2811     FrameView* view = m_frame->view();
2812     if (!view)
2813         return false;
2814 
2815     Document* doc = m_frame->document();
2816     if (!doc)
2817         return false;
2818 
2819     // Clear mouse press state to avoid initiating a drag while context menu is up.
2820     m_mousePressed = false;
2821 
2822     static const int kContextMenuMargin = 1;
2823 
2824 #if OS(WIN)
2825     int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2826 #else
2827     int rightAligned = 0;
2828 #endif
2829     IntPoint location;
2830 
2831     Element* focusedElement = doc->focusedElement();
2832     FrameSelection& selection = m_frame->selection();
2833     Position start = selection.selection().start();
2834 
2835     if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2836         RefPtr<Range> selectionRange = selection.toNormalizedRange();
2837         IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2838 
2839         int x = rightAligned ? firstRect.maxX() : firstRect.x();
2840         // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2841         int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2842         location = IntPoint(x, y);
2843     } else if (focusedElement) {
2844         RenderBoxModelObject* box = focusedElement->renderBoxModelObject();
2845         if (!box)
2846             return false;
2847         IntRect clippedRect = box->pixelSnappedAbsoluteClippedOverflowRect();
2848         location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2849     } else {
2850         location = IntPoint(
2851             rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2852             kContextMenuMargin);
2853     }
2854 
2855     m_frame->view()->setCursor(pointerCursor());
2856 
2857     IntPoint position = view->contentsToRootView(location);
2858     IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2859 
2860     Node* targetNode = doc->focusedElement();
2861     if (!targetNode)
2862         targetNode = doc;
2863 
2864     // Use the focused node as the target for hover and active.
2865     HitTestResult result(position);
2866     result.setInnerNode(targetNode);
2867     doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, result.innerElement());
2868 
2869     // The contextmenu event is a mouse event even when invoked using the keyboard.
2870     // This is required for web compatibility.
2871 
2872 #if OS(WIN)
2873     PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2874 #else
2875     PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2876 #endif
2877 
2878     PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2879 
2880     return !dispatchMouseEvent(EventTypeNames::contextmenu, targetNode, true, 0, mouseEvent, false);
2881 }
2882 
sendContextMenuEventForGesture(const PlatformGestureEvent & event)2883 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2884 {
2885 #if OS(WIN)
2886     PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2887 #else
2888     PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2889 #endif
2890 
2891     IntPoint adjustedPoint = event.position();
2892     adjustGesturePosition(event, adjustedPoint);
2893     PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2894     // To simulate right-click behavior, we send a right mouse down and then
2895     // context menu event.
2896     handleMousePressEvent(mouseEvent);
2897     return sendContextMenuEvent(mouseEvent);
2898     // We do not need to send a corresponding mouse release because in case of
2899     // right-click, the context menu takes capture and consumes all events.
2900 }
2901 
scheduleHoverStateUpdate()2902 void EventHandler::scheduleHoverStateUpdate()
2903 {
2904     if (!m_hoverTimer.isActive())
2905         m_hoverTimer.startOneShot(0);
2906 }
2907 
scheduleCursorUpdate()2908 void EventHandler::scheduleCursorUpdate()
2909 {
2910     if (!m_cursorUpdateTimer.isActive())
2911         m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
2912 }
2913 
dispatchFakeMouseMoveEventSoon()2914 void EventHandler::dispatchFakeMouseMoveEventSoon()
2915 {
2916     if (m_mousePressed)
2917         return;
2918 
2919     if (m_mousePositionIsUnknown)
2920         return;
2921 
2922     Settings* settings = m_frame->settings();
2923     if (settings && !settings->deviceSupportsMouse())
2924         return;
2925 
2926     // If the content has ever taken longer than fakeMouseMoveShortInterval we
2927     // reschedule the timer and use a longer time. This will cause the content
2928     // to receive these moves only after the user is done scrolling, reducing
2929     // pauses during the scroll.
2930     if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2931         if (m_fakeMouseMoveEventTimer.isActive())
2932             m_fakeMouseMoveEventTimer.stop();
2933         m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval);
2934     } else {
2935         if (!m_fakeMouseMoveEventTimer.isActive())
2936             m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval);
2937     }
2938 }
2939 
dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad & quad)2940 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2941 {
2942     FrameView* view = m_frame->view();
2943     if (!view)
2944         return;
2945 
2946     if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2947         return;
2948 
2949     dispatchFakeMouseMoveEventSoon();
2950 }
2951 
fakeMouseMoveEventTimerFired(Timer<EventHandler> * timer)2952 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2953 {
2954     ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2955     ASSERT(!m_mousePressed);
2956 
2957     Settings* settings = m_frame->settings();
2958     if (settings && !settings->deviceSupportsMouse())
2959         return;
2960 
2961     FrameView* view = m_frame->view();
2962     if (!view)
2963         return;
2964 
2965     if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2966         return;
2967 
2968     // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2969     if (!isCursorVisible())
2970         return;
2971 
2972     bool shiftKey;
2973     bool ctrlKey;
2974     bool altKey;
2975     bool metaKey;
2976     PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2977     PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2978     handleMouseMoveEvent(fakeMouseMoveEvent);
2979 }
2980 
cancelFakeMouseMoveEvent()2981 void EventHandler::cancelFakeMouseMoveEvent()
2982 {
2983     m_fakeMouseMoveEventTimer.stop();
2984 }
2985 
isCursorVisible() const2986 bool EventHandler::isCursorVisible() const
2987 {
2988     return m_frame->page()->isCursorVisible();
2989 }
2990 
setResizingFrameSet(HTMLFrameSetElement * frameSet)2991 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2992 {
2993     m_frameSetBeingResized = frameSet;
2994 }
2995 
resizeScrollableAreaDestroyed()2996 void EventHandler::resizeScrollableAreaDestroyed()
2997 {
2998     ASSERT(m_resizeScrollableArea);
2999     m_resizeScrollableArea = 0;
3000 }
3001 
hoverTimerFired(Timer<EventHandler> *)3002 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
3003 {
3004     m_hoverTimer.stop();
3005 
3006     ASSERT(m_frame);
3007     ASSERT(m_frame->document());
3008 
3009     if (RenderView* renderer = m_frame->contentRenderer()) {
3010         if (FrameView* view = m_frame->view()) {
3011             HitTestRequest request(HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3012             HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
3013             renderer->hitTest(request, result);
3014             m_frame->document()->updateHoverActiveState(request, result.innerElement());
3015         }
3016     }
3017 }
3018 
activeIntervalTimerFired(Timer<EventHandler> *)3019 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
3020 {
3021     m_activeIntervalTimer.stop();
3022 
3023     if (m_frame
3024         && m_frame->document()
3025         && m_lastDeferredTapElement) {
3026         // FIXME: Enable condition when http://crbug.com/226842 lands
3027         // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
3028         HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
3029         m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
3030     }
3031     m_lastDeferredTapElement = 0;
3032 }
3033 
notifyElementActivated()3034 void EventHandler::notifyElementActivated()
3035 {
3036     // Since another element has been set to active, stop current timer and clear reference.
3037     if (m_activeIntervalTimer.isActive())
3038         m_activeIntervalTimer.stop();
3039     m_lastDeferredTapElement = 0;
3040 }
3041 
handleAccessKey(const PlatformKeyboardEvent & evt)3042 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
3043 {
3044     // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3045     // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3046     // lower case variants are present in a document, the correct element is matched based on Shift key state.
3047     // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3048     ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
3049     if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
3050         return false;
3051     String key = evt.unmodifiedText();
3052     Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
3053     if (!elem)
3054         return false;
3055     elem->accessKeyAction(false);
3056     return true;
3057 }
3058 
isKeyEventAllowedInFullScreen(FullscreenElementStack * fullscreen,const PlatformKeyboardEvent & keyEvent) const3059 bool EventHandler::isKeyEventAllowedInFullScreen(FullscreenElementStack* fullscreen, const PlatformKeyboardEvent& keyEvent) const
3060 {
3061     if (fullscreen->webkitFullScreenKeyboardInputAllowed())
3062         return true;
3063 
3064     if (keyEvent.type() == PlatformKeyboardEvent::Char) {
3065         if (keyEvent.text().length() != 1)
3066             return false;
3067         UChar character = keyEvent.text()[0];
3068         return character == ' ';
3069     }
3070 
3071     int keyCode = keyEvent.windowsVirtualKeyCode();
3072     return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
3073         || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
3074         || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
3075         || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
3076 }
3077 
keyEvent(const PlatformKeyboardEvent & initialKeyEvent)3078 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3079 {
3080     RefPtr<FrameView> protector(m_frame->view());
3081 
3082     if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(m_frame->document())) {
3083         if (fullscreen->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent))
3084             return false;
3085     }
3086 
3087     if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3088         capsLockStateMayHaveChanged();
3089 
3090 #if OS(WIN)
3091     if (panScrollInProgress()) {
3092         // If a key is pressed while the panScroll is in progress then we want to stop
3093         if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
3094             stopAutoscroll();
3095 
3096         // If we were in panscroll mode, we swallow the key event
3097         return true;
3098     }
3099 #endif
3100 
3101     // Check for cases where we are too early for events -- possible unmatched key up
3102     // from pressing return in the location bar.
3103     RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
3104     if (!node)
3105         return false;
3106 
3107     UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3108 
3109     if (FrameView* view = m_frame->view())
3110         view->resetDeferredRepaintDelay();
3111 
3112     // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
3113     // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
3114     // with access keys. Then we dispatch keydown, but suppress its default handling.
3115     // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
3116     // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3117     bool matchedAnAccessKey = false;
3118     if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3119         matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3120 
3121     // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3122     if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3123         return !node->dispatchKeyEvent(initialKeyEvent);
3124 
3125     PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3126     if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3127         keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
3128     RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
3129     if (matchedAnAccessKey)
3130         keydown->setDefaultPrevented(true);
3131     keydown->setTarget(node);
3132 
3133     if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3134         node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3135         // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3136         bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3137         return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3138     }
3139 
3140     node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3141     // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
3142     bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
3143     bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
3144     if (keydownResult)
3145         return keydownResult;
3146 
3147     // Focus may have changed during keydown handling, so refetch node.
3148     // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3149     node = eventTargetNodeForDocument(m_frame->document());
3150     if (!node)
3151         return false;
3152 
3153     PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3154     keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
3155     if (keyPressEvent.text().isEmpty())
3156         return keydownResult;
3157     RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
3158     keypress->setTarget(node);
3159     if (keydownResult)
3160         keypress->setDefaultPrevented(true);
3161     node->dispatchEvent(keypress, IGNORE_EXCEPTION);
3162 
3163     return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
3164 }
3165 
focusDirectionForKey(const AtomicString & keyIdentifier)3166 static FocusDirection focusDirectionForKey(const AtomicString& keyIdentifier)
3167 {
3168     DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
3169     DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
3170     DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
3171     DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
3172 
3173     FocusDirection retVal = FocusDirectionNone;
3174 
3175     if (keyIdentifier == Down)
3176         retVal = FocusDirectionDown;
3177     else if (keyIdentifier == Up)
3178         retVal = FocusDirectionUp;
3179     else if (keyIdentifier == Left)
3180         retVal = FocusDirectionLeft;
3181     else if (keyIdentifier == Right)
3182         retVal = FocusDirectionRight;
3183 
3184     return retVal;
3185 }
3186 
defaultKeyboardEventHandler(KeyboardEvent * event)3187 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3188 {
3189     if (event->type() == EventTypeNames::keydown) {
3190         m_frame->editor().handleKeyboardEvent(event);
3191         if (event->defaultHandled())
3192             return;
3193         if (event->keyIdentifier() == "U+0009")
3194             defaultTabEventHandler(event);
3195         else if (event->keyIdentifier() == "U+0008")
3196             defaultBackspaceEventHandler(event);
3197         else if (event->keyIdentifier() == "U+001B")
3198             defaultEscapeEventHandler(event);
3199         else {
3200             FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
3201             if (direction != FocusDirectionNone)
3202                 defaultArrowEventHandler(direction, event);
3203         }
3204     }
3205     if (event->type() == EventTypeNames::keypress) {
3206         m_frame->editor().handleKeyboardEvent(event);
3207         if (event->defaultHandled())
3208             return;
3209         if (event->charCode() == ' ')
3210             defaultSpaceEventHandler(event);
3211     }
3212 }
3213 
dragHysteresisExceeded(const IntPoint & floatDragViewportLocation) const3214 bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocation) const
3215 {
3216     FloatPoint dragViewportLocation(floatDragViewportLocation.x(), floatDragViewportLocation.y());
3217     return dragHysteresisExceeded(dragViewportLocation);
3218 }
3219 
dragHysteresisExceeded(const FloatPoint & dragViewportLocation) const3220 bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
3221 {
3222     FrameView* view = m_frame->view();
3223     if (!view)
3224         return false;
3225     IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3226     IntSize delta = dragLocation - m_mouseDownPos;
3227 
3228     int threshold = GeneralDragHysteresis;
3229     switch (dragState().m_dragType) {
3230     case DragSourceActionSelection:
3231         threshold = TextDragHysteresis;
3232         break;
3233     case DragSourceActionImage:
3234         threshold = ImageDragHysteresis;
3235         break;
3236     case DragSourceActionLink:
3237         threshold = LinkDragHysteresis;
3238         break;
3239     case DragSourceActionDHTML:
3240         break;
3241     case DragSourceActionNone:
3242         ASSERT_NOT_REACHED();
3243     }
3244 
3245     return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3246 }
3247 
freeClipboard()3248 void EventHandler::freeClipboard()
3249 {
3250     if (dragState().m_dragClipboard)
3251         dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3252 }
3253 
dragSourceEndedAt(const PlatformMouseEvent & event,DragOperation operation)3254 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3255 {
3256     // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3257     HitTestRequest request(HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3258     prepareMouseEvent(request, event);
3259 
3260     if (dragState().m_dragSrc) {
3261         dragState().m_dragClipboard->setDestinationOperation(operation);
3262         // for now we don't care if event handler cancels default behavior, since there is none
3263         dispatchDragSrcEvent(EventTypeNames::dragend, event);
3264     }
3265     freeClipboard();
3266     dragState().m_dragSrc = 0;
3267     // In case the drag was ended due to an escape key press we need to ensure
3268     // that consecutive mousemove events don't reinitiate the drag and drop.
3269     m_mouseDownMayStartDrag = false;
3270 }
3271 
updateDragStateAfterEditDragIfNeeded(Element * rootEditableElement)3272 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3273 {
3274     // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3275     if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3276         dragState().m_dragSrc = rootEditableElement;
3277 }
3278 
3279 // returns if we should continue "default processing", i.e., whether eventhandler canceled
dispatchDragSrcEvent(const AtomicString & eventType,const PlatformMouseEvent & event)3280 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3281 {
3282     return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3283 }
3284 
handleDrag(const MouseEventWithHitTestResults & event,CheckDragHysteresis checkDragHysteresis)3285 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3286 {
3287     ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3288     // Callers must protect the reference to FrameView, since this function may dispatch DOM
3289     // events, causing page/FrameView to go away.
3290     ASSERT(m_frame);
3291     ASSERT(m_frame->view());
3292     if (!m_frame->page())
3293         return false;
3294 
3295     if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3296         // If we allowed the other side of the bridge to handle a drag
3297         // last time, then m_mousePressed might still be set. So we
3298         // clear it now to make sure the next move after a drag
3299         // doesn't look like a drag.
3300         m_mousePressed = false;
3301         return false;
3302     }
3303 
3304     if (m_mouseDownMayStartDrag) {
3305         HitTestRequest request(HitTestRequest::ReadOnly);
3306         HitTestResult result(m_mouseDownPos);
3307         m_frame->contentRenderer()->hitTest(request, result);
3308         Node* node = result.innerNode();
3309         if (node) {
3310             DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3311                 ? DragController::DelayedSelectionDragResolution
3312                 : DragController::ImmediateSelectionDragResolution;
3313             dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3314         } else {
3315             dragState().m_dragSrc = 0;
3316         }
3317 
3318         if (!dragState().m_dragSrc)
3319             m_mouseDownMayStartDrag = false; // no element is draggable
3320     }
3321 
3322     if (!m_mouseDownMayStartDrag)
3323         return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3324 
3325     // We are starting a text/image/url drag, so the cursor should be an arrow
3326     // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3327     m_frame->view()->setCursor(pointerCursor());
3328 
3329     if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3330         return true;
3331 
3332     // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3333     invalidateClick();
3334 
3335     if (!tryStartDrag(event)) {
3336         // Something failed to start the drag, clean up.
3337         freeClipboard();
3338         dragState().m_dragSrc = 0;
3339     }
3340 
3341     m_mouseDownMayStartDrag = false;
3342     // Whether or not the drag actually started, no more default handling (like selection).
3343     return true;
3344 }
3345 
tryStartDrag(const MouseEventWithHitTestResults & event)3346 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3347 {
3348     freeClipboard(); // would only happen if we missed a dragEnd.  Do it anyway, just
3349                      // to make sure it gets numbified
3350     dragState().m_dragClipboard = createDraggingClipboard();
3351 
3352     // Check to see if this a DOM based drag, if it is get the DOM specified drag
3353     // image and offset
3354     if (dragState().m_dragType == DragSourceActionDHTML) {
3355         if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3356             // FIXME: This doesn't work correctly with transforms.
3357             FloatPoint absPos = renderer->localToAbsolute();
3358             IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3359             dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3360         } else {
3361             // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3362             // the element in some way. In this case we just kill the drag.
3363             return false;
3364         }
3365     }
3366 
3367     DragController& dragController = m_frame->page()->dragController();
3368     if (!dragController.populateDragClipboard(m_frame, dragState(), m_mouseDownPos))
3369         return false;
3370     m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3371         && !m_frame->selection().isInPasswordField();
3372 
3373     // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3374     // image can still be changed as we drag, but not the pasteboard data.
3375     dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3376 
3377     if (m_mouseDownMayStartDrag) {
3378         // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3379         m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3380         // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3381         // whether or not the drag started, but perhaps it can simply use the return value from
3382         // handleDrag(), even though it doesn't mean exactly the same thing.
3383         if (m_didStartDrag)
3384             return true;
3385         // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3386         dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3387     }
3388 
3389     return false;
3390 }
3391 
handleTextInputEvent(const String & text,Event * underlyingEvent,TextEventInputType inputType)3392 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3393 {
3394     // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3395     // and avoid dispatching text input events from keydown default handlers.
3396     ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3397 
3398     if (!m_frame)
3399         return false;
3400 
3401     EventTarget* target;
3402     if (underlyingEvent)
3403         target = underlyingEvent->target();
3404     else
3405         target = eventTargetNodeForDocument(m_frame->document());
3406     if (!target)
3407         return false;
3408 
3409     if (FrameView* view = m_frame->view())
3410         view->resetDeferredRepaintDelay();
3411 
3412     RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3413     event->setUnderlyingEvent(underlyingEvent);
3414 
3415     target->dispatchEvent(event, IGNORE_EXCEPTION);
3416     return event->defaultHandled();
3417 }
3418 
defaultTextInputEventHandler(TextEvent * event)3419 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3420 {
3421     if (m_frame->editor().handleTextEvent(event))
3422         event->setDefaultHandled();
3423 }
3424 
defaultSpaceEventHandler(KeyboardEvent * event)3425 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3426 {
3427     ASSERT(event->type() == EventTypeNames::keypress);
3428 
3429     if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3430         return;
3431 
3432     ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3433     if (scrollOverflow(direction, ScrollByPage)) {
3434         event->setDefaultHandled();
3435         return;
3436     }
3437 
3438     FrameView* view = m_frame->view();
3439     if (!view)
3440         return;
3441 
3442     if (view->scroll(direction, ScrollByPage))
3443         event->setDefaultHandled();
3444 }
3445 
defaultBackspaceEventHandler(KeyboardEvent * event)3446 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3447 {
3448     ASSERT(event->type() == EventTypeNames::keydown);
3449 
3450     if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3451         return;
3452 
3453     if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3454         return;
3455 
3456     Page* page = m_frame->page();
3457     if (!page)
3458         return;
3459     bool handledEvent = page->mainFrame()->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3460     if (handledEvent)
3461         event->setDefaultHandled();
3462 }
3463 
defaultArrowEventHandler(FocusDirection focusDirection,KeyboardEvent * event)3464 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
3465 {
3466     ASSERT(event->type() == EventTypeNames::keydown);
3467 
3468     if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3469         return;
3470 
3471     Page* page = m_frame->page();
3472     if (!page)
3473         return;
3474 
3475     if (!isSpatialNavigationEnabled(m_frame))
3476         return;
3477 
3478     // Arrows and other possible directional navigation keys can be used in design
3479     // mode editing.
3480     if (m_frame->document()->inDesignMode())
3481         return;
3482 
3483     if (page->focusController().advanceFocus(focusDirection))
3484         event->setDefaultHandled();
3485 }
3486 
defaultTabEventHandler(KeyboardEvent * event)3487 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3488 {
3489     ASSERT(event->type() == EventTypeNames::keydown);
3490 
3491     // We should only advance focus on tabs if no special modifier keys are held down.
3492     if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3493         return;
3494 
3495     Page* page = m_frame->page();
3496     if (!page)
3497         return;
3498     if (!page->tabKeyCyclesThroughElements())
3499         return;
3500 
3501     FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3502 
3503     // Tabs can be used in design mode editing.
3504     if (m_frame->document()->inDesignMode())
3505         return;
3506 
3507     if (page->focusController().advanceFocus(focusDirection))
3508         event->setDefaultHandled();
3509 }
3510 
defaultEscapeEventHandler(KeyboardEvent * event)3511 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3512 {
3513     if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3514         dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3515 }
3516 
capsLockStateMayHaveChanged()3517 void EventHandler::capsLockStateMayHaveChanged()
3518 {
3519     if (Element* element = m_frame->document()->focusedElement()) {
3520         if (RenderObject* r = element->renderer()) {
3521             if (r->isTextField())
3522                 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3523         }
3524     }
3525 }
3526 
setFrameWasScrolledByUser()3527 void EventHandler::setFrameWasScrolledByUser()
3528 {
3529     if (FrameView* view = m_frame->view())
3530         view->setWasScrolledByUser(true);
3531 }
3532 
passMousePressEventToScrollbar(MouseEventWithHitTestResults & mev,Scrollbar * scrollbar)3533 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3534 {
3535     if (!scrollbar || !scrollbar->enabled())
3536         return false;
3537     setFrameWasScrolledByUser();
3538     scrollbar->mouseDown(mev.event());
3539     return true;
3540 }
3541 
3542 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3543 // last to scrollbar if setLast is true; else set last to 0.
updateLastScrollbarUnderMouse(Scrollbar * scrollbar,bool setLast)3544 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3545 {
3546     if (m_lastScrollbarUnderMouse != scrollbar) {
3547         // Send mouse exited to the old scrollbar.
3548         if (m_lastScrollbarUnderMouse)
3549             m_lastScrollbarUnderMouse->mouseExited();
3550 
3551         // Send mouse entered if we're setting a new scrollbar.
3552         if (scrollbar && setLast)
3553             scrollbar->mouseEntered();
3554 
3555         m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3556     }
3557 }
3558 
eventNameForTouchPointState(PlatformTouchPoint::State state)3559 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3560 {
3561     switch (state) {
3562     case PlatformTouchPoint::TouchReleased:
3563         return EventTypeNames::touchend;
3564     case PlatformTouchPoint::TouchCancelled:
3565         return EventTypeNames::touchcancel;
3566     case PlatformTouchPoint::TouchPressed:
3567         return EventTypeNames::touchstart;
3568     case PlatformTouchPoint::TouchMoved:
3569         return EventTypeNames::touchmove;
3570     case PlatformTouchPoint::TouchStationary:
3571         // TouchStationary state is not converted to touch events, so fall through to assert.
3572     default:
3573         ASSERT_NOT_REACHED();
3574         return emptyAtom;
3575     }
3576 }
3577 
hitTestResultInFrame(Frame * frame,const LayoutPoint & point,HitTestRequest::HitTestRequestType hitType)3578 HitTestResult EventHandler::hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3579 {
3580     HitTestResult result(point);
3581 
3582     if (!frame || !frame->contentRenderer())
3583         return result;
3584     if (frame->view()) {
3585         IntRect rect = frame->view()->visibleContentRect();
3586         if (!rect.contains(roundedIntPoint(point)))
3587             return result;
3588     }
3589     frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3590     return result;
3591 }
3592 
handleTouchEvent(const PlatformTouchEvent & event)3593 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3594 {
3595     // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3596     // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3597     // for an overview of how these lists fit together.
3598 
3599     // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3600     RefPtr<TouchList> touches = TouchList::create();
3601 
3602     // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3603     // 'targetTouches' list in the JS event.
3604     typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3605     TargetTouchesMap touchesByTarget;
3606 
3607     // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3608     typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3609     struct {
3610         // The touches corresponding to the particular change state this struct instance represents.
3611         RefPtr<TouchList> m_touches;
3612         // Set of targets involved in m_touches.
3613         EventTargetSet m_targets;
3614     } changedTouches[PlatformTouchPoint::TouchStateEnd];
3615 
3616     const Vector<PlatformTouchPoint>& points = event.touchPoints();
3617 
3618     UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3619 
3620     unsigned i;
3621     bool freshTouchEvents = true;
3622     bool allTouchReleased = true;
3623     for (i = 0; i < points.size(); ++i) {
3624         const PlatformTouchPoint& point = points[i];
3625         if (point.state() != PlatformTouchPoint::TouchPressed)
3626             freshTouchEvents = false;
3627         if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3628             allTouchReleased = false;
3629     }
3630 
3631     for (i = 0; i < points.size(); ++i) {
3632         const PlatformTouchPoint& point = points[i];
3633         PlatformTouchPoint::State pointState = point.state();
3634         LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3635 
3636         // Gesture events trigger the active state, not touch events,
3637         // so touch event hit tests can always be read only.
3638         HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly;
3639         // The HitTestRequest types used for mouse events map quite adequately
3640         // to touch events. Note that in addition to meaning that the hit test
3641         // should affect the active state of the current node if necessary,
3642         // HitTestRequest::Active signifies that the hit test is taking place
3643         // with the mouse (or finger in this case) being pressed.
3644         switch (pointState) {
3645         case PlatformTouchPoint::TouchPressed:
3646             hitType |= HitTestRequest::Active;
3647             break;
3648         case PlatformTouchPoint::TouchMoved:
3649             hitType |= HitTestRequest::Active | HitTestRequest::Move;
3650             break;
3651         case PlatformTouchPoint::TouchReleased:
3652         case PlatformTouchPoint::TouchCancelled:
3653             hitType |= HitTestRequest::Release;
3654             break;
3655         case PlatformTouchPoint::TouchStationary:
3656             hitType |= HitTestRequest::Active;
3657             break;
3658         default:
3659             ASSERT_NOT_REACHED();
3660             break;
3661         }
3662 
3663         // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3664         unsigned touchPointTargetKey = point.id() + 1;
3665         RefPtr<EventTarget> touchTarget;
3666         if (pointState == PlatformTouchPoint::TouchPressed) {
3667             HitTestResult result;
3668             if (freshTouchEvents) {
3669                 result = hitTestResultAtPoint(pagePoint, hitType);
3670                 m_originatingTouchPointTargetKey = touchPointTargetKey;
3671             } else if (m_originatingTouchPointDocument.get() && m_originatingTouchPointDocument->frame()) {
3672                 LayoutPoint pagePointInOriginatingDocument = documentPointForWindowPoint(m_originatingTouchPointDocument->frame(), point.pos());
3673                 result = hitTestResultInFrame(m_originatingTouchPointDocument->frame(), pagePointInOriginatingDocument, hitType);
3674             } else
3675                 continue;
3676 
3677             Node* node = result.innerNode();
3678             if (!node)
3679                 continue;
3680 
3681             // Touch events should not go to text nodes
3682             if (node->isTextNode())
3683                 node = EventPath::parent(node);
3684 
3685             Document& doc = node->document();
3686             // Record the originating touch document even if it does not have a touch listener.
3687             if (freshTouchEvents) {
3688                 m_originatingTouchPointDocument = &doc;
3689                 freshTouchEvents = false;
3690             }
3691             if (!doc.hasTouchEventHandlers())
3692                 continue;
3693             m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3694             touchTarget = node;
3695 
3696             // FIXME(rbyers): Should really be doing a second hit test that ignores inline elements - crbug.com/319479.
3697             TouchAction effectiveTouchAction = computeEffectiveTouchAction(*node);
3698             if (effectiveTouchAction != TouchActionAuto)
3699                 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3700 
3701         } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3702             // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3703             // we also remove it from the map.
3704             touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3705         } else
3706             // No hittest is performed on move or stationary, since the target is not allowed to change anyway.
3707             touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3708 
3709         if (!touchTarget.get())
3710             continue;
3711         Document& doc = touchTarget->toNode()->document();
3712         if (!doc.hasTouchEventHandlers())
3713             continue;
3714         Frame* targetFrame = doc.frame();
3715         if (!targetFrame)
3716             continue;
3717 
3718         if (m_frame != targetFrame) {
3719             // pagePoint should always be relative to the target elements containing frame.
3720             pagePoint = documentPointForWindowPoint(targetFrame, point.pos());
3721         }
3722 
3723         float scaleFactor = targetFrame->pageZoomFactor();
3724 
3725         int adjustedPageX = lroundf(pagePoint.x() / scaleFactor);
3726         int adjustedPageY = lroundf(pagePoint.y() / scaleFactor);
3727         int adjustedRadiusX = lroundf(point.radiusX() / scaleFactor);
3728         int adjustedRadiusY = lroundf(point.radiusY() / scaleFactor);
3729 
3730         RefPtr<Touch> touch = Touch::create(targetFrame, touchTarget.get(), point.id(),
3731                                             point.screenPos().x(), point.screenPos().y(),
3732                                             adjustedPageX, adjustedPageY,
3733                                             adjustedRadiusX, adjustedRadiusY,
3734                                             point.rotationAngle(), point.force());
3735 
3736         // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3737         TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3738         if (targetTouchesIterator == touchesByTarget.end())
3739             targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).iterator;
3740 
3741         // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3742         // released or cancelled it will only appear in the changedTouches list.
3743         if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3744             touches->append(touch);
3745             targetTouchesIterator->value->append(touch);
3746         }
3747 
3748         // Now build up the correct list for changedTouches.
3749         // Note that  any touches that are in the TouchStationary state (e.g. if
3750         // the user had several points touched but did not move them all) should
3751         // never be in the changedTouches list so we do not handle them explicitly here.
3752         // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3753         // about the TouchStationary state.
3754         if (pointState != PlatformTouchPoint::TouchStationary) {
3755             ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3756             if (!changedTouches[pointState].m_touches)
3757                 changedTouches[pointState].m_touches = TouchList::create();
3758             changedTouches[pointState].m_touches->append(touch);
3759             changedTouches[pointState].m_targets.add(touchTarget);
3760         }
3761     }
3762     m_touchPressed = touches->length() > 0;
3763     if (allTouchReleased)
3764         m_originatingTouchPointDocument.clear();
3765 
3766     // Now iterate the changedTouches list and m_targets within it, sending events to the targets as required.
3767     bool swallowedEvent = false;
3768     RefPtr<TouchList> emptyList = TouchList::create();
3769     for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3770         if (!changedTouches[state].m_touches)
3771             continue;
3772 
3773         // When sending a touch cancel event, use empty touches and targetTouches lists.
3774         bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3775         RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3776         const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3777         const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3778 
3779         for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3780             EventTarget* touchEventTarget = it->get();
3781             RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3782             ASSERT(targetTouches);
3783 
3784             RefPtr<TouchEvent> touchEvent =
3785                 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3786                     stateName, touchEventTarget->toNode()->document().domWindow(),
3787                     0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3788             touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3789             swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3790         }
3791     }
3792 
3793     return swallowedEvent;
3794 }
3795 
dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent & event)3796 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
3797 {
3798     if (!m_frame || !m_frame->settings() || !m_frame->settings()->touchEventEmulationEnabled())
3799         return false;
3800 
3801     PlatformEvent::Type eventType = event.type();
3802     if (eventType != PlatformEvent::MouseMoved && eventType != PlatformEvent::MousePressed && eventType != PlatformEvent::MouseReleased)
3803         return false;
3804 
3805     HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3806     MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
3807     if (mev.scrollbar() || subframeForHitTestResult(mev))
3808         return false;
3809 
3810     // The order is important. This check should follow the subframe test: http://webkit.org/b/111292.
3811     if (eventType == PlatformEvent::MouseMoved && event.button() == NoButton)
3812         return true;
3813 
3814     SyntheticSingleTouchEvent touchEvent(event);
3815     if (handleTouchEvent(touchEvent))
3816         return true;
3817 
3818     return handleMouseEventAsEmulatedGesture(event);
3819 }
3820 
handleMouseEventAsEmulatedGesture(const PlatformMouseEvent & event)3821 bool EventHandler::handleMouseEventAsEmulatedGesture(const PlatformMouseEvent& event)
3822 {
3823     PlatformEvent::Type eventType = event.type();
3824     if (event.button() != LeftButton || !m_frame->isMainFrame())
3825         return false;
3826 
3827     // Simulate pinch / scroll gesture.
3828     const IntPoint& position = event.position();
3829     bool swallowEvent = false;
3830 
3831     FrameView* view = m_frame->view();
3832     if (event.shiftKey()) {
3833         // Shift pressed - consider it gesture.
3834         swallowEvent = true;
3835         Page* page = m_frame->page();
3836         float pageScaleFactor = page->pageScaleFactor();
3837         switch (eventType) {
3838         case PlatformEvent::MousePressed:
3839             m_lastSyntheticPinchAnchorCss = adoptPtr(new IntPoint(view->scrollPosition() + position));
3840             m_lastSyntheticPinchAnchorDip = adoptPtr(new IntPoint(position));
3841             m_lastSyntheticPinchAnchorDip->scale(pageScaleFactor, pageScaleFactor);
3842             m_syntheticPageScaleFactor = pageScaleFactor;
3843             break;
3844         case PlatformEvent::MouseMoved:
3845             {
3846                 if (!m_lastSyntheticPinchAnchorCss)
3847                     break;
3848 
3849                 float dy = m_lastSyntheticPinchAnchorDip->y() - position.y() * pageScaleFactor;
3850                 float magnifyDelta = exp(dy * 0.002f);
3851                 float newPageScaleFactor = m_syntheticPageScaleFactor * magnifyDelta;
3852 
3853                 IntPoint anchorCss(*m_lastSyntheticPinchAnchorDip.get());
3854                 anchorCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor);
3855                 page->inspectorController().requestPageScaleFactor(newPageScaleFactor, *m_lastSyntheticPinchAnchorCss.get() - toIntSize(anchorCss));
3856                 break;
3857             }
3858         case PlatformEvent::MouseReleased:
3859             m_lastSyntheticPinchAnchorCss.clear();
3860             m_lastSyntheticPinchAnchorDip.clear();
3861         default:
3862             break;
3863         }
3864     } else {
3865         switch (eventType) {
3866         case PlatformEvent::MouseMoved:
3867             {
3868                 // Always consume move events.
3869                 swallowEvent = true;
3870                 int dx = m_lastSyntheticPanLocation ? position.x() - m_lastSyntheticPanLocation->x() : 0;
3871                 int dy = m_lastSyntheticPanLocation ? position.y() - m_lastSyntheticPanLocation->y() : 0;
3872                 if (dx || dy)
3873                     view->scrollBy(IntSize(-dx, -dy));
3874                 // Mouse dragged - consider it gesture.
3875                 m_lastSyntheticPanLocation = adoptPtr(new IntPoint(position));
3876                 break;
3877             }
3878         case PlatformEvent::MouseReleased:
3879             // There was a drag -> gesture.
3880             swallowEvent = !!m_lastSyntheticPanLocation;
3881             m_lastSyntheticPanLocation.clear();
3882         default:
3883             break;
3884         }
3885     }
3886 
3887     return swallowEvent;
3888 }
3889 
handleWheelEventAsEmulatedGesture(const PlatformWheelEvent & event)3890 bool EventHandler::handleWheelEventAsEmulatedGesture(const PlatformWheelEvent& event)
3891 {
3892     if (!m_frame || !m_frame->settings() || !m_frame->settings()->touchEventEmulationEnabled())
3893         return false;
3894 
3895     // Only convert vertical wheel w/ shift into pinch for touch-enabled device convenience.
3896     if (!event.shiftKey() || !event.deltaY())
3897         return false;
3898 
3899     Page* page = m_frame->page();
3900     FrameView* view = m_frame->view();
3901     float pageScaleFactor = page->pageScaleFactor();
3902     IntPoint anchorBeforeCss(view->scrollPosition() + event.position());
3903     IntPoint anchorBeforeDip(event.position());
3904     anchorBeforeDip.scale(pageScaleFactor, pageScaleFactor);
3905 
3906     float magnifyDelta = exp(event.deltaY() * 0.002f);
3907     float newPageScaleFactor = pageScaleFactor * magnifyDelta;
3908 
3909     IntPoint anchorAfterCss(anchorBeforeDip);
3910     anchorAfterCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor);
3911     page->inspectorController().requestPageScaleFactor(newPageScaleFactor, anchorBeforeCss - toIntSize(anchorAfterCss));
3912     return true;
3913 }
3914 
computeEffectiveTouchAction(const Node & node)3915 TouchAction EventHandler::computeEffectiveTouchAction(const Node& node)
3916 {
3917     // Optimization to minimize risk of this new feature (behavior should be identical
3918     // since there's no way to get non-default touch-action values).
3919     if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
3920         return TouchActionAuto;
3921 
3922     // Start by permitting all actions, then walk the block level elements from
3923     // the target node up to the nearest scrollable ancestor and exclude any
3924     // prohibited actions. For now this is trivial, but when we add more types
3925     // of actions it'll get a little more complex.
3926     for (const Node* curNode = &node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3927         // The spec says only block and SVG elements get touch-action.
3928         // FIXME(rbyers): Add correct support for SVG, crbug.com/247396.
3929         if (RenderObject* renderer = curNode->renderer()) {
3930             if (renderer->isRenderBlockFlow()) {
3931                 if (renderer->style()->touchAction() == TouchActionNone)
3932                     return TouchActionNone;
3933             }
3934 
3935             // If we've reached an ancestor that supports a touch action, search no further.
3936             if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3937                 break;
3938         }
3939     }
3940     return TouchActionAuto;
3941 }
3942 
setLastKnownMousePosition(const PlatformMouseEvent & event)3943 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3944 {
3945     m_mousePositionIsUnknown = false;
3946     m_lastKnownMousePosition = event.position();
3947     m_lastKnownMouseGlobalPosition = event.globalPosition();
3948 }
3949 
passMousePressEventToSubframe(MouseEventWithHitTestResults & mev,Frame * subframe)3950 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
3951 {
3952     // If we're clicking into a frame that is selected, the frame will appear
3953     // greyed out even though we're clicking on the selection.  This looks
3954     // really strange (having the whole frame be greyed out), so we deselect the
3955     // selection.
3956     IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3957     if (m_frame->selection().contains(p)) {
3958         VisiblePosition visiblePos(
3959             mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
3960         VisibleSelection newSelection(visiblePos);
3961         m_frame->selection().setSelection(newSelection);
3962     }
3963 
3964     subframe->eventHandler().handleMousePressEvent(mev.event());
3965     return true;
3966 }
3967 
passMouseMoveEventToSubframe(MouseEventWithHitTestResults & mev,Frame * subframe,HitTestResult * hoveredNode)3968 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
3969 {
3970     if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
3971         return false;
3972     subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3973     return true;
3974 }
3975 
passMouseReleaseEventToSubframe(MouseEventWithHitTestResults & mev,Frame * subframe)3976 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
3977 {
3978     subframe->eventHandler().handleMouseReleaseEvent(mev.event());
3979     return true;
3980 }
3981 
passWheelEventToWidget(const PlatformWheelEvent & wheelEvent,Widget * widget)3982 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
3983 {
3984     // We can sometimes get a null widget!  EventHandlerMac handles a null
3985     // widget by returning false, so we do the same.
3986     if (!widget)
3987         return false;
3988 
3989     // If not a FrameView, then probably a plugin widget.  Those will receive
3990     // the event via an EventTargetNode dispatch when this returns false.
3991     if (!widget->isFrameView())
3992         return false;
3993 
3994     return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
3995 }
3996 
passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults & event)3997 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
3998 {
3999     // Figure out which view to send the event to.
4000     if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
4001         return false;
4002     return false;
4003 }
4004 
createDraggingClipboard() const4005 PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
4006 {
4007     return Clipboard::create(Clipboard::DragAndDrop, ClipboardWritable, ChromiumDataObject::create());
4008 }
4009 
focusDocumentView()4010 void EventHandler::focusDocumentView()
4011 {
4012     Page* page = m_frame->page();
4013     if (!page)
4014         return;
4015     page->focusController().setFocusedFrame(m_frame);
4016 }
4017 
accessKeyModifiers()4018 unsigned EventHandler::accessKeyModifiers()
4019 {
4020 #if OS(MACOSX)
4021     return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
4022 #else
4023     return PlatformEvent::AltKey;
4024 #endif
4025 }
4026 
4027 } // namespace WebCore
4028