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