Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: Source/core/editing/SelectionController.cpp

Issue 1113323002: [Reland] Refactor the selection code in EventHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/editing/SelectionController.h ('k') | Source/core/html/HTMLLabelElement.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed. 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies) 4 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5 * Copyright (C) 2015 Google Inc. All rights reserved.
5 * 6 *
6 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
8 * are met: 9 * are met:
9 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
14 * 15 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * (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 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 27 */
27 28
28 #include "config.h" 29 #include "config.h"
29 #include "core/input/EventHandler.h" 30 #include "core/editing/SelectionController.h"
30 31
31 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
32 #include "core/HTMLNames.h" 32 #include "core/HTMLNames.h"
33 #include "core/InputTypeNames.h"
34 #include "core/clipboard/DataObject.h"
35 #include "core/clipboard/DataTransfer.h"
36 #include "core/dom/Document.h" 33 #include "core/dom/Document.h"
37 #include "core/dom/DocumentMarkerController.h" 34 #include "core/dom/DocumentMarkerController.h"
38 #include "core/dom/TouchList.h"
39 #include "core/dom/shadow/ComposedTreeTraversal.h"
40 #include "core/dom/shadow/ShadowRoot.h"
41 #include "core/editing/Editor.h" 35 #include "core/editing/Editor.h"
42 #include "core/editing/FrameSelection.h" 36 #include "core/editing/FrameSelection.h"
43 #include "core/editing/htmlediting.h" 37 #include "core/editing/htmlediting.h"
44 #include "core/editing/iterators/TextIterator.h" 38 #include "core/editing/iterators/TextIterator.h"
45 #include "core/events/EventPath.h" 39 #include "core/events/Event.h"
46 #include "core/events/KeyboardEvent.h"
47 #include "core/events/MouseEvent.h"
48 #include "core/events/TextEvent.h"
49 #include "core/events/TouchEvent.h"
50 #include "core/events/WheelEvent.h"
51 #include "core/fetch/ImageResource.h"
52 #include "core/frame/EventHandlerRegistry.h"
53 #include "core/frame/FrameHost.h"
54 #include "core/frame/FrameView.h" 40 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h" 41 #include "core/frame/LocalFrame.h"
56 #include "core/frame/PinchViewport.h"
57 #include "core/frame/Settings.h" 42 #include "core/frame/Settings.h"
58 #include "core/html/HTMLDialogElement.h"
59 #include "core/html/HTMLFrameElementBase.h"
60 #include "core/html/HTMLFrameSetElement.h"
61 #include "core/html/HTMLInputElement.h"
62 #include "core/layout/HitTestRequest.h"
63 #include "core/layout/HitTestResult.h"
64 #include "core/layout/LayoutPart.h"
65 #include "core/layout/LayoutTextControlSingleLine.h"
66 #include "core/layout/LayoutView.h" 43 #include "core/layout/LayoutView.h"
67 #include "core/loader/FrameLoader.h"
68 #include "core/loader/FrameLoaderClient.h"
69 #include "core/page/AutoscrollController.h"
70 #include "core/page/ChromeClient.h"
71 #include "core/page/DragController.h"
72 #include "core/page/DragState.h"
73 #include "core/page/FocusController.h" 44 #include "core/page/FocusController.h"
74 #include "core/page/FrameTree.h"
75 #include "core/page/Page.h" 45 #include "core/page/Page.h"
76 #include "core/page/SpatialNavigation.h"
77 #include "core/page/TouchAdjustment.h"
78 #include "core/page/scrolling/ScrollState.h"
79 #include "core/paint/DeprecatedPaintLayer.h"
80 #include "core/style/ComputedStyle.h"
81 #include "core/svg/SVGDocumentExtensions.h"
82 #include "platform/PlatformGestureEvent.h"
83 #include "platform/PlatformKeyboardEvent.h"
84 #include "platform/PlatformTouchEvent.h"
85 #include "platform/PlatformWheelEvent.h"
86 #include "platform/RuntimeEnabledFeatures.h" 46 #include "platform/RuntimeEnabledFeatures.h"
87 #include "platform/TraceEvent.h"
88 #include "platform/WindowsKeyboardCodes.h"
89 #include "platform/geometry/FloatPoint.h"
90 #include "platform/graphics/Image.h"
91 #include "platform/heap/Handle.h"
92 #include "platform/scroll/ScrollAnimator.h"
93 #include "platform/scroll/Scrollbar.h"
94 #include "wtf/Assertions.h"
95 #include "wtf/CurrentTime.h"
96 #include "wtf/StdLibExtras.h"
97 #include "wtf/TemporaryChange.h"
98 47
99 namespace blink { 48 namespace blink {
100 49 PassOwnPtrWillBeRawPtr<SelectionController> SelectionController::create(LocalFra me& frame)
101 using namespace HTMLNames;
102
103 // The link drag hysteresis is much larger than the others because there
104 // needs to be enough space to cancel the link press without starting a link dra g,
105 // and because dragging links is rare.
106 static const int LinkDragHysteresis = 40;
107 static const int ImageDragHysteresis = 5;
108 static const int TextDragHysteresis = 3;
109 static const int GeneralDragHysteresis = 3;
110
111 // The amount of time to wait before sending a fake mouse event, triggered
112 // during a scroll. The short interval is used if the content responds to the mo use events quickly enough,
113 // otherwise the long interval is used.
114 static const double fakeMouseMoveShortInterval = 0.1;
115 static const double fakeMouseMoveLongInterval = 0.250;
116
117 // The amount of time to wait for a cursor update on style and layout changes
118 // Set to 50Hz, no need to be faster than common screen refresh rate
119 static const double cursorUpdateInterval = 0.02;
120
121 static const int maximumCursorSize = 128;
122
123 // It's pretty unlikely that a scale of less than one would ever be used. But al l we really
124 // need to ensure here is that the scale isn't so small that integer overflow ca n occur when
125 // dividing cursor sizes (limited above) by the scale.
126 static const double minimumCursorScale = 0.001;
127
128 // The minimum amount of time an element stays active after a ShowPress
129 // This is roughly 9 frames, which should be long enough to be noticeable.
130 static const double minimumActiveInterval = 0.15;
131
132 #if OS(MACOSX)
133 static const double TextDragDelay = 0.15;
134 #else
135 static const double TextDragDelay = 0.0;
136 #endif
137
138 enum NoCursorChangeType { NoCursorChange };
139
140 enum class DragInitiator { Mouse, Touch };
141
142 class OptionalCursor {
143 public:
144 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
145 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(curs or) { }
146
147 bool isCursorChange() const { return m_isCursorChange; }
148 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
149
150 private:
151 bool m_isCursorChange;
152 Cursor m_cursor;
153 };
154
155 class MaximumDurationTracker {
156 public:
157 explicit MaximumDurationTracker(double *maxDuration)
158 : m_maxDuration(maxDuration)
159 , m_start(monotonicallyIncreasingTime())
160 {
161 }
162
163 ~MaximumDurationTracker()
164 {
165 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_s tart);
166 }
167
168 private:
169 double* m_maxDuration;
170 double m_start;
171 };
172
173 static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent* event)
174 { 50 {
175 unsigned deltaMode = event->deltaMode(); 51 return adoptPtrWillBeNoop(new SelectionController(frame));
176 if (deltaMode == WheelEvent::DOM_DELTA_PAGE)
177 return ScrollByPage;
178 if (deltaMode == WheelEvent::DOM_DELTA_LINE)
179 return ScrollByLine;
180 ASSERT(deltaMode == WheelEvent::DOM_DELTA_PIXEL);
181 return event->hasPreciseScrollingDeltas() ? ScrollByPrecisePixel : ScrollByP ixel;
182 } 52 }
183 53
184 // Refetch the event target node if it is removed or currently is the shadow nod e inside an <input> element. 54 SelectionController::SelectionController(LocalFrame& frame)
185 // If a mouse event handler changes the input element type to one that has a wid get associated, 55 : m_frame(&frame)
186 // we'd like to EventHandler::handleMousePressEvent to pass the event to the wid get and thus the
187 // event target node can't still be the shadow node.
188 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
189 {
190 Node* targetNode = mev.innerNode();
191 if (!targetNode || !targetNode->parentNode())
192 return true;
193 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(target Node)->host());
194 }
195
196 void recomputeScrollChain(const LocalFrame& frame, const Node& startNode,
197 WillBeHeapDeque<RefPtrWillBeMember<Element>>& scrollChain)
198 {
199 scrollChain.clear();
200
201 ASSERT(startNode.layoutObject());
202 LayoutBox* curBox = startNode.layoutObject()->enclosingBox();
203
204 // Scrolling propagates along the containing block chain.
205 while (curBox && !curBox->isLayoutView()) {
206 Node* curNode = curBox->node();
207 // FIXME: this should reject more elements, as part of crbug.com/410974.
208 if (curNode && curNode->isElementNode())
209 scrollChain.prepend(toElement(curNode));
210 curBox = curBox->containingBlock();
211 }
212
213 // FIXME: we should exclude the document in some cases, as part
214 // of crbug.com/410974.
215 scrollChain.prepend(frame.document()->documentElement());
216 }
217
218 EventHandler::EventHandler(LocalFrame* frame)
219 : m_frame(frame)
220 , m_mousePressed(false)
221 , m_capturesDragging(false)
222 , m_mouseDownMayStartSelect(false) 56 , m_mouseDownMayStartSelect(false)
223 , m_mouseDownMayStartDrag(false)
224 , m_mouseDownWasSingleClickInSelection(false) 57 , m_mouseDownWasSingleClickInSelection(false)
225 , m_selectionInitiationState(HaveNotStartedSelection) 58 , m_selectionInitiationState(HaveNotStartedSelection)
226 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
227 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
228 , m_mouseDownMayStartAutoscroll(false)
229 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFire d)
230 , m_svgPan(false)
231 , m_resizeScrollableArea(nullptr)
232 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
233 , m_clickCount(0)
234 , m_shouldOnlyFireDragOverEvent(false)
235 , m_accumulatedRootOverscroll(FloatSize())
236 , m_mousePositionIsUnknown(true)
237 , m_mouseDownTimestamp(0)
238 , m_widgetIsLatched(false)
239 , m_touchPressed(false)
240 , m_scrollGestureHandlingNode(nullptr)
241 , m_lastGestureScrollOverWidget(false)
242 , m_maxMouseMovedDuration(0)
243 , m_longTapShouldInvokeContextMenu(false)
244 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
245 , m_lastShowPressTimestamp(0)
246 , m_deltaConsumedForScrollSequence(false)
247 { 59 {
248 } 60 }
249 61
250 EventHandler::~EventHandler() 62 DEFINE_TRACE(SelectionController)
251 { 63 {
252 ASSERT(!m_fakeMouseMoveEventTimer.isActive()); 64 visitor->trace(m_frame);
253 }
254
255 DEFINE_TRACE(EventHandler)
256 {
257 #if ENABLE(OILPAN)
258 visitor->trace(m_mousePressNode);
259 visitor->trace(m_capturingMouseEventsNode);
260 visitor->trace(m_nodeUnderMouse);
261 visitor->trace(m_lastNodeUnderMouse);
262 visitor->trace(m_lastMouseMoveEventSubframe);
263 visitor->trace(m_lastScrollbarUnderMouse);
264 visitor->trace(m_clickNode);
265 visitor->trace(m_dragTarget);
266 visitor->trace(m_frameSetBeingResized);
267 visitor->trace(m_latchedWheelEventNode);
268 visitor->trace(m_previousWheelScrolledNode);
269 visitor->trace(m_scrollbarHandlingScrollGesture);
270 visitor->trace(m_targetForTouchID);
271 visitor->trace(m_touchSequenceDocument);
272 visitor->trace(m_scrollGestureHandlingNode);
273 visitor->trace(m_previousGestureScrolledNode);
274 visitor->trace(m_lastDeferredTapElement);
275 visitor->trace(m_currentScrollChain);
276 #endif
277 }
278
279 DragState& EventHandler::dragState()
280 {
281 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState()));
282 return *state;
283 }
284
285 void EventHandler::clear()
286 {
287 m_hoverTimer.stop();
288 m_cursorUpdateTimer.stop();
289 m_fakeMouseMoveEventTimer.stop();
290 m_activeIntervalTimer.stop();
291 m_resizeScrollableArea = nullptr;
292 m_nodeUnderMouse = nullptr;
293 m_lastNodeUnderMouse = nullptr;
294 m_lastMouseMoveEventSubframe = nullptr;
295 m_lastScrollbarUnderMouse = nullptr;
296 m_clickCount = 0;
297 m_clickNode = nullptr;
298 m_frameSetBeingResized = nullptr;
299 m_dragTarget = nullptr;
300 m_shouldOnlyFireDragOverEvent = false;
301 m_mousePositionIsUnknown = true;
302 m_lastKnownMousePosition = IntPoint();
303 m_lastKnownMouseGlobalPosition = IntPoint();
304 m_lastMouseDownUserGestureToken.clear();
305 m_mousePressNode = nullptr;
306 m_mousePressed = false;
307 m_capturesDragging = false;
308 m_capturingMouseEventsNode = nullptr;
309 m_latchedWheelEventNode = nullptr;
310 m_previousWheelScrolledNode = nullptr;
311 m_targetForTouchID.clear();
312 m_touchSequenceDocument.clear();
313 m_touchSequenceUserGestureToken.clear();
314 m_scrollGestureHandlingNode = nullptr;
315 m_lastGestureScrollOverWidget = false;
316 m_previousGestureScrolledNode = nullptr;
317 m_scrollbarHandlingScrollGesture = nullptr;
318 m_maxMouseMovedDuration = 0;
319 m_touchPressed = false;
320 m_mouseDownMayStartSelect = false;
321 m_mouseDownMayStartDrag = false;
322 m_lastShowPressTimestamp = 0;
323 m_lastDeferredTapElement = nullptr;
324 m_eventHandlerWillResetCapturingMouseEventsNode = false;
325 m_mouseDownWasSingleClickInSelection = false;
326 m_selectionInitiationState = HaveNotStartedSelection;
327 m_mouseDownMayStartAutoscroll = false;
328 m_svgPan = false;
329 m_mouseDownPos = IntPoint();
330 m_mouseDownTimestamp = 0;
331 m_longTapShouldInvokeContextMenu = false;
332 m_dragStartPos = LayoutPoint();
333 m_offsetFromResizeCorner = LayoutSize();
334 m_mouseDown = PlatformMouseEvent();
335 }
336
337 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
338 {
339 if (nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get())) {
340 // We don't dispatch click events if the mousedown node is removed
341 // before a mouseup event. It is compatible with IE and Firefox.
342 m_clickNode = nullptr;
343 }
344 } 65 }
345 66
346 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti on& newSelection) 67 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelecti on& newSelection)
347 { 68 {
348 if (selection.selection() != newSelection) 69 if (selection.selection() != newSelection)
349 selection.setSelection(newSelection); 70 selection.setSelection(newSelection);
350 } 71 }
351 72
352 static inline bool dispatchSelectStart(Node* node) 73 static inline bool dispatchSelectStart(Node* node)
353 { 74 {
354 if (!node || !node->layoutObject()) 75 if (!node || !node->layoutObject())
355 return true; 76 return true;
356 77
357 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart)); 78 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::sel ectstart));
358 } 79 }
359 80
360 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection) 81 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
361 { 82 {
362 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode); 83 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
363 if (!rootUserSelectAll) 84 if (!rootUserSelectAll)
364 return selection; 85 return selection;
365 86
366 VisibleSelection newSelection(selection); 87 VisibleSelection newSelection(selection);
367 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCross EditingBoundary)); 88 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCross EditingBoundary));
368 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCr ossEditingBoundary)); 89 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCr ossEditingBoundary));
369 90
370 return newSelection; 91 return newSelection;
371 } 92 }
372 93
373 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targe tNode, const VisibleSelection& selection, TextGranularity granularity) 94 bool SelectionController::updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode, const VisibleSelection& selection, TextGranularity granularity)
374 { 95 {
375 if (Position::nodeIsUserSelectNone(targetNode)) 96 if (Position::nodeIsUserSelectNone(targetNode))
376 return false; 97 return false;
377 98
378 if (!dispatchSelectStart(targetNode)) 99 if (!dispatchSelectStart(targetNode))
379 return false; 100 return false;
380 101
381 if (selection.isRange()) { 102 if (selection.isRange()) {
382 m_selectionInitiationState = ExtendedSelection; 103 m_selectionInitiationState = ExtendedSelection;
383 } else { 104 } else {
384 granularity = CharacterGranularity; 105 granularity = CharacterGranularity;
385 m_selectionInitiationState = PlacedCaret; 106 m_selectionInitiationState = PlacedCaret;
386 } 107 }
387 108
388 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granulari ty); 109 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granulari ty);
389 110
390 return true; 111 return true;
391 } 112 }
392 113
393 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& resul t, AppendTrailingWhitespace appendTrailingWhitespace) 114 void SelectionController::selectClosestWordFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace)
394 { 115 {
395 Node* innerNode = result.innerNode(); 116 Node* innerNode = result.innerNode();
396 VisibleSelection newSelection; 117 VisibleSelection newSelection;
397 118
398 if (innerNode && innerNode->layoutObject()) { 119 if (innerNode && innerNode->layoutObject()) {
399 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); 120 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
400 if (pos.isNotNull()) { 121 if (pos.isNotNull()) {
401 newSelection = VisibleSelection(pos); 122 newSelection = VisibleSelection(pos);
402 newSelection.expandUsingGranularity(WordGranularity); 123 newSelection.expandUsingGranularity(WordGranularity);
403 } 124 }
404 125
405 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) 126 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange())
406 newSelection.appendTrailingWhitespace(); 127 newSelection.appendTrailingWhitespace();
407 128
408 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); 129 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
409 } 130 }
410 } 131 }
411 132
412 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult & result, AppendTrailingWhitespace appendTrailingWhitespace) 133 void SelectionController::selectClosestMisspellingFromHitTestResult(const HitTes tResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
413 { 134 {
414 Node* innerNode = result.innerNode(); 135 Node* innerNode = result.innerNode();
415 VisibleSelection newSelection; 136 VisibleSelection newSelection;
416 137
417 if (innerNode && innerNode->layoutObject()) { 138 if (innerNode && innerNode->layoutObject()) {
418 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); 139 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
419 Position start = pos.deepEquivalent(); 140 Position start = pos.deepEquivalent();
420 Position end = pos.deepEquivalent(); 141 Position end = pos.deepEquivalent();
421 if (pos.isNotNull()) { 142 if (pos.isNotNull()) {
422 DocumentMarkerVector markers = innerNode->document().markers().marke rsInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers()); 143 DocumentMarkerVector markers = innerNode->document().markers().marke rsInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
423 if (markers.size() == 1) { 144 if (markers.size() == 1) {
424 start.moveToOffset(markers[0]->startOffset()); 145 start.moveToOffset(markers[0]->startOffset());
425 end.moveToOffset(markers[0]->endOffset()); 146 end.moveToOffset(markers[0]->endOffset());
426 newSelection = VisibleSelection(start, end); 147 newSelection = VisibleSelection(start, end);
427 } 148 }
428 } 149 }
429 150
430 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange()) 151 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSel ection.isRange())
431 newSelection.appendTrailingWhitespace(); 152 newSelection.appendTrailingWhitespace();
432 153
433 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); 154 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
434 } 155 }
435 } 156 }
436 157
437 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe sults& result) 158 void SelectionController::selectClosestWordFromMouseEvent(const MouseEventWithHi tTestResults& result)
438 { 159 {
439 if (m_mouseDownMayStartSelect) { 160 if (m_mouseDownMayStartSelect) {
440 selectClosestWordFromHitTestResult(result.hitTestResult(), 161 selectClosestWordFromHitTestResult(result.hitTestResult(),
441 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); 162 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace);
442 } 163 }
443 } 164 }
444 165
445 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHi tTestResults& result) 166 void SelectionController::selectClosestMisspellingFromMouseEvent(const MouseEven tWithHitTestResults& result)
446 { 167 {
447 if (m_mouseDownMayStartSelect) { 168 if (m_mouseDownMayStartSelect) {
448 selectClosestMisspellingFromHitTestResult(result.hitTestResult(), 169 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
449 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace); 170 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrail ingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhi tespace);
450 } 171 }
451 } 172 }
452 173
453 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit TestResults& result) 174 void SelectionController::selectClosestWordOrLinkFromMouseEvent(const MouseEvent WithHitTestResults& result)
454 { 175 {
455 if (!result.hitTestResult().isLiveLink()) 176 if (!result.hitTestResult().isLiveLink())
456 return selectClosestWordFromMouseEvent(result); 177 return selectClosestWordFromMouseEvent(result);
457 178
458 Node* innerNode = result.innerNode(); 179 Node* innerNode = result.innerNode();
459 180
460 if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) { 181 if (innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect) {
461 VisibleSelection newSelection; 182 VisibleSelection newSelection;
462 Element* URLElement = result.hitTestResult().URLElement(); 183 Element* URLElement = result.hitTestResult().URLElement();
463 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint())); 184 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(result.l ocalPoint()));
464 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescenda ntOf(URLElement)) 185 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescenda ntOf(URLElement))
465 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElem ent); 186 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElem ent);
466 187
467 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity); 188 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelec tionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
468 } 189 }
469 } 190 }
470 191
471 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestR esults& event) 192 bool SelectionController::handleMousePressEventDoubleClick(const MouseEventWithH itTestResults& event)
472 { 193 {
473 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventDoubleClick"); 194 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventDoubleClick ");
474 195
475 if (event.event().button() != LeftButton) 196 if (event.event().button() != LeftButton)
476 return false; 197 return false;
477 198
478 if (m_frame->selection().isRange()) { 199 if (m_frame->selection().isRange()) {
479 // A double-click when range is already selected 200 // A double-click when range is already selected
480 // should not change the selection. So, do not call 201 // should not change the selection. So, do not call
481 // selectClosestWordFromMouseEvent, but do set 202 // selectClosestWordFromMouseEvent, but do set
482 // m_beganSelectingText to prevent handleMouseReleaseEvent 203 // m_beganSelectingText to prevent handleMouseReleaseEvent
483 // from setting caret selection. 204 // from setting caret selection.
484 m_selectionInitiationState = ExtendedSelection; 205 m_selectionInitiationState = ExtendedSelection;
485 } else { 206 } else {
486 selectClosestWordFromMouseEvent(event); 207 selectClosestWordFromMouseEvent(event);
487 } 208 }
488 return true; 209 return true;
489 } 210 }
490 211
491 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR esults& event) 212 bool SelectionController::handleMousePressEventTripleClick(const MouseEventWithH itTestResults& event)
492 { 213 {
493 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventTripleClick"); 214 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventTripleClick ");
494 215
495 if (event.event().button() != LeftButton) 216 if (event.event().button() != LeftButton)
496 return false; 217 return false;
497 218
498 Node* innerNode = event.innerNode(); 219 Node* innerNode = event.innerNode();
499 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) 220 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect))
500 return false; 221 return false;
501 222
502 VisibleSelection newSelection; 223 VisibleSelection newSelection;
503 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint())); 224 VisiblePosition pos(innerNode->layoutObject()->positionForPoint(event.localP oint()));
504 if (pos.isNotNull()) { 225 if (pos.isNotNull()) {
505 newSelection = VisibleSelection(pos); 226 newSelection = VisibleSelection(pos);
506 newSelection.expandUsingGranularity(ParagraphGranularity); 227 newSelection.expandUsingGranularity(ParagraphGranularity);
507 } 228 }
508 229
509 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity); 230 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSe lectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
510 } 231 }
511 232
512 static int textDistance(const Position& start, const Position& end) 233 static int textDistance(const Position& start, const Position& end)
513 { 234 {
514 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, en d); 235 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, en d);
515 return TextIterator::rangeLength(range->startPosition(), range->endPosition( ), true); 236 return TextIterator::rangeLength(range->startPosition(), range->endPosition( ), true);
516 } 237 }
517 238
518 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR esults& event) 239 bool SelectionController::handleMousePressEventSingleClick(const MouseEventWithH itTestResults& event)
519 { 240 {
520 TRACE_EVENT0("blink", "EventHandler::handleMousePressEventSingleClick"); 241 TRACE_EVENT0("blink", "SelectionController::handleMousePressEventSingleClick ");
521 242
522 m_frame->document()->updateLayoutIgnorePendingStylesheets(); 243 m_frame->document()->updateLayoutIgnorePendingStylesheets();
523 Node* innerNode = event.innerNode(); 244 Node* innerNode = event.innerNode();
524 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect)) 245 if (!(innerNode && innerNode->layoutObject() && m_mouseDownMayStartSelect))
525 return false; 246 return false;
526 247
527 // Extend the selection if the Shift key is down, unless the click is in a l ink. 248 // Extend the selection if the Shift key is down, unless the click is in a l ink.
528 bool extendSelection = event.event().shiftKey() && !event.isOverLink(); 249 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
529 250
530 // Don't restart the selection when the mouse is pressed on an 251 // Don't restart the selection when the mouse is pressed on an
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 { 309 {
589 if (!node || !node->layoutObject()) 310 if (!node || !node->layoutObject())
590 return true; 311 return true;
591 312
592 if (!node->canStartSelection()) 313 if (!node->canStartSelection())
593 return false; 314 return false;
594 315
595 return true; 316 return true;
596 } 317 }
597 318
598 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve nt) 319 void SelectionController::handleMousePressEvent(const MouseEventWithHitTestResul ts& event)
599 { 320 {
600 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent");
601
602 // Reset drag state.
603 dragState().m_dragSrc = nullptr;
604
605 cancelFakeMouseMoveEvent();
606
607 m_frame->document()->updateLayoutIgnorePendingStylesheets();
608
609 if (FrameView* frameView = m_frame->view()) {
610 if (frameView->isPointInScrollbarCorner(event.event().position()))
611 return false;
612 }
613
614 bool singleClick = event.event().clickCount() <= 1;
615
616 // If we got the event back, that must mean it wasn't prevented, 321 // If we got the event back, that must mean it wasn't prevented,
617 // so it's allowed to start a drag or selection if it wasn't in a scrollbar. 322 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
618 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar(); 323 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.innerNode()) && !e vent.scrollbar();
619
620 m_mouseDownMayStartDrag = singleClick;
621
622 m_mouseDownWasSingleClickInSelection = false; 324 m_mouseDownWasSingleClickInSelection = false;
623
624 m_mouseDown = event.event();
625
626 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGEx tensions().zoomAndPanEnabled()) {
627 if (event.event().shiftKey() && singleClick) {
628 m_svgPan = true;
629 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()- >rootFrameToContents(event.event().position()));
630 return true;
631 }
632 }
633
634 // We don't do this at the start of mouse down handling,
635 // because we don't want to do it until we know we didn't hit a widget.
636 if (singleClick)
637 focusDocumentView();
638
639 Node* innerNode = event.innerNode();
640
641 m_mousePressNode = innerNode;
642 m_dragStartPos = event.event().position();
643
644 bool swallowEvent = false;
645 m_mousePressed = true;
646 m_selectionInitiationState = HaveNotStartedSelection;
647
648 if (event.event().clickCount() == 2)
649 swallowEvent = handleMousePressEventDoubleClick(event);
650 else if (event.event().clickCount() >= 3)
651 swallowEvent = handleMousePressEventTripleClick(event);
652 else
653 swallowEvent = handleMousePressEventSingleClick(event);
654
655 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
656 || (m_mousePressNode && m_mousePressNode->layoutBox() && m_mousePressNod e->layoutBox()->canBeProgramaticallyScrolled());
657
658 return swallowEvent;
659 } 325 }
660 326
661 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e vent) 327 void SelectionController::handleMouseDraggedEvent(const MouseEventWithHitTestRes ults& event, const IntPoint& mouseDownPos, const LayoutPoint& dragStartPos, Node * mousePressNode, const IntPoint& lastKnownMousePosition)
662 { 328 {
663 TRACE_EVENT0("blink", "EventHandler::handleMouseDraggedEvent");
664
665 // While resetting m_mousePressed here may seem out of place, it turns out
666 // to be needed to handle some bugs^Wfeatures in Blink mouse event handling:
667 // 1. Certain elements, such as <embed>, capture mouse events. They do not
668 // bubble back up. One way for a <embed> to start capturing mouse events
669 // is on a mouse press. The problem is the <embed> node only starts
670 // capturing mouse events *after* m_mousePressed for the containing frame
671 // has already been set to true. As a result, the frame's EventHandler
672 // never sees the mouse release event, which is supposed to reset
673 // m_mousePressed... so m_mousePressed ends up remaining true until the
674 // event handler finally gets another mouse released event. Oops.
675 // 2. Dragging doesn't start until after a mouse press event, but a drag
676 // that ends as a result of a mouse release does not send a mouse release
677 // event. As a result, m_mousePressed also ends up remaining true until
678 // the next mouse release event seen by the EventHandler.
679 if (event.event().button() != LeftButton)
680 m_mousePressed = false;
681
682 if (!m_mousePressed)
683 return false;
684
685 if (handleDrag(event, DragInitiator::Mouse))
686 return true;
687
688 Node* targetNode = event.innerNode();
689 if (!targetNode)
690 return false;
691
692 LayoutObject* layoutObject = targetNode->layoutObject();
693 if (!layoutObject) {
694 Node* parent = ComposedTreeTraversal::parent(*targetNode);
695 if (!parent)
696 return false;
697
698 layoutObject = parent->layoutObject();
699 if (!layoutObject || !layoutObject->isListBox())
700 return false;
701 }
702
703 m_mouseDownMayStartDrag = false;
704
705 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
706 if (AutoscrollController* controller = autoscrollController()) {
707 controller->startAutoscrollForSelection(layoutObject);
708 m_mouseDownMayStartAutoscroll = false;
709 }
710 }
711
712 if (m_selectionInitiationState != ExtendedSelection) { 329 if (m_selectionInitiationState != ExtendedSelection) {
713 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active ); 330 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active );
714 HitTestResult result(request, m_mouseDownPos); 331 HitTestResult result(request, mouseDownPos);
715 m_frame->document()->layoutView()->hitTest(result); 332 m_frame->document()->layoutView()->hitTest(result);
716 333
717 updateSelectionForMouseDrag(result); 334 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKn ownMousePosition);
718 } 335 }
719 updateSelectionForMouseDrag(event.hitTestResult()); 336 updateSelectionForMouseDrag(event.hitTestResult(), mousePressNode, dragStart Pos, lastKnownMousePosition);
720 return true;
721 } 337 }
722 338
723 void EventHandler::updateSelectionForMouseDrag() 339 void SelectionController::updateSelectionForMouseDrag(Node* mousePressNode, cons t LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition)
724 { 340 {
725 FrameView* view = m_frame->view(); 341 FrameView* view = m_frame->view();
726 if (!view) 342 if (!view)
727 return; 343 return;
728 LayoutView* layoutObject = m_frame->contentLayoutObject(); 344 LayoutView* layoutObject = m_frame->contentLayoutObject();
729 if (!layoutObject) 345 if (!layoutObject)
730 return; 346 return;
731 347
732 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move); 348 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | H itTestRequest::Move);
733 HitTestResult result(request, view->rootFrameToContents(m_lastKnownMousePosi tion)); 349 HitTestResult result(request, view->rootFrameToContents(lastKnownMousePositi on));
734 layoutObject->hitTest(result); 350 layoutObject->hitTest(result);
735 updateSelectionForMouseDrag(result); 351 updateSelectionForMouseDrag(result, mousePressNode, dragStartPos, lastKnownM ousePosition);
736 } 352 }
737 353
738 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul t) 354 void SelectionController::updateSelectionForMouseDrag(const HitTestResult& hitTe stResult, Node* mousePressNode, const LayoutPoint& dragStartPos, const IntPoint& lastKnownMousePosition)
739 { 355 {
740 if (!m_mouseDownMayStartSelect) 356 if (!m_mouseDownMayStartSelect)
741 return; 357 return;
742 358
743 Node* target = hitTestResult.innerNode(); 359 Node* target = hitTestResult.innerNode();
744 if (!target) 360 if (!target)
745 return; 361 return;
746 362
747 VisiblePosition targetPosition = m_frame->selection().selection().visiblePos itionRespectingEditingBoundary(hitTestResult.localPoint(), target); 363 VisiblePosition targetPosition = m_frame->selection().selection().visiblePos itionRespectingEditingBoundary(hitTestResult.localPoint(), target);
748 // Don't modify the selection if we're not on a node. 364 // Don't modify the selection if we're not on a node.
(...skipping 18 matching lines...) Expand all
767 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelect Start(target)) 383 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelect Start(target))
768 return; 384 return;
769 385
770 if (m_selectionInitiationState != ExtendedSelection) { 386 if (m_selectionInitiationState != ExtendedSelection) {
771 // Always extend selection here because it's caused by a mouse drag 387 // Always extend selection here because it's caused by a mouse drag
772 m_selectionInitiationState = ExtendedSelection; 388 m_selectionInitiationState = ExtendedSelection;
773 newSelection = VisibleSelection(targetPosition); 389 newSelection = VisibleSelection(targetPosition);
774 } 390 }
775 391
776 if (RuntimeEnabledFeatures::userSelectAllEnabled()) { 392 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
777 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(m_mousePressNode.get()); 393 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllFo rNode(mousePressNode);
778 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) { 394 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePress Node == Position::rootUserSelectAllForNode(target)) {
779 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePre ssNode).upstream(CanCrossEditingBoundary)); 395 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePre ssNode).upstream(CanCrossEditingBoundary));
780 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePr essNode).downstream(CanCrossEditingBoundary)); 396 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePr essNode).downstream(CanCrossEditingBoundary));
781 } else { 397 } else {
782 // Reset base for user select all when base is inside user-select-al l area and extent < base. 398 // Reset base for user select all when base is inside user-select-al l area and extent < base.
783 if (rootUserSelectAllForMousePressNode && comparePositions(target->l ayoutObject()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->l ayoutObject()->positionForPoint(m_dragStartPos)) < 0) 399 if (rootUserSelectAllForMousePressNode && comparePositions(target->l ayoutObject()->positionForPoint(hitTestResult.localPoint()), mousePressNode->lay outObject()->positionForPoint(dragStartPos)) < 0)
784 newSelection.setBase(positionAfterNode(rootUserSelectAllForMouse PressNode).downstream(CanCrossEditingBoundary)); 400 newSelection.setBase(positionAfterNode(rootUserSelectAllForMouse PressNode).downstream(CanCrossEditingBoundary));
785 401
786 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target); 402 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNod e(target);
787 if (rootUserSelectAllForTarget && m_mousePressNode->layoutObject() & & comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localP oint()), m_mousePressNode->layoutObject()->positionForPoint(m_dragStartPos)) < 0 ) 403 if (rootUserSelectAllForTarget && mousePressNode->layoutObject() && comparePositions(target->layoutObject()->positionForPoint(hitTestResult.localPoi nt()), mousePressNode->layoutObject()->positionForPoint(dragStartPos)) < 0)
788 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTa rget).upstream(CanCrossEditingBoundary)); 404 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTa rget).upstream(CanCrossEditingBoundary));
789 else if (rootUserSelectAllForTarget && m_mousePressNode->layoutObjec t()) 405 else if (rootUserSelectAllForTarget && mousePressNode->layoutObject( ))
790 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTar get).downstream(CanCrossEditingBoundary)); 406 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTar get).downstream(CanCrossEditingBoundary));
791 else 407 else
792 newSelection.setExtent(targetPosition); 408 newSelection.setExtent(targetPosition);
793 } 409 }
794 } else { 410 } else {
795 newSelection.setExtent(targetPosition); 411 newSelection.setExtent(targetPosition);
796 } 412 }
797 413
798 if (m_frame->selection().granularity() != CharacterGranularity) 414 if (m_frame->selection().granularity() != CharacterGranularity)
799 newSelection.expandUsingGranularity(m_frame->selection().granularity()); 415 newSelection.expandUsingGranularity(m_frame->selection().granularity());
800 416
801 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_fram e->selection().granularity(), 417 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_fram e->selection().granularity(),
802 FrameSelection::AdjustEndpointsAtBidiBoundary); 418 FrameSelection::AdjustEndpointsAtBidiBoundary);
803 } 419 }
804 420
805 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e vent) 421 bool SelectionController::handleMouseReleaseEvent(const MouseEventWithHitTestRes ults& event, const LayoutPoint& dragStartPos)
806 { 422 {
807 AutoscrollController* controller = autoscrollController(); 423 bool handled = false;
808 if (controller && controller->autoscrollInProgress())
809 stopAutoscroll();
810
811 // Used to prevent mouseMoveEvent from initiating a drag before
812 // the mouse is pressed again.
813 m_mousePressed = false;
814 m_capturesDragging = false;
815 m_mouseDownMayStartDrag = false;
816 m_mouseDownMayStartSelect = false; 424 m_mouseDownMayStartSelect = false;
817 m_mouseDownMayStartAutoscroll = false;
818
819 bool handled = false;
820
821 // Clear the selection if the mouse didn't move after the last mouse 425 // Clear the selection if the mouse didn't move after the last mouse
822 // press and it's not a context menu click. We do this so when clicking 426 // press and it's not a context menu click. We do this so when clicking
823 // on the selection, the selection goes away. However, if we are 427 // on the selection, the selection goes away. However, if we are
824 // editing, place the caret. 428 // editing, place the caret.
825 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != Ex tendedSelection 429 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != Ex tendedSelection
826 && m_dragStartPos == event.event().position() 430 && dragStartPos == event.event().position()
827 && m_frame->selection().isRange() 431 && m_frame->selection().isRange()
828 && event.event().button() != RightButton) { 432 && event.event().button() != RightButton) {
829 VisibleSelection newSelection; 433 VisibleSelection newSelection;
830 Node* node = event.innerNode(); 434 Node* node = event.innerNode();
831 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled(); 435 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBr owsingEnabled();
832 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) { 436 if (node && node->layoutObject() && (caretBrowsing || node->hasEditableS tyle())) {
833 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint())); 437 VisiblePosition pos = VisiblePosition(node->layoutObject()->position ForPoint(event.localPoint()));
834 newSelection = VisibleSelection(pos); 438 newSelection = VisibleSelection(pos);
835 } 439 }
836 440
837 setSelectionIfNeeded(m_frame->selection(), newSelection); 441 setSelectionIfNeeded(m_frame->selection(), newSelection);
838 442
839 handled = true; 443 handled = true;
840 } 444 }
841 445
842 m_frame->selection().notifyLayoutObjectOfSelectionChange(UserTriggered); 446 m_frame->selection().notifyLayoutObjectOfSelectionChange(UserTriggered);
843 447
844 m_frame->selection().selectFrameElementInParentIfFullySelected(); 448 m_frame->selection().selectFrameElementInParentIfFullySelected();
845 449
846 if (event.event().button() == MiddleButton && !event.isOverLink()) { 450 if (event.event().button() == MiddleButton && !event.isOverLink()) {
847 // Ignore handled, since we want to paste to where the caret was placed anyway. 451 // Ignore handled, since we want to paste to where the caret was placed anyway.
848 handled = handlePasteGlobalSelection(event.event()) || handled; 452 handled = handlePasteGlobalSelection(event.event()) || handled;
849 } 453 }
850 454
851 return handled; 455 return handled;
852 } 456 }
853 457
854 #if OS(WIN)
855 458
856 void EventHandler::startPanScrolling(LayoutObject* layoutObject) 459 bool SelectionController::handlePasteGlobalSelection(const PlatformMouseEvent& m ouseEvent)
857 {
858 if (!layoutObject->isBox())
859 return;
860 AutoscrollController* controller = autoscrollController();
861 if (!controller)
862 return;
863 controller->startPanScrolling(toLayoutBox(layoutObject), lastKnownMousePosit ion());
864 invalidateClick();
865 }
866
867 #endif // OS(WIN)
868
869 AutoscrollController* EventHandler::autoscrollController() const
870 {
871 if (Page* page = m_frame->page())
872 return &page->autoscrollController();
873 return nullptr;
874 }
875
876 bool EventHandler::panScrollInProgress() const
877 {
878 return autoscrollController() && autoscrollController()->panScrollInProgress ();
879 }
880
881 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTe stRequest::HitTestRequestType hitType, const LayoutSize& padding)
882 {
883 TRACE_EVENT0("blink", "EventHandler::hitTestResultAtPoint");
884
885 ASSERT((hitType & HitTestRequest::ListBased) || padding.isEmpty());
886
887 // We always send hitTestResultAtPoint to the main frame if we have one,
888 // otherwise we might hit areas that are obscured by higher frames.
889 if (m_frame->page()) {
890 LocalFrame* mainFrame = m_frame->localFrameRoot();
891 if (mainFrame && m_frame != mainFrame) {
892 FrameView* frameView = m_frame->view();
893 FrameView* mainView = mainFrame->view();
894 if (frameView && mainView) {
895 IntPoint mainFramePoint = mainView->rootFrameToContents(frameVie w->contentsToRootFrame(roundedIntPoint(point)));
896 return mainFrame->eventHandler().hitTestResultAtPoint(mainFrameP oint, hitType, padding);
897 }
898 }
899 }
900
901 // hitTestResultAtPoint is specifically used to hitTest into all frames, thu s it always allows child frame content.
902 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
903 HitTestResult result(request, point, padding.height(), padding.width(), padd ing.height(), padding.width());
904
905 // LayoutView::hitTest causes a layout, and we don't want to hit that until the first
906 // layout because until then, there is nothing shown on the screen - the use r can't
907 // have intentionally clicked on something belonging to this page. Furthermo re,
908 // mousemove events before the first layout should not lead to a premature l ayout()
909 // happening, which could show a flash of white.
910 // See also the similar code in Document::prepareMouseEvent.
911 if (!m_frame->contentLayoutObject() || !m_frame->view() || !m_frame->view()- >didFirstLayout())
912 return result;
913
914 m_frame->contentLayoutObject()->hitTest(result);
915 if (!request.readOnly())
916 m_frame->document()->updateHoverActiveState(request, result.innerElement ());
917
918 return result;
919 }
920
921 void EventHandler::stopAutoscroll()
922 {
923 if (AutoscrollController* controller = autoscrollController())
924 controller->stopAutoscroll();
925 }
926
927 ScrollResultOneDimensional EventHandler::scroll(ScrollDirection direction, Scrol lGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoin t absolutePoint)
928 {
929 if (!delta)
930 return ScrollResultOneDimensional(false);
931
932 Node* node = startNode;
933
934 if (!node)
935 node = m_frame->document()->focusedElement();
936
937 if (!node)
938 node = m_mousePressNode.get();
939
940 if (!node || !node->layoutObject())
941 return ScrollResultOneDimensional(false, delta);
942
943 LayoutBox* curBox = node->layoutObject()->enclosingBox();
944 while (curBox && !curBox->isLayoutView()) {
945 ScrollDirectionPhysical physicalDirection = toPhysicalDirection(
946 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFli ppedBlocksWritingMode());
947
948 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
949 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *st opNode;
950 ScrollResultOneDimensional result = curBox->scroll(physicalDirection, gr anularity, delta);
951
952 if (result.didScroll && stopNode)
953 *stopNode = curBox->node();
954
955 if (result.didScroll || shouldStopBubbling) {
956 setFrameWasScrolledByUser();
957 result.didScroll = true;
958 return result;
959 }
960
961 curBox = curBox->containingBlock();
962 }
963
964 return ScrollResultOneDimensional(false, delta);
965 }
966
967 void EventHandler::customizedScroll(const Node& startNode, ScrollState& scrollSt ate)
968 {
969 if (scrollState.fullyConsumed())
970 return;
971
972 if (m_currentScrollChain.isEmpty())
973 recomputeScrollChain(*m_frame, startNode, m_currentScrollChain);
974 scrollState.setScrollChain(m_currentScrollChain);
975 scrollState.distributeToScrollChainDescendant();
976 }
977
978 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity g ranularity, Node* startingNode)
979 {
980 // The layout needs to be up to date to determine if we can scroll. We may b e
981 // here because of an onLoad event, in which case the final layout hasn't be en performed yet.
982 m_frame->document()->updateLayoutIgnorePendingStylesheets();
983 // FIXME: enable scroll customization in this case. See crbug.com/410974.
984 if (scroll(direction, granularity, startingNode).didScroll)
985 return true;
986 LocalFrame* frame = m_frame;
987 FrameView* view = frame->view();
988 if (view) {
989 ScrollDirectionPhysical physicalDirection =
990 toPhysicalDirection(direction, view->isVerticalDocument(), view->isF lippedDocument());
991 if (view->scrollableArea()->userScroll(physicalDirection, granularity).d idScroll) {
992 setFrameWasScrolledByUser();
993 return true;
994 }
995 }
996
997 Frame* parentFrame = frame->tree().parent();
998 if (!parentFrame || !parentFrame->isLocalFrame())
999 return false;
1000 // FIXME: Broken for OOPI.
1001 return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, g ranularity, m_frame->deprecatedLocalOwner());
1002 }
1003
1004 IntPoint EventHandler::lastKnownMousePosition() const
1005 {
1006 return m_lastKnownMousePosition;
1007 }
1008
1009 static LocalFrame* subframeForTargetNode(Node* node)
1010 {
1011 if (!node)
1012 return nullptr;
1013
1014 LayoutObject* layoutObject = node->layoutObject();
1015 if (!layoutObject || !layoutObject->isLayoutPart())
1016 return nullptr;
1017
1018 Widget* widget = toLayoutPart(layoutObject)->widget();
1019 if (!widget || !widget->isFrameView())
1020 return nullptr;
1021
1022 return &toFrameView(widget)->frame();
1023 }
1024
1025 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1026 {
1027 if (!hitTestResult.isOverWidget())
1028 return nullptr;
1029 return subframeForTargetNode(hitTestResult.innerNode());
1030 }
1031
1032 static bool isSubmitImage(Node* node)
1033 {
1034 return isHTMLInputElement(node) && toHTMLInputElement(node)->type() == Input TypeNames::image;
1035 }
1036
1037 bool EventHandler::useHandCursor(Node* node, bool isOverLink)
1038 {
1039 if (!node)
1040 return false;
1041
1042 return ((isOverLink || isSubmitImage(node)) && !node->hasEditableStyle());
1043 }
1044
1045 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
1046 {
1047 ASSERT(m_frame);
1048 ASSERT(m_frame->document());
1049
1050 updateCursor();
1051 }
1052
1053 void EventHandler::updateCursor()
1054 {
1055 TRACE_EVENT0("input", "EventHandler::updateCursor");
1056
1057 // We must do a cross-frame hit test because the frame that triggered the cu rsor
1058 // update could be occluded by a different frame.
1059 ASSERT(m_frame == m_frame->localFrameRoot());
1060
1061 if (m_mousePositionIsUnknown)
1062 return;
1063
1064 FrameView* view = m_frame->view();
1065 if (!view || !view->shouldSetCursor())
1066 return;
1067
1068 LayoutView* layoutView = view->layoutView();
1069 if (!layoutView)
1070 return;
1071
1072 m_frame->document()->updateLayout();
1073
1074 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::AllowChild FrameContent);
1075 HitTestResult result(request, view->rootFrameToContents(m_lastKnownMousePosi tion));
1076 layoutView->hitTest(result);
1077
1078 if (LocalFrame* frame = result.innerNodeFrame()) {
1079 OptionalCursor optionalCursor = frame->eventHandler().selectCursor(resul t);
1080 if (optionalCursor.isCursorChange()) {
1081 view->setCursor(optionalCursor.cursor());
1082 }
1083 }
1084 }
1085
1086 OptionalCursor EventHandler::selectCursor(const HitTestResult& result)
1087 {
1088 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1089 return NoCursorChange;
1090
1091 Page* page = m_frame->page();
1092 if (!page)
1093 return NoCursorChange;
1094 if (panScrollInProgress())
1095 return NoCursorChange;
1096
1097 Node* node = result.innerPossiblyPseudoNode();
1098 if (!node)
1099 return selectAutoCursor(result, node, iBeamCursor());
1100
1101 LayoutObject* layoutObject = node->layoutObject();
1102 const ComputedStyle* style = layoutObject ? layoutObject->style() : nullptr;
1103
1104 if (layoutObject) {
1105 Cursor overrideCursor;
1106 switch (layoutObject->getCursor(roundedIntPoint(result.localPoint()), ov errideCursor)) {
1107 case SetCursorBasedOnStyle:
1108 break;
1109 case SetCursor:
1110 return overrideCursor;
1111 case DoNotSetCursor:
1112 return NoCursorChange;
1113 }
1114 }
1115
1116 if (style && style->cursors()) {
1117 const CursorList* cursors = style->cursors();
1118 for (unsigned i = 0; i < cursors->size(); ++i) {
1119 StyleImage* styleImage = (*cursors)[i].image();
1120 if (!styleImage)
1121 continue;
1122 ImageResource* cachedImage = styleImage->cachedImage();
1123 if (!cachedImage)
1124 continue;
1125 float scale = styleImage->imageScaleFactor();
1126 bool hotSpotSpecified = (*cursors)[i].hotSpotSpecified();
1127 // Get hotspot and convert from logical pixels to physical pixels.
1128 IntPoint hotSpot = (*cursors)[i].hotSpot();
1129 hotSpot.scale(scale, scale);
1130 IntSize size = cachedImage->imageForLayoutObject(layoutObject)->size ();
1131 if (cachedImage->errorOccurred())
1132 continue;
1133 // Limit the size of cursors (in UI pixels) so that they cannot be
1134 // used to cover UI elements in chrome.
1135 size.scale(1 / scale);
1136 if (size.width() > maximumCursorSize || size.height() > maximumCurso rSize)
1137 continue;
1138
1139 Image* image = cachedImage->imageForLayoutObject(layoutObject);
1140 // Ensure no overflow possible in calculations above.
1141 if (scale < minimumCursorScale)
1142 continue;
1143 return Cursor(image, hotSpotSpecified, hotSpot, scale);
1144 }
1145 }
1146
1147 switch (style ? style->cursor() : CURSOR_AUTO) {
1148 case CURSOR_AUTO: {
1149 bool horizontalText = !style || style->isHorizontalWritingMode();
1150 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCurso r();
1151 return selectAutoCursor(result, node, iBeam);
1152 }
1153 case CURSOR_CROSS:
1154 return crossCursor();
1155 case CURSOR_POINTER:
1156 return handCursor();
1157 case CURSOR_MOVE:
1158 return moveCursor();
1159 case CURSOR_ALL_SCROLL:
1160 return moveCursor();
1161 case CURSOR_E_RESIZE:
1162 return eastResizeCursor();
1163 case CURSOR_W_RESIZE:
1164 return westResizeCursor();
1165 case CURSOR_N_RESIZE:
1166 return northResizeCursor();
1167 case CURSOR_S_RESIZE:
1168 return southResizeCursor();
1169 case CURSOR_NE_RESIZE:
1170 return northEastResizeCursor();
1171 case CURSOR_SW_RESIZE:
1172 return southWestResizeCursor();
1173 case CURSOR_NW_RESIZE:
1174 return northWestResizeCursor();
1175 case CURSOR_SE_RESIZE:
1176 return southEastResizeCursor();
1177 case CURSOR_NS_RESIZE:
1178 return northSouthResizeCursor();
1179 case CURSOR_EW_RESIZE:
1180 return eastWestResizeCursor();
1181 case CURSOR_NESW_RESIZE:
1182 return northEastSouthWestResizeCursor();
1183 case CURSOR_NWSE_RESIZE:
1184 return northWestSouthEastResizeCursor();
1185 case CURSOR_COL_RESIZE:
1186 return columnResizeCursor();
1187 case CURSOR_ROW_RESIZE:
1188 return rowResizeCursor();
1189 case CURSOR_TEXT:
1190 return iBeamCursor();
1191 case CURSOR_WAIT:
1192 return waitCursor();
1193 case CURSOR_HELP:
1194 return helpCursor();
1195 case CURSOR_VERTICAL_TEXT:
1196 return verticalTextCursor();
1197 case CURSOR_CELL:
1198 return cellCursor();
1199 case CURSOR_CONTEXT_MENU:
1200 return contextMenuCursor();
1201 case CURSOR_PROGRESS:
1202 return progressCursor();
1203 case CURSOR_NO_DROP:
1204 return noDropCursor();
1205 case CURSOR_ALIAS:
1206 return aliasCursor();
1207 case CURSOR_COPY:
1208 return copyCursor();
1209 case CURSOR_NONE:
1210 return noneCursor();
1211 case CURSOR_NOT_ALLOWED:
1212 return notAllowedCursor();
1213 case CURSOR_DEFAULT:
1214 return pointerCursor();
1215 case CURSOR_ZOOM_IN:
1216 return zoomInCursor();
1217 case CURSOR_ZOOM_OUT:
1218 return zoomOutCursor();
1219 case CURSOR_WEBKIT_GRAB:
1220 return grabCursor();
1221 case CURSOR_WEBKIT_GRABBING:
1222 return grabbingCursor();
1223 }
1224 return pointerCursor();
1225 }
1226
1227 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam)
1228 {
1229 bool editable = (node && node->hasEditableStyle());
1230
1231 if (useHandCursor(node, result.isOverLink()))
1232 return handCursor();
1233
1234 bool inResizer = false;
1235 LayoutObject* layoutObject = node ? node->layoutObject() : nullptr;
1236 if (layoutObject && m_frame->view()) {
1237 DeprecatedPaintLayer* layer = layoutObject->enclosingLayer();
1238 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointI nResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1239 }
1240
1241 // During selection, use an I-beam no matter what we're over.
1242 // If a drag may be starting or we're capturing mouse events for a particula r node, don't treat this as a selection.
1243 if (m_mousePressed && m_mouseDownMayStartSelect
1244 && !m_mouseDownMayStartDrag
1245 && m_frame->selection().isCaretOrRange()
1246 && !m_capturingMouseEventsNode) {
1247 return iBeam;
1248 }
1249
1250 if ((editable || (layoutObject && layoutObject->isText() && node->canStartSe lection())) && !inResizer && !result.scrollbar())
1251 return iBeam;
1252 return pointerCursor();
1253 }
1254
1255 static LayoutPoint contentPointFromRootFrame(LocalFrame* frame, const IntPoint& pointInRootFrame)
1256 {
1257 FrameView* view = frame->view();
1258 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1259 // Historically the code would just crash; this is clearly no worse than tha t.
1260 return view ? view->rootFrameToContents(pointInRootFrame) : pointInRootFrame ;
1261 }
1262
1263 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1264 {
1265 TRACE_EVENT0("blink", "EventHandler::handleMousePressEvent");
1266
1267 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1268
1269 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1270 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1271
1272 cancelFakeMouseMoveEvent();
1273 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1274 m_capturingMouseEventsNode = nullptr;
1275 m_mousePressed = true;
1276 m_capturesDragging = true;
1277 setLastKnownMousePosition(mouseEvent);
1278 m_mouseDownTimestamp = mouseEvent.timestamp();
1279 m_mouseDownMayStartDrag = false;
1280 m_mouseDownMayStartSelect = false;
1281 m_mouseDownMayStartAutoscroll = false;
1282 if (FrameView* view = m_frame->view()) {
1283 m_mouseDownPos = view->rootFrameToContents(mouseEvent.position());
1284 } else {
1285 invalidateClick();
1286 return false;
1287 }
1288
1289 HitTestRequest request(HitTestRequest::Active);
1290 // Save the document point we generate in case the window coordinate is inva lidated by what happens
1291 // when we dispatch the event.
1292 LayoutPoint documentPoint = contentPointFromRootFrame(m_frame, mouseEvent.po sition());
1293 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(re quest, documentPoint, mouseEvent);
1294
1295 if (!mev.innerNode()) {
1296 invalidateClick();
1297 return false;
1298 }
1299
1300 m_mousePressNode = mev.innerNode();
1301
1302 RefPtrWillBeRawPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1303 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1304 // Start capturing future events for this frame. We only do this if we didn't clear
1305 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1306 m_capturesDragging = subframe->eventHandler().capturesDragging();
1307 if (m_mousePressed && m_capturesDragging) {
1308 m_capturingMouseEventsNode = mev.innerNode();
1309 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1310 }
1311 invalidateClick();
1312 return true;
1313 }
1314
1315 #if OS(WIN)
1316 // We store whether pan scrolling is in progress before calling stopAutoscro ll()
1317 // because it will set m_autoscrollType to NoAutoscroll on return.
1318 bool isPanScrollInProgress = panScrollInProgress();
1319 stopAutoscroll();
1320 if (isPanScrollInProgress) {
1321 // We invalidate the click when exiting pan scrolling so that we don't i nadvertently navigate
1322 // away from the current page (e.g. the click was on a hyperlink). See < rdar://problem/6095023>.
1323 invalidateClick();
1324 return true;
1325 }
1326 #endif
1327
1328 m_clickCount = mouseEvent.clickCount();
1329 m_clickNode = mev.innerNode()->isTextNode() ? ComposedTreeTraversal::parent (*mev.innerNode()) : mev.innerNode();
1330
1331 if (FrameView* view = m_frame->view()) {
1332 DeprecatedPaintLayer* layer = mev.innerNode()->layoutObject() ? mev.inne rNode()->layoutObject()->enclosingLayer() : nullptr;
1333 IntPoint p = view->rootFrameToContents(mouseEvent.position());
1334 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPoint InResizeControl(p, ResizerForPointer)) {
1335 m_resizeScrollableArea = layer->scrollableArea();
1336 m_resizeScrollableArea->setInResizeMode(true);
1337 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offset FromResizeCorner(p));
1338 invalidateClick();
1339 return true;
1340 }
1341 }
1342
1343 m_frame->selection().setCaretBlinkingSuspended(true);
1344
1345 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.inner Node(), m_clickCount, mouseEvent, true);
1346 HitTestResult hitTestResult = hitTestResultInFrame(m_frame, mouseEvent.posit ion(), HitTestRequest::ReadOnly);
1347 swallowEvent = swallowEvent || handleMouseFocus(MouseEventWithHitTestResults (mouseEvent, hitTestResult));
1348 m_capturesDragging = !swallowEvent || mev.scrollbar();
1349
1350 // If the hit testing originally determined the event was in a scrollbar, re fetch the MouseEventWithHitTestResults
1351 // in case the scrollbar widget was destroyed when the mouse event was handl ed.
1352 if (mev.scrollbar()) {
1353 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMou se.get();
1354 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active );
1355 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mou seEvent);
1356 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get ())
1357 m_lastScrollbarUnderMouse = nullptr;
1358 }
1359
1360 if (swallowEvent) {
1361 // scrollbars should get events anyway, even disabled controls might be scrollable
1362 passMousePressEventToScrollbar(mev);
1363 } else {
1364 if (shouldRefetchEventTarget(mev)) {
1365 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Ac tive);
1366 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1367 }
1368
1369 if (passMousePressEventToScrollbar(mev))
1370 swallowEvent = true;
1371 else
1372 swallowEvent = handleMousePressEvent(mev);
1373 }
1374
1375 return swallowEvent;
1376 }
1377
1378 static DeprecatedPaintLayer* layerForNode(Node* node)
1379 {
1380 if (!node)
1381 return nullptr;
1382
1383 LayoutObject* layoutObject = node->layoutObject();
1384 if (!layoutObject)
1385 return nullptr;
1386
1387 DeprecatedPaintLayer* layer = layoutObject->enclosingLayer();
1388 if (!layer)
1389 return nullptr;
1390
1391 return layer;
1392 }
1393
1394 ScrollableArea* EventHandler::associatedScrollableArea(const DeprecatedPaintLaye r* layer) const
1395 {
1396 if (DeprecatedPaintLayerScrollableArea* scrollableArea = layer->scrollableAr ea()) {
1397 if (scrollableArea->scrollsOverflow())
1398 return scrollableArea;
1399 }
1400
1401 return nullptr;
1402 }
1403
1404 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1405 {
1406 TRACE_EVENT0("blink", "EventHandler::handleMouseMoveEvent");
1407
1408 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1409 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1410
1411 HitTestResult hoveredNode = HitTestResult();
1412 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1413
1414 Page* page = m_frame->page();
1415 if (!page)
1416 return result;
1417
1418 if (DeprecatedPaintLayer* layer = layerForNode(hoveredNode.innerNode())) {
1419 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer ))
1420 layerScrollableArea->mouseMovedInContentArea();
1421 }
1422
1423 if (FrameView* frameView = m_frame->view())
1424 frameView->mouseMovedInContentArea();
1425
1426 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1427 page->chromeClient().mouseDidMoveOverElement(hoveredNode);
1428
1429 return result;
1430 }
1431
1432 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1433 {
1434 TRACE_EVENT0("blink", "EventHandler::handleMouseLeaveEvent");
1435
1436 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1437 handleMouseMoveOrLeaveEvent(event, 0, false, true);
1438 }
1439
1440 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEv ent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars, bool forceLeave)
1441 {
1442 ASSERT(m_frame);
1443 ASSERT(m_frame->view());
1444
1445 setLastKnownMousePosition(mouseEvent);
1446
1447 if (m_hoverTimer.isActive())
1448 m_hoverTimer.stop();
1449
1450 m_cursorUpdateTimer.stop();
1451
1452 cancelFakeMouseMoveEvent();
1453
1454 if (m_svgPan) {
1455 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->ro otFrameToContents(m_lastKnownMousePosition));
1456 return true;
1457 }
1458
1459 if (m_frameSetBeingResized)
1460 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingRes ized.get(), 0, mouseEvent, false);
1461
1462 // Send events right to a scrollbar if the mouse is pressed.
1463 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1464 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1465 return true;
1466 }
1467
1468 // Mouse events simulated from touch should not hit-test again.
1469 ASSERT(!mouseEvent.fromTouch());
1470
1471 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move;
1472 if (m_mousePressed) {
1473 hitType |= HitTestRequest::Active;
1474 } else if (onlyUpdateScrollbars) {
1475 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1476 // means that :hover and :active freeze in the state they were in, rathe r than updating
1477 // for nodes the mouse moves while the window is not key (which will be the case if
1478 // onlyUpdateScrollbars is true).
1479 hitType |= HitTestRequest::ReadOnly;
1480 }
1481
1482 // Treat any mouse move events as readonly if the user is currently touching the screen.
1483 if (m_touchPressed)
1484 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1485 HitTestRequest request(hitType);
1486 MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(mouseEvent, HitTestResult(request, LayoutPoint()));
1487
1488 // We don't want to do a hit-test in forceLeave scenarios because there migh t actually be some other frame above this one at the specified co-ordinate.
1489 // So we must force the hit-test to fail, while still clearing hover/active state.
1490 if (forceLeave)
1491 m_frame->document()->updateHoverActiveState(request, 0);
1492 else
1493 mev = prepareMouseEvent(request, mouseEvent);
1494
1495 if (hoveredNode)
1496 *hoveredNode = mev.hitTestResult();
1497
1498 Scrollbar* scrollbar = nullptr;
1499
1500 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
1501 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1502 } else {
1503 if (!scrollbar)
1504 scrollbar = mev.scrollbar();
1505
1506 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1507 if (onlyUpdateScrollbars)
1508 return true;
1509 }
1510
1511 bool swallowEvent = false;
1512 RefPtrWillBeRawPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get( ) ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTest Result(mev);
1513
1514 // We want mouseouts to happen first, from the inside out. First send a mov e event to the last subframe so that it will fire mouseouts.
1515 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isD escendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1516 m_lastMouseMoveEventSubframe->eventHandler().handleMouseLeaveEvent(mouse Event);
1517
1518 if (newSubframe) {
1519 // Update over/out state before passing the event to the subframe.
1520 updateMouseEventTargetNode(mev.innerNode(), mouseEvent, true);
1521
1522 // Event dispatch in updateMouseEventTargetNode may have caused the subf rame of the target
1523 // node to be detached from its FrameView, in which case the event shoul d not be passed.
1524 if (newSubframe->view())
1525 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1526 } else {
1527 if (scrollbar && !m_mousePressed)
1528 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platfo rms that support visual feedback on scrollbar hovering.
1529 if (FrameView* view = m_frame->view()) {
1530 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult());
1531 if (optionalCursor.isCursorChange()) {
1532 view->setCursor(optionalCursor.cursor());
1533 }
1534 }
1535 }
1536
1537 m_lastMouseMoveEventSubframe = newSubframe;
1538
1539 if (swallowEvent)
1540 return true;
1541
1542 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.innerNode( ), 0, mouseEvent, true);
1543 if (!swallowEvent)
1544 swallowEvent = handleMouseDraggedEvent(mev);
1545
1546 return swallowEvent;
1547 }
1548
1549 void EventHandler::invalidateClick()
1550 {
1551 m_clickCount = 0;
1552 m_clickNode = nullptr;
1553 }
1554
1555 static ContainerNode* parentForClickEvent(const Node& node)
1556 {
1557 // IE doesn't dispatch click events for mousedown/mouseup events across form
1558 // controls.
1559 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1560 return nullptr;
1561
1562 return ComposedTreeTraversal::parent(node);
1563 }
1564
1565 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1566 {
1567 TRACE_EVENT0("blink", "EventHandler::handleMouseReleaseEvent");
1568
1569 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
1570
1571 m_frame->selection().setCaretBlinkingSuspended(false);
1572
1573 OwnPtr<UserGestureIndicator> gestureIndicator;
1574
1575 if (m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToke n)
1576 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->localFrame Root()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1577 else
1578 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessin gUserGesture));
1579
1580 #if OS(WIN)
1581 if (Page* page = m_frame->page())
1582 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1583 #endif
1584
1585 m_mousePressed = false;
1586 setLastKnownMousePosition(mouseEvent);
1587
1588 if (m_svgPan) {
1589 m_svgPan = false;
1590 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->ro otFrameToContents(m_lastKnownMousePosition));
1591 return true;
1592 }
1593
1594 if (m_frameSetBeingResized)
1595 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResiz ed.get(), m_clickCount, mouseEvent, false);
1596
1597 if (m_lastScrollbarUnderMouse) {
1598 invalidateClick();
1599 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1600 bool setUnder = false;
1601 return !dispatchMouseEvent(EventTypeNames::mouseup, m_nodeUnderMouse.get (), m_clickCount, mouseEvent, setUnder);
1602 }
1603
1604 // Mouse events simulated from touch should not hit-test again.
1605 ASSERT(!mouseEvent.fromTouch());
1606
1607 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release;
1608 HitTestRequest request(hitType);
1609 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1610 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetN ode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1611 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1612 m_capturingMouseEventsNode = nullptr;
1613 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1614 return true;
1615
1616 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev. innerNode(), m_clickCount, mouseEvent, false);
1617
1618 bool contextMenuEvent = mouseEvent.button() == RightButton;
1619 #if OS(MACOSX)
1620 // FIXME: The Mac port achieves the same behavior by checking whether the co ntext menu is currently open in WebPage::mouseEvent(). Consider merging the impl ementations.
1621 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEv ent::CtrlKey)
1622 contextMenuEvent = true;
1623 #endif
1624
1625 bool swallowClickEvent = false;
1626 if (m_clickCount > 0 && !contextMenuEvent && mev.innerNode() && m_clickNode && mev.innerNode()->canParticipateInComposedTree() && m_clickNode->canParticipat eInComposedTree()) {
1627 // Updates distribution because a 'mouseup' event listener can make the
1628 // tree dirty at dispatchMouseEvent() invocation above.
1629 // Unless distribution is updated, commonAncestor would hit ASSERT.
1630 // Both m_clickNode and mev.innerNode() don't need to be updated
1631 // because commonAncestor() will exit early if their documents are diffe rent.
1632 m_clickNode->updateDistribution();
1633 if (Node* clickTargetNode = mev.innerNode()->commonAncestor(*m_clickNode , parentForClickEvent))
1634 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, click TargetNode, m_clickCount, mouseEvent, true);
1635 }
1636
1637 if (m_resizeScrollableArea) {
1638 m_resizeScrollableArea->setInResizeMode(false);
1639 m_resizeScrollableArea = nullptr;
1640 }
1641
1642 bool swallowMouseReleaseEvent = false;
1643 if (!swallowMouseUpEvent)
1644 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1645
1646 invalidateClick();
1647
1648 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1649 }
1650
1651 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEve nt)
1652 { 460 {
1653 // If the event was a middle click, attempt to copy global selection in afte r 461 // If the event was a middle click, attempt to copy global selection in afte r
1654 // the newly set caret position. 462 // the newly set caret position.
1655 // 463 //
1656 // This code is called from either the mouse up or mouse down handling. Ther e 464 // This code is called from either the mouse up or mouse down handling. Ther e
1657 // is some debate about when the global selection is pasted: 465 // is some debate about when the global selection is pasted:
1658 // xterm: pastes on up. 466 // xterm: pastes on up.
1659 // GTK: pastes on down. 467 // GTK: pastes on down.
1660 // Qt: pastes on up. 468 // Qt: pastes on up.
1661 // Firefox: pastes on up. 469 // Firefox: pastes on up.
(...skipping 10 matching lines...) Expand all
1672 if (!m_frame->page()) 480 if (!m_frame->page())
1673 return false; 481 return false;
1674 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame(); 482 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1675 // Do not paste here if the focus was moved somewhere else. 483 // Do not paste here if the focus was moved somewhere else.
1676 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction()) 484 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSele ction())
1677 return m_frame->editor().command("PasteGlobalSelection").execute(); 485 return m_frame->editor().command("PasteGlobalSelection").execute();
1678 486
1679 return false; 487 return false;
1680 } 488 }
1681 489
1682 490 bool SelectionController::handleGestureLongPress(const PlatformGestureEvent& ges tureEvent, const HitTestResult& hitTestResult)
1683 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa rget, const PlatformMouseEvent& event, DataTransfer* dataTransfer)
1684 { 491 {
1685 FrameView* view = m_frame->view();
1686
1687 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1688 if (!view)
1689 return false;
1690
1691 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType,
1692 true, true, m_frame->document()->domWindow(),
1693 0, event.globalPosition().x(), event.globalPosition().y(), event.positio n().x(), event.position().y(),
1694 event.movementDelta().x(), event.movementDelta().y(),
1695 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1696 0, MouseEvent::platformModifiersToButtons(event.modifiers()), nullptr, d ataTransfer);
1697
1698 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1699 return me->defaultPrevented();
1700 }
1701
1702 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1703 {
1704 if (!isHTMLFrameElementBase(target))
1705 return false;
1706
1707 // Cross-process drag and drop is not yet supported.
1708 if (toHTMLFrameElementBase(target)->contentFrame() && !toHTMLFrameElementBas e(target)->contentFrame()->isLocalFrame())
1709 return false;
1710
1711 frame = toLocalFrame(toHTMLFrameElementBase(target)->contentFrame());
1712 return true;
1713 }
1714
1715 static bool findDropZone(Node* target, DataTransfer* dataTransfer)
1716 {
1717 Element* element = target->isElementNode() ? toElement(target) : target->par entElement();
1718 for (; element; element = element->parentElement()) {
1719 bool matched = false;
1720 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr) ;
1721
1722 if (dropZoneStr.isEmpty())
1723 continue;
1724
1725 UseCounter::count(element->document(), UseCounter::PrefixedHTMLElementDr opzone);
1726
1727 dropZoneStr = dropZoneStr.lower();
1728
1729 SpaceSplitString keywords(dropZoneStr, SpaceSplitString::ShouldNotFoldCa se);
1730 if (keywords.isNull())
1731 continue;
1732
1733 DragOperation dragOperation = DragOperationNone;
1734 for (unsigned i = 0; i < keywords.size(); i++) {
1735 DragOperation op = convertDropZoneOperationToDragOperation(keywords[ i]);
1736 if (op != DragOperationNone) {
1737 if (dragOperation == DragOperationNone)
1738 dragOperation = op;
1739 } else {
1740 matched = matched || dataTransfer->hasDropZoneType(keywords[i].s tring());
1741 }
1742
1743 if (matched && dragOperation != DragOperationNone)
1744 break;
1745 }
1746 if (matched) {
1747 dataTransfer->setDropEffect(convertDragOperationToDropZoneOperation( dragOperation));
1748 return true;
1749 }
1750 }
1751 return false;
1752 }
1753
1754 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, DataTransf er* dataTransfer)
1755 {
1756 bool accept = false;
1757
1758 if (!m_frame->view())
1759 return false;
1760
1761 HitTestRequest request(HitTestRequest::ReadOnly);
1762 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1763
1764 // Drag events should never go to text nodes (following IE, and proper mouse over/out dispatch)
1765 RefPtrWillBeRawPtr<Node> newTarget = mev.innerNode();
1766 if (newTarget && newTarget->isTextNode())
1767 newTarget = ComposedTreeTraversal::parent(*newTarget);
1768
1769 if (AutoscrollController* controller = autoscrollController())
1770 controller->updateDragAndDrop(newTarget.get(), event.position(), event.t imestamp());
1771
1772 if (m_dragTarget != newTarget) {
1773 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1774 // it is sometimes incorrect when dragging within subframes, as seen wit h
1775 // LayoutTests/fast/events/drag-in-frames.html.
1776 //
1777 // 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>.
1778 LocalFrame* targetFrame;
1779 if (targetIsFrame(newTarget.get(), targetFrame)) {
1780 if (targetFrame)
1781 accept = targetFrame->eventHandler().updateDragAndDrop(event, da taTransfer);
1782 } else if (newTarget) {
1783 // As per section 7.9.4 of the HTML 5 spec., we must always fire a d rag event before firing a dragenter, dragleave, or dragover event.
1784 if (dragState().m_dragSrc) {
1785 // for now we don't care if event handler cancels default behavi or, since there is none
1786 dispatchDragSrcEvent(EventTypeNames::drag, event);
1787 }
1788 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get( ), event, dataTransfer);
1789 if (!accept)
1790 accept = findDropZone(newTarget.get(), dataTransfer);
1791 }
1792
1793 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1794 if (targetFrame)
1795 accept = targetFrame->eventHandler().updateDragAndDrop(event, da taTransfer);
1796 } else if (m_dragTarget) {
1797 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), eve nt, dataTransfer);
1798 }
1799
1800 if (newTarget) {
1801 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1802 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1803 m_shouldOnlyFireDragOverEvent = true;
1804 }
1805 } else {
1806 LocalFrame* targetFrame;
1807 if (targetIsFrame(newTarget.get(), targetFrame)) {
1808 if (targetFrame)
1809 accept = targetFrame->eventHandler().updateDragAndDrop(event, da taTransfer);
1810 } else if (newTarget) {
1811 // Note, when dealing with sub-frames, we may need to fire only a dr agover event as a drag event may have been fired earlier.
1812 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1813 // for now we don't care if event handler cancels default behavi or, since there is none
1814 dispatchDragSrcEvent(EventTypeNames::drag, event);
1815 }
1816 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get() , event, dataTransfer);
1817 if (!accept)
1818 accept = findDropZone(newTarget.get(), dataTransfer);
1819 m_shouldOnlyFireDragOverEvent = false;
1820 }
1821 }
1822 m_dragTarget = newTarget;
1823
1824 return accept;
1825 }
1826
1827 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, DataTransf er* dataTransfer)
1828 {
1829 LocalFrame* targetFrame;
1830 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1831 if (targetFrame)
1832 targetFrame->eventHandler().cancelDragAndDrop(event, dataTransfer);
1833 } else if (m_dragTarget.get()) {
1834 if (dragState().m_dragSrc)
1835 dispatchDragSrcEvent(EventTypeNames::drag, event);
1836 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, dataTransfer);
1837 }
1838 clearDragState();
1839 }
1840
1841 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, DataTrans fer* dataTransfer)
1842 {
1843 LocalFrame* targetFrame;
1844 bool preventedDefault = false;
1845 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1846 if (targetFrame)
1847 preventedDefault = targetFrame->eventHandler().performDragAndDrop(ev ent, dataTransfer);
1848 } else if (m_dragTarget.get()) {
1849 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget. get(), event, dataTransfer);
1850 }
1851 clearDragState();
1852 return preventedDefault;
1853 }
1854
1855 void EventHandler::clearDragState()
1856 {
1857 stopAutoscroll();
1858 m_dragTarget = nullptr;
1859 m_capturingMouseEventsNode = nullptr;
1860 m_shouldOnlyFireDragOverEvent = false;
1861 }
1862
1863 void EventHandler::setCapturingMouseEventsNode(PassRefPtrWillBeRawPtr<Node> n)
1864 {
1865 m_capturingMouseEventsNode = n;
1866 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1867 }
1868
1869 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestReques t& request, const PlatformMouseEvent& mev)
1870 {
1871 ASSERT(m_frame);
1872 ASSERT(m_frame->document());
1873
1874 return m_frame->document()->prepareMouseEvent(request, contentPointFromRootF rame(m_frame, mev.position()), mev);
1875 }
1876
1877 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo useEvent& mouseEvent, bool fireMouseEvents)
1878 {
1879 Node* result = targetNode;
1880
1881 // If we're capturing, we always go right to that node.
1882 if (m_capturingMouseEventsNode) {
1883 result = m_capturingMouseEventsNode.get();
1884 } else {
1885 // If the target node is a text node, dispatch on the parent node - rdar ://4196646
1886 if (result && result->isTextNode())
1887 result = ComposedTreeTraversal::parent(*result);
1888 }
1889 m_nodeUnderMouse = result;
1890
1891 if (fireMouseEvents) {
1892 DeprecatedPaintLayer* layerForLastNode = layerForNode(m_lastNodeUnderMou se.get());
1893 DeprecatedPaintLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderM ouse.get());
1894 Page* page = m_frame->page();
1895
1896 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->docu ment() != m_frame->document())) {
1897 // The mouse has moved between frames.
1898 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1899 if (FrameView* frameView = frame->view())
1900 frameView->mouseExitedContentArea();
1901 }
1902 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || laye rForNodeUnderMouse != layerForLastNode))) {
1903 // The mouse has moved between layers.
1904 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollable Area(layerForLastNode))
1905 scrollableAreaForLastNode->mouseExitedContentArea();
1906 }
1907
1908 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse-> document() != m_frame->document())) {
1909 // The mouse has moved between frames.
1910 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
1911 if (FrameView* frameView = frame->view())
1912 frameView->mouseEnteredContentArea();
1913 }
1914 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || laye rForNodeUnderMouse != layerForLastNode))) {
1915 // The mouse has moved between layers.
1916 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScro llableArea(layerForNodeUnderMouse))
1917 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1918 }
1919
1920 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame- >document()) {
1921 m_lastNodeUnderMouse = nullptr;
1922 m_lastScrollbarUnderMouse = nullptr;
1923 }
1924
1925 if (m_lastNodeUnderMouse != m_nodeUnderMouse)
1926 sendMouseEventsForNodeTransition(m_lastNodeUnderMouse.get(), m_nodeU nderMouse.get(), mouseEvent);
1927
1928 m_lastNodeUnderMouse = m_nodeUnderMouse;
1929 }
1930 }
1931
1932 void EventHandler::sendMouseEventsForNodeTransition(Node* exitedNode, Node* ente redNode, const PlatformMouseEvent& mouseEvent)
1933 {
1934 ASSERT(exitedNode != enteredNode);
1935
1936 // First, dispatch mouseout event (which bubbles to ancestors)
1937 if (exitedNode)
1938 exitedNode->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, enteredNode);
1939
1940 // A note on mouseenter and mouseleave: These are non-bubbling events, and t hey are dispatched if there
1941 // is a capturing event handler on an ancestor or a normal event handler on the element itself. This special
1942 // handling is necessary to avoid O(n^2) capturing event handler checks.
1943 //
1944 // Note, however, that this optimization can possibly cause some unanswere d/missing/redundant mouseenter or
1945 // mouseleave events in certain contrived eventhandling scenarios, e.g., whe n:
1946 // - the mouseleave handler for a node sets the only capturing-mouseleave-li stener in its ancestor, or
1947 // - DOM mods in any mouseenter/mouseleave handler changes the common ancest or of exited & entered nodes, etc.
1948 // We think the spec specifies a "frozen" state to avoid such corner cases ( check the discussion on "candidate event
1949 // listeners" at http://www.w3.org/TR/uievents), but our code below preserve s one such behavior from past only to
1950 // match Firefox and IE behavior.
1951 //
1952 // TODO(mustaq): Confirm spec conformance, double-check with other browsers.
1953
1954 // Create lists of all exited/entered ancestors.
1955 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> exitedAncestors;
1956 WillBeHeapVector<RefPtrWillBeMember<Node>, 32> enteredAncestors;
1957 if (exitedNode) {
1958 exitedNode->updateDistribution();
1959 for (Node* node = exitedNode; node; node = ComposedTreeTraversal::parent (*node)) {
1960 exitedAncestors.append(node);
1961 }
1962 }
1963 if (enteredNode) {
1964 enteredNode->updateDistribution();
1965 for (Node* node = enteredNode; node; node = ComposedTreeTraversal::paren t(*node)) {
1966 enteredAncestors.append(node);
1967 }
1968 }
1969
1970 size_t numExitedAncestors = exitedAncestors.size();
1971 size_t numEnteredAncestors = enteredAncestors.size();
1972
1973 // Locate the common ancestor in the two lists. Start with the assumption th at it's off both the lists.
1974 size_t exitedAncestorIndex = numExitedAncestors;
1975 size_t enteredAncestorIndex = numEnteredAncestors;
1976 for (size_t j = 0; j < numExitedAncestors; j++) {
1977 for (size_t i = 0; i < numEnteredAncestors; i++) {
1978 if (exitedAncestors[j] == enteredAncestors[i]) {
1979 exitedAncestorIndex = j;
1980 enteredAncestorIndex = i;
1981 break;
1982 }
1983 }
1984 if (exitedAncestorIndex < numExitedAncestors)
1985 break;
1986 }
1987
1988 // Determine if there is a capturing mouseleave listener in an ancestor.
1989 bool exitedNodeHasCapturingAncestor = false;
1990 for (size_t j = 0; j < numExitedAncestors; j++) {
1991 if (exitedAncestors[j]->hasCapturingEventListeners(EventTypeNames::mouse leave))
1992 exitedNodeHasCapturingAncestor = true;
1993 }
1994
1995 // Send mouseleave events to appropriate exited ancestors, in child-to-paren t order.
1996 for (size_t j = 0; j < exitedAncestorIndex; j++) {
1997 if (exitedNodeHasCapturingAncestor || exitedAncestors[j]->hasEventListen ers(EventTypeNames::mouseleave))
1998 exitedAncestors[j]->dispatchMouseEvent(mouseEvent, EventTypeNames::m ouseleave, 0, enteredNode);
1999 }
2000
2001 // Dispatch mouseover event (which bubbles to ancestors) after the mouseleav e events are sent.
2002 if (enteredNode)
2003 enteredNode->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0 , exitedNode);
2004
2005 // Determine if there is a capturing mouseenter listener in an ancestor. Thi s must be done /after/ dispatching the
2006 // mouseleave events because the handler for mouseleave might set a capturin g mouseenter handler.
2007 bool enteredNodeHasCapturingAncestor = false;
2008 for (size_t i = 0; i < numEnteredAncestors; i++) {
2009 if (enteredAncestors[i]->hasCapturingEventListeners(EventTypeNames::mous eenter))
2010 enteredNodeHasCapturingAncestor = true;
2011 }
2012
2013 // Send mouseenter events to appropriate entered ancestors, in parent-to-chi ld order.
2014 for (size_t i = enteredAncestorIndex; i > 0; i--) {
2015 if (enteredNodeHasCapturingAncestor || enteredAncestors[i-1]->hasEventLi steners(EventTypeNames::mouseenter))
2016 enteredAncestors[i-1]->dispatchMouseEvent(mouseEvent, EventTypeNames ::mouseenter, 0, exitedNode);
2017 }
2018 }
2019
2020 // The return value means 'continue default handling.'
2021 // TODO(mustaq): setUnder needs a more informative name.
2022 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe tNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2023 {
2024 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2025 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2026 }
2027
2028 // The return value means 'swallow event' (was handled), as for other handle* fu nctions.
2029 bool EventHandler::handleMouseFocus(const MouseEventWithHitTestResults& targeted Event)
2030 {
2031 const PlatformMouseEvent& mouseEvent = targetedEvent.event();
2032
2033 // If clicking on a frame scrollbar, do not mess up with content focus.
2034 if (FrameView* view = m_frame->view()) {
2035 if (view->scrollbarAtRootFramePoint(mouseEvent.position()))
2036 return false;
2037 }
2038
2039 // The layout needs to be up to date to determine if an element is focusable .
2040 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2041
2042 Element* element = nullptr;
2043 if (m_nodeUnderMouse)
2044 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse ) : m_nodeUnderMouse->parentOrShadowHostElement();
2045 for (; element; element = element->parentOrShadowHostElement()) {
2046 if (element->isFocusable() && element->isFocusedElementInDocument())
2047 return false;
2048 if (element->isMouseFocusable())
2049 break;
2050 }
2051 ASSERT(!element || element->isMouseFocusable());
2052
2053 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
2054 // a node on mouse down if it's selected and inside a focused node. It will
2055 // be focused if the user does a mouseup over it, however, because the
2056 // mouseup will set a selection inside it, which will call
2057 // FrameSelection::setFocusedNodeIfNeeded.
2058 if (element
2059 && m_frame->selection().isRange()
2060 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE _EXCEPTION) == Range::NODE_INSIDE
2061 && element->isDescendantOf(m_frame->document()->focusedElement()))
2062 return false;
2063
2064 // Only change the focus when clicking scrollbars if it can transfered to a
2065 // mouse focusable node.
2066 if (!element && targetedEvent.hitTestResult().scrollbar())
2067 return true;
2068
2069 if (Page* page = m_frame->page()) {
2070 // If focus shift is blocked, we eat the event. Note we should never
2071 // clear swallowEvent if the page already set it (e.g., by canceling
2072 // default behavior).
2073 if (element) {
2074 if (slideFocusOnShadowHostIfNecessary(*element))
2075 return true;
2076 if (!page->focusController().setFocusedElement(element, m_frame, Web FocusTypeMouse))
2077 return true;
2078 } else {
2079 // We call setFocusedElement even with !element in order to blur
2080 // current focus element when a link is clicked; this is expected by
2081 // some sites that rely on onChange handlers running from form
2082 // fields before the button click is processed.
2083 if (!page->focusController().setFocusedElement(0, m_frame))
2084 return true;
2085 }
2086 }
2087
2088 return false;
2089 }
2090
2091 bool EventHandler::slideFocusOnShadowHostIfNecessary(const Element& element)
2092 {
2093 if (element.shadowRoot() && element.shadowRoot()->delegatesFocus()) {
2094 Document* doc = m_frame->document();
2095 if (element.containsIncludingShadowDOM(doc->focusedElement())) {
2096 // If the inner element is already focused, do nothing.
2097 return true;
2098 }
2099
2100 // If the host has a focusable inner element, focus it. Otherwise, the h ost takes focus.
2101 Page* page = m_frame->page();
2102 ASSERT(page);
2103 Element* next = page->focusController().findFocusableElement(WebFocusTyp eForward, *element.shadowRoot());
2104 if (next && element.containsIncludingShadowDOM(next)) {
2105 // Use WebFocusTypeForward instead of WebFocusTypeMouse here to mean the focus has slided.
2106 next->focus(false, WebFocusTypeForward);
2107 return true;
2108 }
2109 }
2110 return false;
2111 }
2112
2113 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
2114 {
2115 #define RETURN_WHEEL_EVENT_HANDLED() \
2116 { \
2117 setFrameWasScrolledByUser(); \
2118 return true; \
2119 }
2120
2121 Document* doc = m_frame->document();
2122
2123 if (!doc->layoutView())
2124 return false;
2125
2126 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2127
2128 FrameView* view = m_frame->view();
2129 if (!view)
2130 return false;
2131
2132 LayoutPoint vPoint = view->rootFrameToContents(event.position());
2133
2134 HitTestRequest request(HitTestRequest::ReadOnly);
2135 HitTestResult result(request, vPoint);
2136 doc->layoutView()->hitTest(result);
2137
2138 Node* node = result.innerNode();
2139 // Wheel events should not dispatch to text nodes.
2140 if (node && node->isTextNode())
2141 node = ComposedTreeTraversal::parent(*node);
2142
2143 bool isOverWidget;
2144 if (event.useLatchedEventNode()) {
2145 if (!m_latchedWheelEventNode) {
2146 m_latchedWheelEventNode = node;
2147 m_widgetIsLatched = result.isOverWidget();
2148 } else {
2149 node = m_latchedWheelEventNode.get();
2150 }
2151
2152 isOverWidget = m_widgetIsLatched;
2153 } else {
2154 if (m_latchedWheelEventNode)
2155 m_latchedWheelEventNode = nullptr;
2156 if (m_previousWheelScrolledNode)
2157 m_previousWheelScrolledNode = nullptr;
2158
2159 isOverWidget = result.isOverWidget();
2160 }
2161
2162 if (node) {
2163 // Figure out which view to send the event to.
2164 LayoutObject* target = node->layoutObject();
2165
2166 if (isOverWidget && target && target->isLayoutPart()) {
2167 Widget* widget = toLayoutPart(target)->widget();
2168 if (widget && passWheelEventToWidget(event, *widget))
2169 RETURN_WHEEL_EVENT_HANDLED();
2170 }
2171
2172 if (node && !node->dispatchWheelEvent(event))
2173 RETURN_WHEEL_EVENT_HANDLED();
2174 }
2175
2176 // We do another check on the frame view because the event handler can run
2177 // JS which results in the frame getting destroyed.
2178 view = m_frame->view();
2179 if (!view)
2180 return false;
2181
2182 if (view->scrollableArea()->handleWheel(event).didScroll())
2183 RETURN_WHEEL_EVENT_HANDLED();
2184
2185 return false;
2186 #undef RETURN_WHEEL_EVENT_HANDLED
2187 }
2188
2189 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEv ent)
2190 {
2191 if (!startNode || !wheelEvent)
2192 return;
2193
2194 // When the wheelEvent do not scroll, we trigger zoom in/out instead.
2195 if (!wheelEvent->canScroll())
2196 return;
2197
2198 Node* stopNode = m_previousWheelScrolledNode.get();
2199 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEve nt);
2200 IntPoint absolutePosition = roundedIntPoint(wheelEvent->absoluteLocation());
2201
2202 // Break up into two scrolls if we need to. Diagonal movement on
2203 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where b oth deltaX and deltaY can be set).
2204
2205 // FIXME: enable scroll customization in this case. See crbug.com/410974.
2206 if (wheelEvent->railsMode() != Event::RailsModeVertical
2207 && scroll(ScrollRightIgnoringWritingMode, granularity, startNode, &stopN ode, wheelEvent->deltaX(), absolutePosition).didScroll)
2208 wheelEvent->setDefaultHandled();
2209
2210 if (wheelEvent->railsMode() != Event::RailsModeHorizontal
2211 && scroll(ScrollDownIgnoringWritingMode, granularity, startNode, &stopNo de, wheelEvent->deltaY(), absolutePosition).didScroll)
2212 wheelEvent->setDefaultHandled();
2213
2214 if (!m_latchedWheelEventNode)
2215 m_previousWheelScrolledNode = stopNode;
2216 }
2217
2218 bool EventHandler::handleGestureShowPress()
2219 {
2220 m_lastShowPressTimestamp = WTF::currentTime();
2221
2222 FrameView* view = m_frame->view();
2223 if (!view)
2224 return false;
2225 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2226 scrollAnimator->cancelAnimations();
2227 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2228 if (!areas)
2229 return false;
2230 for (const ScrollableArea* scrollableArea : *areas) {
2231 ScrollAnimator* animator = scrollableArea->existingScrollAnimator();
2232 if (animator)
2233 animator->cancelAnimations();
2234 }
2235 return false;
2236 }
2237
2238 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2239 {
2240 // Propagation to inner frames is handled below this function.
2241 ASSERT(m_frame == m_frame->localFrameRoot());
2242
2243 // Scrolling-related gesture events invoke EventHandler recursively for each frame down
2244 // the chain, doing a single-frame hit-test per frame. This matches handleWh eelEvent.
2245 // FIXME: Add a test that traverses this path, e.g. for devtools overlay.
2246 if (gestureEvent.isScrollEvent())
2247 return handleGestureScrollEvent(gestureEvent);
2248
2249 // Hit test across all frames and do touch adjustment as necessary for the e vent type.
2250 GestureEventWithHitTestResults targetedEvent = targetGestureEvent(gestureEve nt);
2251
2252 return handleGestureEvent(targetedEvent);
2253 }
2254
2255 bool EventHandler::handleGestureEvent(const GestureEventWithHitTestResults& targ etedEvent)
2256 {
2257 TRACE_EVENT0("input", "EventHandler::handleGestureEvent");
2258
2259 // Propagation to inner frames is handled below this function.
2260 ASSERT(m_frame == m_frame->localFrameRoot());
2261
2262 // Non-scrolling related gesture events do a single cross-frame hit-test and jump
2263 // directly to the inner most frame. This matches handleMousePressEvent etc.
2264 ASSERT(!targetedEvent.event().isScrollEvent());
2265
2266 // Route to the correct frame.
2267 if (LocalFrame* innerFrame = targetedEvent.hitTestResult().innerNodeFrame())
2268 return innerFrame->eventHandler().handleGestureEventInFrame(targetedEven t);
2269
2270 // No hit test result, handle in root instance. Perhaps we should just retur n false instead?
2271 return handleGestureEventInFrame(targetedEvent);
2272 }
2273
2274 bool EventHandler::handleGestureEventInFrame(const GestureEventWithHitTestResult s& targetedEvent)
2275 {
2276 ASSERT(!targetedEvent.event().isScrollEvent());
2277
2278 RefPtrWillBeRawPtr<Node> eventTarget = targetedEvent.hitTestResult().innerNo de();
2279 RefPtrWillBeRawPtr<Scrollbar> scrollbar = targetedEvent.hitTestResult().scro llbar();
2280 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2281
2282 if (scrollbar) {
2283 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2284 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallow ed)
2285 m_scrollbarHandlingScrollGesture = scrollbar;
2286 if (eventSwallowed)
2287 return true;
2288 }
2289
2290 if (eventTarget && eventTarget->dispatchGestureEvent(gestureEvent))
2291 return true;
2292
2293 switch (gestureEvent.type()) {
2294 case PlatformEvent::GestureTap:
2295 return handleGestureTap(targetedEvent);
2296 case PlatformEvent::GestureShowPress:
2297 return handleGestureShowPress();
2298 case PlatformEvent::GestureLongPress:
2299 return handleGestureLongPress(targetedEvent);
2300 case PlatformEvent::GestureLongTap:
2301 return handleGestureLongTap(targetedEvent);
2302 case PlatformEvent::GestureTwoFingerTap:
2303 return sendContextMenuEventForGesture(targetedEvent);
2304 case PlatformEvent::GestureTapDown:
2305 case PlatformEvent::GesturePinchBegin:
2306 case PlatformEvent::GesturePinchEnd:
2307 case PlatformEvent::GesturePinchUpdate:
2308 case PlatformEvent::GestureTapDownCancel:
2309 case PlatformEvent::GestureTapUnconfirmed:
2310 break;
2311 default:
2312 ASSERT_NOT_REACHED();
2313 }
2314
2315 return false;
2316 }
2317
2318 bool EventHandler::handleGestureScrollEvent(const PlatformGestureEvent& gestureE vent)
2319 {
2320 TRACE_EVENT0("input", "EventHandler::handleGestureScrollEvent");
2321
2322 RefPtrWillBeRawPtr<Node> eventTarget = nullptr;
2323 RefPtrWillBeRawPtr<Scrollbar> scrollbar = nullptr;
2324 if (gestureEvent.type() != PlatformEvent::GestureScrollBegin) {
2325 scrollbar = m_scrollbarHandlingScrollGesture.get();
2326 eventTarget = m_scrollGestureHandlingNode.get();
2327 }
2328
2329 if (!eventTarget) {
2330 Document* document = m_frame->document();
2331 if (!document->layoutView())
2332 return false;
2333
2334 FrameView* view = m_frame->view();
2335 LayoutPoint viewPoint = view->rootFrameToContents(gestureEvent.position( ));
2336 HitTestRequest request(HitTestRequest::ReadOnly);
2337 HitTestResult result(request, viewPoint);
2338 document->layoutView()->hitTest(result);
2339
2340 eventTarget = result.innerNode();
2341
2342 m_lastGestureScrollOverWidget = result.isOverWidget();
2343 m_scrollGestureHandlingNode = eventTarget;
2344 m_previousGestureScrolledNode = nullptr;
2345
2346 if (!scrollbar)
2347 scrollbar = result.scrollbar();
2348 }
2349
2350 if (scrollbar) {
2351 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2352 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2353 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2354 || !eventSwallowed) {
2355 m_scrollbarHandlingScrollGesture = nullptr;
2356 }
2357 if (eventSwallowed)
2358 return true;
2359 }
2360
2361 if (eventTarget) {
2362 bool eventSwallowed = handleScrollGestureOnResizer(eventTarget.get(), ge stureEvent);
2363 if (!eventSwallowed)
2364 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2365 if (eventSwallowed)
2366 return true;
2367 }
2368
2369 switch (gestureEvent.type()) {
2370 case PlatformEvent::GestureScrollBegin:
2371 return handleGestureScrollBegin(gestureEvent);
2372 case PlatformEvent::GestureScrollUpdate:
2373 return handleGestureScrollUpdate(gestureEvent);
2374 case PlatformEvent::GestureScrollEnd:
2375 return handleGestureScrollEnd(gestureEvent);
2376 case PlatformEvent::GestureFlingStart:
2377 case PlatformEvent::GesturePinchBegin:
2378 case PlatformEvent::GesturePinchEnd:
2379 case PlatformEvent::GesturePinchUpdate:
2380 return false;
2381 default:
2382 ASSERT_NOT_REACHED();
2383 return false;
2384 }
2385 }
2386
2387 bool EventHandler::handleGestureTap(const GestureEventWithHitTestResults& target edEvent)
2388 {
2389 RefPtrWillBeRawPtr<FrameView> frameView(m_frame->view());
2390 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2391 HitTestRequest::HitTestRequestType hitType = getHitTypeForGestureType(gestur eEvent.type());
2392 uint64_t preDispatchDomTreeVersion = m_frame->document()->domTreeVersion();
2393 uint64_t preDispatchStyleVersion = m_frame->document()->styleVersion();
2394
2395 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2396
2397 HitTestResult currentHitTest = targetedEvent.hitTestResult();
2398
2399 // We use the adjusted position so the application isn't surprised to see a event with
2400 // co-ordinates outside the target's bounds.
2401 IntPoint adjustedPoint = frameView->rootFrameToContents(gestureEvent.positio n());
2402
2403 unsigned modifiers = gestureEvent.modifiers();
2404 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globa lPosition(),
2405 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2406 static_cast<PlatformEvent::Modifiers>(modifiers),
2407 PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2408 dispatchMouseEvent(EventTypeNames::mousemove, currentHitTest.innerNode(), 0, fakeMouseMove, true);
2409
2410 // Do a new hit-test in case the mousemove event changed the DOM.
2411 // Note that if the original hit test wasn't over an element (eg. was over a scrollbar) we
2412 // don't want to re-hit-test because it may be in the wrong frame (and there 's no way the page
2413 // could have seen the event anyway).
2414 // Also note that the position of the frame may have changed, so we need to recompute the content
2415 // co-ordinates (updating layout/style as hitTestResultAtPoint normally woul d).
2416 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug. com/398920
2417 if (currentHitTest.innerNode()) {
2418 LocalFrame* mainFrame = m_frame->localFrameRoot();
2419 if (mainFrame && mainFrame->view())
2420 mainFrame->view()->updateLayoutAndStyleForPainting();
2421 adjustedPoint = frameView->rootFrameToContents(gestureEvent.position());
2422 currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, hitType);
2423 }
2424 m_clickNode = currentHitTest.innerNode();
2425
2426 // Capture data for showUnhandledTapUIIfNeeded.
2427 RefPtrWillBeRawPtr<Node> tappedNode = m_clickNode;
2428 IntPoint tappedPosition = gestureEvent.position();
2429
2430 if (m_clickNode && m_clickNode->isTextNode())
2431 m_clickNode = ComposedTreeTraversal::parent(*m_clickNode);
2432
2433 PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globa lPosition(),
2434 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2435 static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::LeftBut tonDown),
2436 PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2437 bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true);
2438 if (!swallowMouseDownEvent)
2439 swallowMouseDownEvent = handleMouseFocus(MouseEventWithHitTestResults(fa keMouseDown, currentHitTest));
2440 if (!swallowMouseDownEvent)
2441 swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResul ts(fakeMouseDown, currentHitTest));
2442
2443 // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug. com/398920
2444 if (currentHitTest.innerNode()) {
2445 LocalFrame* mainFrame = m_frame->localFrameRoot();
2446 if (mainFrame && mainFrame->view())
2447 mainFrame->view()->updateLayoutAndStyleForPainting();
2448 adjustedPoint = frameView->rootFrameToContents(gestureEvent.position());
2449 currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, hitType);
2450 }
2451 PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalP osition(),
2452 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2453 static_cast<PlatformEvent::Modifiers>(modifiers),
2454 PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2455 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, curr entHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseUp, false);
2456
2457 bool swallowClickEvent = false;
2458 if (m_clickNode) {
2459 if (currentHitTest.innerNode()) {
2460 // Updates distribution because a mouseup (or mousedown) event liste ner can make the
2461 // tree dirty at dispatchMouseEvent() invocation above.
2462 // Unless distribution is updated, commonAncestor would hit ASSERT.
2463 // Both m_clickNode and currentHitTest.innerNode()) don't need to be updated
2464 // because commonAncestor() will exit early if their documents are d ifferent.
2465 m_clickNode->updateDistribution();
2466 Node* clickTargetNode = currentHitTest.innerNode()->commonAncestor(* m_clickNode, parentForClickEvent);
2467 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, click TargetNode, gestureEvent.tapCount(), fakeMouseUp, true);
2468 }
2469 m_clickNode = nullptr;
2470 }
2471
2472 if (!swallowMouseUpEvent)
2473 swallowMouseUpEvent = handleMouseReleaseEvent(MouseEventWithHitTestResul ts(fakeMouseUp, currentHitTest));
2474
2475 bool swallowed = swallowMouseDownEvent | swallowMouseUpEvent | swallowClickE vent;
2476 if (!swallowed && tappedNode && m_frame->page()) {
2477 bool domTreeChanged = preDispatchDomTreeVersion != m_frame->document()-> domTreeVersion();
2478 bool styleChanged = preDispatchStyleVersion != m_frame->document()->styl eVersion();
2479
2480 IntPoint tappedPositionInViewport = m_frame->page()->frameHost().pinchVi ewport().rootFrameToViewport(tappedPosition);
2481 m_frame->chromeClient().showUnhandledTapUIIfNeeded(tappedPositionInViewp ort, tappedNode.get(), domTreeChanged || styleChanged);
2482 }
2483 return swallowed;
2484 }
2485
2486 bool EventHandler::handleGestureLongPress(const GestureEventWithHitTestResults& targetedEvent)
2487 {
2488 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
2489 IntPoint adjustedPoint = gestureEvent.position();
2490
2491 unsigned modifiers = gestureEvent.modifiers();
2492
2493 // FIXME: Ideally we should try to remove the extra mouse-specific hit-tests here (re-using the
2494 // supplied HitTestResult), but that will require some overhaul of the touch drag-and-drop code
2495 // and LongPress is such a special scenario that it's unlikely to matter muc h in practice.
2496
2497 m_longTapShouldInvokeContextMenu = false;
2498 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_ frame->view()) {
2499 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosi tion(), LeftButton, PlatformEvent::MousePressed, 1,
2500 static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::Lef tButtonDown),
2501 PlatformMouseEvent::FromTouch, WTF::currentTime());
2502 m_mouseDown = mouseDownEvent;
2503
2504 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosi tion(), LeftButton, PlatformEvent::MouseMoved, 1,
2505 static_cast<PlatformEvent::Modifiers>(modifiers | PlatformEvent::Lef tButtonDown),
2506 PlatformMouseEvent::FromTouch, WTF::currentTime());
2507 HitTestRequest request(HitTestRequest::ReadOnly);
2508 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragE vent);
2509 m_mouseDownMayStartDrag = true;
2510 dragState().m_dragSrc = nullptr;
2511 m_mouseDownPos = m_frame->view()->rootFrameToContents(mouseDragEvent.pos ition());
2512 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2513 if (handleDrag(mev, DragInitiator::Touch)) {
2514 m_longTapShouldInvokeContextMenu = true;
2515 return true;
2516 }
2517 }
2518 #if OS(ANDROID) 492 #if OS(ANDROID)
2519 bool shouldLongPressSelectWord = true; 493 bool shouldLongPressSelectWord = true;
2520 #else 494 #else
2521 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()- >touchEditingEnabled(); 495 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()- >touchEditingEnabled();
2522 #endif 496 #endif
2523 if (shouldLongPressSelectWord) { 497 if (shouldLongPressSelectWord) {
2524 IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(gestureEven t.position()); 498
2525 HitTestResult result = hitTestResultAtPoint(hitTestPoint); 499
2526 Node* innerNode = result.innerNode(); 500 Node* innerNode = hitTestResult.innerNode();
2527 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode() 501 if (!hitTestResult.isLiveLink() && innerNode && (innerNode->isContentEdi table() || innerNode->isTextNode()
2528 #if OS(ANDROID) 502 #if OS(ANDROID)
2529 || innerNode->canStartSelection() 503 || innerNode->canStartSelection()
2530 #endif 504 #endif
2531 )) { 505 )) {
2532 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitesp ace); 506 selectClosestWordFromHitTestResult(hitTestResult, DontAppendTrailing Whitespace);
2533 if (m_frame->selection().isRange()) { 507 if (m_frame->selection().isRange())
2534 focusDocumentView();
2535 return true; 508 return true;
2536 }
2537 } 509 }
2538 } 510 }
2539 return sendContextMenuEventForGesture(targetedEvent);
2540 }
2541
2542 bool EventHandler::handleGestureLongTap(const GestureEventWithHitTestResults& ta rgetedEvent)
2543 {
2544 #if !OS(ANDROID)
2545 if (m_longTapShouldInvokeContextMenu) {
2546 m_longTapShouldInvokeContextMenu = false;
2547 return sendContextMenuEventForGesture(targetedEvent);
2548 }
2549 #endif
2550 return false; 511 return false;
2551 } 512 }
2552 513
2553 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const Platfor mGestureEvent& gestureEvent) 514 void SelectionController::sendContextMenuEvent(const MouseEventWithHitTestResult s& mev, const LayoutPoint& position)
2554 { 515 {
2555 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) { 516 if (!m_frame->selection().contains(position)
2556 DeprecatedPaintLayer* layer = eventTarget->layoutObject() ? eventTarget- >layoutObject()->enclosingLayer() : nullptr;
2557 IntPoint p = m_frame->view()->rootFrameToContents(gestureEvent.position( ));
2558 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPoint InResizeControl(p, ResizerForTouch)) {
2559 m_resizeScrollableArea = layer->scrollableArea();
2560 m_resizeScrollableArea->setInResizeMode(true);
2561 m_offsetFromResizeCorner = LayoutSize(m_resizeScrollableArea->offset FromResizeCorner(p));
2562 return true;
2563 }
2564 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate) {
2565 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2566 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorne r);
2567 return true;
2568 }
2569 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2570 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2571 m_resizeScrollableArea->setInResizeMode(false);
2572 m_resizeScrollableArea = nullptr;
2573 return false;
2574 }
2575 }
2576
2577 return false;
2578 }
2579
2580 bool EventHandler::passScrollGestureEventToWidget(const PlatformGestureEvent& ge stureEvent, LayoutObject* layoutObject)
2581 {
2582 ASSERT(gestureEvent.isScrollEvent());
2583
2584 if (!m_lastGestureScrollOverWidget)
2585 return false;
2586
2587 if (!layoutObject || !layoutObject->isLayoutPart())
2588 return false;
2589
2590 Widget* widget = toLayoutPart(layoutObject)->widget();
2591
2592 if (!widget || !widget->isFrameView())
2593 return false;
2594
2595 return toFrameView(widget)->frame().eventHandler().handleGestureScrollEvent( gestureEvent);
2596 }
2597
2598 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEve nt)
2599 {
2600 RefPtrWillBeRawPtr<Node> node = m_scrollGestureHandlingNode;
2601
2602 if (node) {
2603 passScrollGestureEventToWidget(gestureEvent, node->layoutObject());
2604 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) {
2605 RefPtrWillBeRawPtr<ScrollState> scrollState = ScrollState::create(
2606 0, 0, 0, 0, 0, gestureEvent.inertial(), /* isBeginning */
2607 false, /* isEnding */ true, /* fromUserInput */ true);
2608 customizedScroll(*node.get(), *scrollState);
2609 }
2610 }
2611
2612 clearGestureScrollState();
2613 return false;
2614 }
2615
2616 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureE vent)
2617 {
2618 Document* document = m_frame->document();
2619 if (!document->layoutView())
2620 return false;
2621
2622 FrameView* view = m_frame->view();
2623 if (!view)
2624 return false;
2625
2626 // If there's no layoutObject on the node, send the event to the nearest anc estor with a layoutObject.
2627 // Needed for <option> and <optgroup> elements so we can touch scroll <selec t>s
2628 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->layoutOb ject())
2629 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShado wHostNode();
2630
2631 if (!m_scrollGestureHandlingNode) {
2632 if (RuntimeEnabledFeatures::scrollCustomizationEnabled())
2633 m_scrollGestureHandlingNode = m_frame->document()->documentElement() ;
2634 else
2635 return false;
2636 }
2637 ASSERT(m_scrollGestureHandlingNode);
2638
2639 passScrollGestureEventToWidget(gestureEvent, m_scrollGestureHandlingNode->la youtObject());
2640 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) {
2641 m_currentScrollChain.clear();
2642 RefPtrWillBeRawPtr<ScrollState> scrollState = ScrollState::create(
2643 0, 0, 0, 0, 0, /* inInertialPhase */ false, /* isBeginning */
2644 true, /* isEnding */ false, /* fromUserInput */ true);
2645 customizedScroll(*m_scrollGestureHandlingNode.get(), *scrollState);
2646 } else {
2647 if (m_frame->isMainFrame())
2648 m_frame->host()->topControls().scrollBegin();
2649 }
2650 return true;
2651 }
2652
2653 void EventHandler::resetOverscroll(bool didScrollX, bool didScrollY)
2654 {
2655 if (didScrollX)
2656 m_accumulatedRootOverscroll.setWidth(0);
2657 if (didScrollY)
2658 m_accumulatedRootOverscroll.setHeight(0);
2659 }
2660
2661 void EventHandler::handleOverscroll(const ScrollResult& scrollResult, const Plat formGestureEvent& gestureEvent)
2662 {
2663 if (m_frame->isMainFrame() && m_frame->view() && m_frame->view()->scrollable Area()) {
2664 ScrollableArea* scrollablearea = m_frame->view()->scrollableArea();
2665 // Set unusedDelta if axis is scrollable, else set 0 to ensure overflow is not reported on non-scrollable axes.
2666 FloatSize unusedDelta(scrollablearea->scrollSize(HorizontalScrollbar) ? scrollResult.unusedScrollDeltaX : 0, scrollablearea->scrollSize(VerticalScrollba r) ? scrollResult.unusedScrollDeltaY : 0);
2667 resetOverscroll(scrollResult.didScrollX, scrollResult.didScrollY);
2668 if (unusedDelta != FloatSize()) {
2669 m_accumulatedRootOverscroll += unusedDelta;
2670 FloatPoint position = FloatPoint(gestureEvent.position().x(), gestur eEvent.position().y());
2671 FloatSize velocity = FloatSize(gestureEvent.velocityX(), gestureEven t.velocityY());
2672 m_frame->chromeClient().didOverscroll(unusedDelta, m_accumulatedRoot Overscroll, position, velocity);
2673 }
2674 }
2675 }
2676
2677 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gesture Event)
2678 {
2679 ASSERT(gestureEvent.type() == PlatformEvent::GestureScrollUpdate);
2680
2681 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2682 if (delta.isZero())
2683 return false;
2684
2685 Node* node = m_scrollGestureHandlingNode.get();
2686 if (node) {
2687 LayoutObject* layoutObject = node->layoutObject();
2688 if (!layoutObject)
2689 return false;
2690
2691 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
2692
2693 Node* stopNode = nullptr;
2694
2695 // Try to send the event to the correct view.
2696 if (passScrollGestureEventToWidget(gestureEvent, layoutObject)) {
2697 if (gestureEvent.preventPropagation()
2698 && !RuntimeEnabledFeatures::scrollCustomizationEnabled()) {
2699 // This is an optimization which doesn't apply with
2700 // scroll customization enabled.
2701 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2702 }
2703 // FIXME: we should allow simultaneous scrolling of nested
2704 // iframes along perpendicular axes. See crbug.com/466991.
2705 m_deltaConsumedForScrollSequence = true;
2706 return true;
2707 }
2708
2709 bool scrolled = false;
2710 if (RuntimeEnabledFeatures::scrollCustomizationEnabled()) {
2711 RefPtrWillBeRawPtr<ScrollState> scrollState = ScrollState::create(
2712 gestureEvent.deltaX(), gestureEvent.deltaY(),
2713 0, gestureEvent.velocityX(), gestureEvent.velocityY(),
2714 gestureEvent.inertial(), /* isBeginning */
2715 false, /* isEnding */ false, /* fromUserInput */ true,
2716 !gestureEvent.preventPropagation(), m_deltaConsumedForScrollSequ ence);
2717 if (m_previousGestureScrolledNode) {
2718 // The ScrollState needs to know what the current
2719 // native scrolling element is, so that for an
2720 // inertial scroll that shouldn't propagate, only the
2721 // currently scrolling element responds.
2722 ASSERT(m_previousGestureScrolledNode->isElementNode());
2723 scrollState->setCurrentNativeScrollingElement(toElement(m_previo usGestureScrolledNode.get()));
2724 }
2725 customizedScroll(*node, *scrollState);
2726 m_previousGestureScrolledNode = scrollState->currentNativeScrollingE lement();
2727 m_deltaConsumedForScrollSequence = scrollState->deltaConsumedForScro llSequence();
2728 scrolled = scrollState->deltaX() != gestureEvent.deltaX()
2729 || scrollState->deltaY() != gestureEvent.deltaY();
2730 } else {
2731 if (gestureEvent.preventPropagation())
2732 stopNode = m_previousGestureScrolledNode.get();
2733
2734 // First try to scroll the closest scrollable LayoutBox ancestor of |node|.
2735 ScrollGranularity granularity = ScrollByPrecisePixel;
2736 ScrollResultOneDimensional result = scroll(ScrollLeftIgnoringWriting Mode, granularity, node, &stopNode, delta.width());
2737 bool horizontalScroll = result.didScroll;
2738 if (!gestureEvent.preventPropagation())
2739 stopNode = nullptr;
2740 result = scroll(ScrollUpIgnoringWritingMode, granularity, node, &sto pNode, delta.height());
2741 bool verticalScroll = result.didScroll;
2742 scrolled = horizontalScroll || verticalScroll;
2743
2744 if (gestureEvent.preventPropagation())
2745 m_previousGestureScrolledNode = stopNode;
2746
2747 resetOverscroll(horizontalScroll, verticalScroll);
2748 }
2749 if (scrolled) {
2750 setFrameWasScrolledByUser();
2751 return true;
2752 }
2753 }
2754
2755 if (RuntimeEnabledFeatures::scrollCustomizationEnabled())
2756 return false;
2757
2758 // Try to scroll the frame view.
2759 ScrollResult scrollResult = m_frame->applyScrollDelta(delta, false);
2760 handleOverscroll(scrollResult, gestureEvent);
2761 if (scrollResult.didScroll()) {
2762 setFrameWasScrolledByUser();
2763 return true;
2764 }
2765
2766 return false;
2767 }
2768
2769 void EventHandler::clearGestureScrollState()
2770 {
2771 m_scrollGestureHandlingNode = nullptr;
2772 m_previousGestureScrolledNode = nullptr;
2773 m_deltaConsumedForScrollSequence = false;
2774 m_currentScrollChain.clear();
2775 m_accumulatedRootOverscroll = FloatSize();
2776 }
2777
2778 bool EventHandler::isScrollbarHandlingGestures() const
2779 {
2780 return m_scrollbarHandlingScrollGesture.get();
2781 }
2782
2783 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2784 {
2785 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2786 return false;
2787 return !event.area().isEmpty();
2788 }
2789
2790 bool EventHandler::bestClickableNodeForHitTestResult(const HitTestResult& result , IntPoint& targetPoint, Node*& targetNode)
2791 {
2792 // FIXME: Unify this with the other best* functions which are very similar.
2793
2794 TRACE_EVENT0("input", "EventHandler::bestClickableNodeForHitTestResult");
2795 ASSERT(result.isRectBasedTest());
2796
2797 // If the touch is over a scrollbar, don't adjust the touch point since touc h adjustment only takes into account
2798 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nod es. This leads to things like textarea
2799 // scrollbars being untouchable.
2800 if (result.scrollbar()) {
2801 targetNode = 0;
2802 return false;
2803 }
2804
2805 IntPoint touchCenter = m_frame->view()->contentsToRootFrame(result.roundedPo intInMainFrame());
2806 IntRect touchRect = m_frame->view()->contentsToRootFrame(result.hitTestLocat ion().boundingBox());
2807
2808 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2809 copyToVector(result.listBasedTestResult(), nodes);
2810
2811 // FIXME: the explicit Vector conversion copies into a temporary and is wast eful.
2812 return findBestClickableCandidate(targetNode, targetPoint, touchCenter, touc hRect, WillBeHeapVector<RefPtrWillBeMember<Node>> (nodes));
2813 }
2814
2815 bool EventHandler::bestContextMenuNodeForHitTestResult(const HitTestResult& resu lt, IntPoint& targetPoint, Node*& targetNode)
2816 {
2817 ASSERT(result.isRectBasedTest());
2818 IntPoint touchCenter = m_frame->view()->contentsToRootFrame(result.roundedPo intInMainFrame());
2819 IntRect touchRect = m_frame->view()->contentsToRootFrame(result.hitTestLocat ion().boundingBox());
2820 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2821 copyToVector(result.listBasedTestResult(), nodes);
2822
2823 // FIXME: the explicit Vector conversion copies into a temporary and is wast eful.
2824 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, to uchRect, WillBeHeapVector<RefPtrWillBeMember<Node>>(nodes));
2825 }
2826
2827 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, co nst IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2828 {
2829 if (touchRadius.isEmpty())
2830 return false;
2831
2832 IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(touchCenter);
2833
2834 HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitT estRequest::Active | HitTestRequest::ListBased;
2835 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType, LayoutSiz e(touchRadius));
2836
2837 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2838 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2839 copyToVector(result.listBasedTestResult(), nodes);
2840
2841 // FIXME: the explicit Vector conversion copies into a temporary and is wast eful.
2842 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node>>(nodes));
2843 }
2844
2845 // Update the hover and active state across all frames for this gesture.
2846 // This logic is different than the mouse case because mice send MouseLeave even ts to frames as they're exited.
2847 // With gestures, a single event conceptually both 'leaves' whatever frame curre ntly had hover and enters a new frame
2848 void EventHandler::updateGestureHoverActiveState(const HitTestRequest& request, Element* innerElement)
2849 {
2850 ASSERT(m_frame == m_frame->localFrameRoot());
2851
2852 WillBeHeapVector<LocalFrame*> newHoverFrameChain;
2853 LocalFrame* newHoverFrameInDocument = innerElement ? innerElement->document( ).frame() : nullptr;
2854 // Insert the ancestors of the frame having the new hovered node to the fram e chain
2855 // The frame chain doesn't include the main frame to avoid the redundant wor k that cleans the hover state.
2856 // Because the hover state for the main frame is updated by calling Document ::updateHoverActiveState
2857 while (newHoverFrameInDocument && newHoverFrameInDocument != m_frame) {
2858 newHoverFrameChain.append(newHoverFrameInDocument);
2859 Frame* parentFrame = newHoverFrameInDocument->tree().parent();
2860 newHoverFrameInDocument = parentFrame && parentFrame->isLocalFrame() ? t oLocalFrame(parentFrame) : nullptr;
2861 }
2862
2863 RefPtrWillBeRawPtr<Node> oldHoverNodeInCurDoc = m_frame->document()->hoverNo de();
2864 RefPtrWillBeRawPtr<Node> newInnermostHoverNode = innerElement;
2865
2866 if (newInnermostHoverNode != oldHoverNodeInCurDoc) {
2867 size_t indexFrameChain = newHoverFrameChain.size();
2868
2869 // Clear the hover state on any frames which are no longer in the frame chain of the hovered elemen
2870 while (oldHoverNodeInCurDoc && oldHoverNodeInCurDoc->isFrameOwnerElement ()) {
2871 LocalFrame* newHoverFrame = nullptr;
2872 // If we can't get the frame from the new hover frame chain,
2873 // the newHoverFrame will be null and the old hover state will be cl eared.
2874 if (indexFrameChain > 0)
2875 newHoverFrame = newHoverFrameChain[--indexFrameChain];
2876
2877 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(oldHoverNodeI nCurDoc.get());
2878 if (!owner->contentFrame() || !owner->contentFrame()->isLocalFrame() )
2879 break;
2880
2881 LocalFrame* oldHoverFrame = toLocalFrame(owner->contentFrame());
2882 Document* doc = oldHoverFrame->document();
2883 if (!doc)
2884 break;
2885
2886 oldHoverNodeInCurDoc = doc->hoverNode();
2887 // If the old hovered frame is different from the new hovered frame.
2888 // we should clear the old hovered node from the old hovered frame.
2889 if (newHoverFrame != oldHoverFrame)
2890 doc->updateHoverActiveState(request, nullptr);
2891 }
2892 }
2893
2894 // Recursively set the new active/hover states on every frame in the chain o f innerElement.
2895 m_frame->document()->updateHoverActiveState(request, innerElement);
2896 }
2897
2898 GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGe stureEvent& gestureEvent, bool readOnly)
2899 {
2900 TRACE_EVENT0("input", "EventHandler::targetGestureEvent");
2901
2902 ASSERT(m_frame == m_frame->localFrameRoot());
2903 // Scrolling events get hit tested per frame (like wheel events do).
2904 ASSERT(!gestureEvent.isScrollEvent());
2905
2906 HitTestRequest::HitTestRequestType hitType = getHitTypeForGestureType(gestur eEvent.type());
2907 double activeInterval = 0;
2908 bool shouldKeepActiveForMinInterval = false;
2909 if (readOnly) {
2910 hitType |= HitTestRequest::ReadOnly;
2911 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2912 // If the Tap is received very shortly after ShowPress, we want to
2913 // delay clearing of the active state so that it's visible to the user
2914 // for at least a couple of frames.
2915 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2916 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInter val < minimumActiveInterval;
2917 if (shouldKeepActiveForMinInterval)
2918 hitType |= HitTestRequest::ReadOnly;
2919 }
2920
2921 GestureEventWithHitTestResults eventWithHitTestResults = hitTestResultForGes tureEvent(gestureEvent, hitType);
2922 // Now apply hover/active state to the final target.
2923 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
2924 if (!request.readOnly())
2925 updateGestureHoverActiveState(request, eventWithHitTestResults.hitTestRe sult().innerElement());
2926
2927 if (shouldKeepActiveForMinInterval) {
2928 m_lastDeferredTapElement = eventWithHitTestResults.hitTestResult().inner Element();
2929 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterva l, FROM_HERE);
2930 }
2931
2932 return eventWithHitTestResults;
2933 }
2934
2935 GestureEventWithHitTestResults EventHandler::hitTestResultForGestureEvent(const PlatformGestureEvent& gestureEvent, HitTestRequest::HitTestRequestType hitType)
2936 {
2937 // Perform the rect-based hit-test (or point-based if adjustment is disabled ). Note that
2938 // we don't yet apply hover/active state here because we need to resolve tou ch adjustment
2939 // first so that we apply hover/active it to the final adjusted node.
2940 IntPoint hitTestPoint = m_frame->view()->rootFrameToContents(gestureEvent.po sition());
2941 LayoutSize padding;
2942 if (shouldApplyTouchAdjustment(gestureEvent)) {
2943 padding = LayoutSize(gestureEvent.area());
2944 if (!padding.isEmpty()) {
2945 padding.scale(1.f / 2);
2946 hitType |= HitTestRequest::ListBased;
2947 }
2948 }
2949 HitTestResult hitTestResult = hitTestResultAtPoint(hitTestPoint, hitType | H itTestRequest::ReadOnly, padding);
2950
2951 // Adjust the location of the gesture to the most likely nearby node, as app ropriate for the
2952 // type of event.
2953 PlatformGestureEvent adjustedEvent = gestureEvent;
2954 applyTouchAdjustment(&adjustedEvent, &hitTestResult);
2955
2956 // Do a new hit-test at the (adjusted) gesture co-ordinates. This is necessa ry because
2957 // rect-based hit testing and touch adjustment sometimes return a different node than
2958 // what a point-based hit test would return for the same point.
2959 // FIXME: Fix touch adjustment to avoid the need for a redundant hit test. h ttp://crbug.com/398914
2960 if (shouldApplyTouchAdjustment(gestureEvent)) {
2961 LocalFrame* hitFrame = hitTestResult.innerNodeFrame();
2962 if (!hitFrame)
2963 hitFrame = m_frame;
2964 hitTestResult = hitTestResultInFrame(hitFrame, hitFrame->view()->rootFra meToContents(adjustedEvent.position()), (hitType | HitTestRequest::ReadOnly) & ~ HitTestRequest::ListBased);
2965 }
2966
2967 // If we did a rect-based hit test it must be resolved to the best single no de by now to
2968 // ensure consumers don't accidentally use one of the other candidates.
2969 ASSERT(!hitTestResult.isRectBasedTest());
2970
2971 return GestureEventWithHitTestResults(adjustedEvent, hitTestResult);
2972 }
2973
2974 HitTestRequest::HitTestRequestType EventHandler::getHitTypeForGestureType(Platfo rmEvent::Type type)
2975 {
2976 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2977 switch (type) {
2978 case PlatformEvent::GestureShowPress:
2979 case PlatformEvent::GestureTapUnconfirmed:
2980 return hitType | HitTestRequest::Active;
2981 case PlatformEvent::GestureTapDownCancel:
2982 // A TapDownCancel received when no element is active shouldn't really b e changing hover state.
2983 if (!m_frame->document()->activeHoverElement())
2984 hitType |= HitTestRequest::ReadOnly;
2985 return hitType | HitTestRequest::Release;
2986 case PlatformEvent::GestureTap:
2987 return hitType | HitTestRequest::Release;
2988 case PlatformEvent::GestureTapDown:
2989 case PlatformEvent::GestureLongPress:
2990 case PlatformEvent::GestureLongTap:
2991 case PlatformEvent::GestureTwoFingerTap:
2992 // FIXME: Shouldn't LongTap and TwoFingerTap clear the Active state?
2993 return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
2994 default:
2995 ASSERT_NOT_REACHED();
2996 return hitType | HitTestRequest::Active | HitTestRequest::ReadOnly;
2997 }
2998 }
2999
3000 void EventHandler::applyTouchAdjustment(PlatformGestureEvent* gestureEvent, HitT estResult* hitTestResult)
3001 {
3002 if (!shouldApplyTouchAdjustment(*gestureEvent))
3003 return;
3004
3005 Node* adjustedNode = nullptr;
3006 IntPoint adjustedPoint = gestureEvent->position();
3007 bool adjusted = false;
3008 switch (gestureEvent->type()) {
3009 case PlatformEvent::GestureTap:
3010 case PlatformEvent::GestureTapUnconfirmed:
3011 case PlatformEvent::GestureTapDown:
3012 case PlatformEvent::GestureShowPress:
3013 adjusted = bestClickableNodeForHitTestResult(*hitTestResult, adjustedPoi nt, adjustedNode);
3014 break;
3015 case PlatformEvent::GestureLongPress:
3016 case PlatformEvent::GestureLongTap:
3017 case PlatformEvent::GestureTwoFingerTap:
3018 adjusted = bestContextMenuNodeForHitTestResult(*hitTestResult, adjustedP oint, adjustedNode);
3019 break;
3020 default:
3021 ASSERT_NOT_REACHED();
3022 }
3023
3024 // Update the hit-test result to be a point-based result instead of a rect-b ased result.
3025 // FIXME: We should do this even when no candidate matches the node filter. crbug.com/398914
3026 if (adjusted) {
3027 hitTestResult->resolveRectBasedTest(adjustedNode, m_frame->view()->rootF rameToContents(adjustedPoint));
3028 gestureEvent->applyTouchAdjustment(adjustedPoint);
3029 }
3030 }
3031
3032 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event, Node* o verrideTargetNode)
3033 {
3034 FrameView* v = m_frame->view();
3035 if (!v)
3036 return false;
3037
3038 // Clear mouse press state to avoid initiating a drag while context menu is up.
3039 m_mousePressed = false;
3040 LayoutPoint positionInContents = v->rootFrameToContents(event.position());
3041 HitTestRequest request(HitTestRequest::Active);
3042 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(re quest, positionInContents, event);
3043
3044 if (!m_frame->selection().contains(positionInContents)
3045 && !mev.scrollbar() 517 && !mev.scrollbar()
3046 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. 518 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
3047 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items 519 // If the selection is non-editable, we do word selection to make it eas ier to use the contextual menu items
3048 // available for text selections. But only if we're above text. 520 // available for text selections. But only if we're above text.
3049 && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev. innerNode()->isTextNode()))) { 521 && (m_frame->selection().isContentEditable() || (mev.innerNode() && mev. innerNode()->isTextNode()))) {
3050 m_mouseDownMayStartSelect = true; // context menu events are always allo wed to perform a selection 522 m_mouseDownMayStartSelect = true; // context menu events are always allo wed to perform a selection
3051 523
3052 if (mev.hitTestResult().isMisspelled()) 524 if (mev.hitTestResult().isMisspelled())
3053 selectClosestMisspellingFromMouseEvent(mev); 525 selectClosestMisspellingFromMouseEvent(mev);
3054 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick( )) 526 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick( ))
3055 selectClosestWordOrLinkFromMouseEvent(mev); 527 selectClosestWordOrLinkFromMouseEvent(mev);
3056 } 528 }
3057
3058 Node* targetNode = overrideTargetNode ? overrideTargetNode : mev.innerNode() ;
3059 return !dispatchMouseEvent(EventTypeNames::contextmenu, targetNode, 0, event , false);
3060 } 529 }
3061 530
3062 bool EventHandler::sendContextMenuEventForKey(Element* overrideTargetElement) 531 void SelectionController::passMousePressEventToSubframe(const MouseEventWithHitT estResults& mev)
3063 {
3064 FrameView* view = m_frame->view();
3065 if (!view)
3066 return false;
3067
3068 Document* doc = m_frame->document();
3069 if (!doc)
3070 return false;
3071
3072 // Clear mouse press state to avoid initiating a drag while context menu is up.
3073 m_mousePressed = false;
3074
3075 static const int kContextMenuMargin = 1;
3076
3077 #if OS(WIN)
3078 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
3079 #else
3080 int rightAligned = 0;
3081 #endif
3082 IntPoint locationInRootFrame;
3083
3084 Element* focusedElement = overrideTargetElement ? overrideTargetElement : do c->focusedElement();
3085 FrameSelection& selection = m_frame->selection();
3086 Position start = selection.selection().start();
3087 PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport();
3088
3089 if (!overrideTargetElement && start.deprecatedNode() && (selection.rootEdita bleElement() || selection.isRange())) {
3090 RefPtrWillBeRawPtr<Range> selectionRange = selection.toNormalizedRange() ;
3091 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.g et());
3092
3093 int x = rightAligned ? firstRect.maxX() : firstRect.x();
3094 // In a multiline edit, firstRect.maxY() would endup on the next line, s o -1.
3095 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
3096 locationInRootFrame = view->contentsToRootFrame(IntPoint(x, y));
3097 } else if (focusedElement) {
3098 IntRect clippedRect = focusedElement->boundsInViewportSpace();
3099 // FIXME: boundsInViewportSpace is actually in the weird scaled but untr anslated coordinate space of
3100 // the old-style pinch viewport. crbug.com/459591.
3101 locationInRootFrame = flooredIntPoint(pinchViewport.viewportCSSPixelsToR ootFrame(clippedRect.center()));
3102 } else {
3103 locationInRootFrame = IntPoint(
3104 rightAligned
3105 ? pinchViewport.visibleRect().maxX() - kContextMenuMargin
3106 : pinchViewport.location().x() + kContextMenuMargin,
3107 pinchViewport.location().y() + kContextMenuMargin);
3108 }
3109
3110 m_frame->view()->setCursor(pointerCursor());
3111 IntPoint locationInViewport = pinchViewport.rootFrameToViewport(locationInRo otFrame);
3112 IntPoint globalPosition = view->hostWindow()->viewportToScreen(IntRect(locat ionInViewport, IntSize())).location();
3113
3114 Node* targetNode = overrideTargetElement ? overrideTargetElement : doc->focu sedElement();
3115 if (!targetNode)
3116 targetNode = doc;
3117
3118 // Use the focused node as the target for hover and active.
3119 HitTestRequest request(HitTestRequest::Active);
3120 HitTestResult result(request, locationInRootFrame);
3121 result.setInnerNode(targetNode);
3122 doc->updateHoverActiveState(request, result.innerElement());
3123
3124 // The contextmenu event is a mouse event even when invoked using the keyboa rd.
3125 // This is required for web compatibility.
3126 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
3127 if (m_frame->settings()->showContextMenuOnMouseUp())
3128 eventType = PlatformEvent::MouseReleased;
3129
3130 PlatformMouseEvent mouseEvent(locationInRootFrame, globalPosition, RightButt on, eventType, 1, false, false, false, false, PlatformMouseEvent::RealOrIndistin guishable, WTF::currentTime());
3131
3132 handleMousePressEvent(mouseEvent);
3133 return sendContextMenuEvent(mouseEvent, overrideTargetElement);
3134 }
3135
3136 bool EventHandler::sendContextMenuEventForGesture(const GestureEventWithHitTestR esults& targetedEvent)
3137 {
3138 const PlatformGestureEvent& gestureEvent = targetedEvent.event();
3139 unsigned modifiers = gestureEvent.modifiers();
3140
3141 // Send MouseMoved event prior to handling (https://crbug.com/485290).
3142 PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globa lPosition(),
3143 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
3144 static_cast<PlatformEvent::Modifiers>(modifiers),
3145 PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
3146 dispatchMouseEvent(EventTypeNames::mousemove, targetedEvent.hitTestResult(). innerNode(), 0, fakeMouseMove, true);
3147
3148 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
3149
3150 if (m_frame->settings()->showContextMenuOnMouseUp())
3151 eventType = PlatformEvent::MouseReleased;
3152 else
3153 modifiers |= PlatformEvent::RightButtonDown;
3154
3155 PlatformMouseEvent mouseEvent(targetedEvent.event().position(), targetedEven t.event().globalPosition(), RightButton, eventType, 1,
3156 static_cast<PlatformEvent::Modifiers>(modifiers),
3157 PlatformMouseEvent::FromTouch, WTF::currentTime());
3158 // To simulate right-click behavior, we send a right mouse down and then
3159 // context menu event.
3160 // FIXME: Send HitTestResults to avoid redundant hit tests.
3161 handleMousePressEvent(mouseEvent);
3162 return sendContextMenuEvent(mouseEvent);
3163 // We do not need to send a corresponding mouse release because in case of
3164 // right-click, the context menu takes capture and consumes all events.
3165 }
3166
3167 void EventHandler::scheduleHoverStateUpdate()
3168 {
3169 if (!m_hoverTimer.isActive())
3170 m_hoverTimer.startOneShot(0, FROM_HERE);
3171 }
3172
3173 void EventHandler::scheduleCursorUpdate()
3174 {
3175 // We only want one timer for the page, rather than each frame having it's o wn timer
3176 // competing which eachother (since there's only one mouse cursor).
3177 ASSERT(m_frame == m_frame->localFrameRoot());
3178
3179 if (!m_cursorUpdateTimer.isActive())
3180 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
3181 }
3182
3183 bool EventHandler::cursorUpdatePending()
3184 {
3185 return m_cursorUpdateTimer.isActive();
3186 }
3187
3188 void EventHandler::dispatchFakeMouseMoveEventSoon()
3189 {
3190 if (m_mousePressed)
3191 return;
3192
3193 if (m_mousePositionIsUnknown)
3194 return;
3195
3196 Settings* settings = m_frame->settings();
3197 if (settings && !settings->deviceSupportsMouse())
3198 return;
3199
3200 // If the content has ever taken longer than fakeMouseMoveShortInterval we
3201 // reschedule the timer and use a longer time. This will cause the content
3202 // to receive these moves only after the user is done scrolling, reducing
3203 // pauses during the scroll.
3204 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
3205 if (m_fakeMouseMoveEventTimer.isActive())
3206 m_fakeMouseMoveEventTimer.stop();
3207 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_H ERE);
3208 } else {
3209 if (!m_fakeMouseMoveEventTimer.isActive())
3210 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, F ROM_HERE);
3211 }
3212 }
3213
3214 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
3215 {
3216 FrameView* view = m_frame->view();
3217 if (!view)
3218 return;
3219
3220 if (!quad.containsPoint(view->rootFrameToContents(m_lastKnownMousePosition)) )
3221 return;
3222
3223 dispatchFakeMouseMoveEventSoon();
3224 }
3225
3226 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
3227 {
3228 TRACE_EVENT0("input", "EventHandler::fakeMouseMoveEventTimerFired");
3229 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
3230 ASSERT(!m_mousePressed);
3231
3232 Settings* settings = m_frame->settings();
3233 if (settings && !settings->deviceSupportsMouse())
3234 return;
3235
3236 FrameView* view = m_frame->view();
3237 if (!view)
3238 return;
3239
3240 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
3241 return;
3242
3243 // Don't dispatch a synthetic mouse move event if the mouse cursor is not vi sible to the user.
3244 if (!isCursorVisible())
3245 return;
3246
3247 bool shiftKey;
3248 bool ctrlKey;
3249 bool altKey;
3250 bool metaKey;
3251 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, me taKey);
3252 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownM ouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, a ltKey, metaKey, PlatformMouseEvent::RealOrIndistinguishable, currentTime());
3253 handleMouseMoveEvent(fakeMouseMoveEvent);
3254 }
3255
3256 void EventHandler::cancelFakeMouseMoveEvent()
3257 {
3258 m_fakeMouseMoveEventTimer.stop();
3259 }
3260
3261 bool EventHandler::isCursorVisible() const
3262 {
3263 return m_frame->page()->isCursorVisible();
3264 }
3265
3266 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
3267 {
3268 m_frameSetBeingResized = frameSet;
3269 }
3270
3271 void EventHandler::resizeScrollableAreaDestroyed()
3272 {
3273 ASSERT(m_resizeScrollableArea);
3274 m_resizeScrollableArea = nullptr;
3275 }
3276
3277 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
3278 {
3279 TRACE_EVENT0("input", "EventHandler::hoverTimerFired");
3280 m_hoverTimer.stop();
3281
3282 ASSERT(m_frame);
3283 ASSERT(m_frame->document());
3284
3285 if (LayoutView* layoutObject = m_frame->contentLayoutObject()) {
3286 if (FrameView* view = m_frame->view()) {
3287 HitTestRequest request(HitTestRequest::Move);
3288 HitTestResult result(request, view->rootFrameToContents(m_lastKnownM ousePosition));
3289 layoutObject->hitTest(result);
3290 m_frame->document()->updateHoverActiveState(request, result.innerEle ment());
3291 }
3292 }
3293 }
3294
3295 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
3296 {
3297 TRACE_EVENT0("input", "EventHandler::activeIntervalTimerFired");
3298 m_activeIntervalTimer.stop();
3299
3300 if (m_frame
3301 && m_frame->document()
3302 && m_lastDeferredTapElement) {
3303 // FIXME: Enable condition when http://crbug.com/226842 lands
3304 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement( )
3305 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Rele ase);
3306 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapEl ement.get());
3307 }
3308 m_lastDeferredTapElement = nullptr;
3309 }
3310
3311 void EventHandler::notifyElementActivated()
3312 {
3313 // Since another element has been set to active, stop current timer and clea r reference.
3314 if (m_activeIntervalTimer.isActive())
3315 m_activeIntervalTimer.stop();
3316 m_lastDeferredTapElement = nullptr;
3317 }
3318
3319 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
3320 {
3321 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
3322 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
3323 // lower case variants are present in a document, the correct element is mat ched based on Shift key state.
3324 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
3325 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
3326 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
3327 return false;
3328 String key = evt.unmodifiedText();
3329 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
3330 if (!elem)
3331 return false;
3332 elem->accessKeyAction(false);
3333 return true;
3334 }
3335
3336 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
3337 {
3338 RefPtrWillBeRawPtr<FrameView> protector(m_frame->view());
3339
3340 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
3341 capsLockStateMayHaveChanged();
3342
3343 #if OS(WIN)
3344 if (panScrollInProgress()) {
3345 // If a key is pressed while the panScroll is in progress then we want t o stop
3346 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent. type() == PlatformEvent::RawKeyDown)
3347 stopAutoscroll();
3348
3349 // If we were in panscroll mode, we swallow the key event
3350 return true;
3351 }
3352 #endif
3353
3354 // Check for cases where we are too early for events -- possible unmatched k ey up
3355 // from pressing return in the location bar.
3356 RefPtrWillBeRawPtr<Node> node = eventTargetNodeForDocument(m_frame->document ());
3357 if (!node)
3358 return false;
3359
3360 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3361
3362 // In IE, access keys are special, they are handled after default keydown pr ocessing, but cannot be canceled - this is hard to match.
3363 // On Mac OS X, we process them before dispatching keydown, as the default k eydown handler implements Emacs key bindings, which may conflict
3364 // with access keys. Then we dispatch keydown, but suppress its default hand ling.
3365 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatch ing a keypress event for WM_SYSCHAR messages.
3366 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
3367 bool matchedAnAccessKey = false;
3368 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
3369 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
3370
3371 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
3372 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
3373 return !node->dispatchKeyEvent(initialKeyEvent);
3374
3375 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
3376 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
3377 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
3378 RefPtrWillBeRawPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEve nt, m_frame->document()->domWindow());
3379 if (matchedAnAccessKey)
3380 keydown->setDefaultPrevented(true);
3381 keydown->setTarget(node);
3382
3383 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
3384 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3385 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
3386 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page() ->focusController().focusedOrMainFrame();
3387 return keydown->defaultHandled() || keydown->defaultPrevented() || chang edFocusedFrame;
3388 }
3389
3390 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
3391 // If frame changed as a result of keydown dispatch, then return early to av oid sending a subsequent keypress message to the new frame.
3392 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->fo cusController().focusedOrMainFrame();
3393 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented( ) || changedFocusedFrame;
3394 if (keydownResult)
3395 return keydownResult;
3396
3397 // Focus may have changed during keydown handling, so refetch node.
3398 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
3399 node = eventTargetNodeForDocument(m_frame->document());
3400 if (!node)
3401 return false;
3402
3403 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
3404 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
3405 if (keyPressEvent.text().isEmpty())
3406 return keydownResult;
3407 RefPtrWillBeRawPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressE vent, m_frame->document()->domWindow());
3408 keypress->setTarget(node);
3409 if (keydownResult)
3410 keypress->setDefaultPrevented(true);
3411 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
3412
3413 return keydownResult || keypress->defaultPrevented() || keypress->defaultHan dled();
3414 }
3415
3416 static WebFocusType focusDirectionForKey(const AtomicString& keyIdentifier)
3417 {
3418 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFrom Literal));
3419 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLite ral));
3420 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFrom Literal));
3421 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFr omLiteral));
3422
3423 WebFocusType retVal = WebFocusTypeNone;
3424
3425 if (keyIdentifier == Down)
3426 retVal = WebFocusTypeDown;
3427 else if (keyIdentifier == Up)
3428 retVal = WebFocusTypeUp;
3429 else if (keyIdentifier == Left)
3430 retVal = WebFocusTypeLeft;
3431 else if (keyIdentifier == Right)
3432 retVal = WebFocusTypeRight;
3433
3434 return retVal;
3435 }
3436
3437 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
3438 {
3439 if (event->type() == EventTypeNames::keydown) {
3440 // Clear caret blinking suspended state to make sure that caret blinks
3441 // when we type again after long pressing on an empty input field.
3442 if (m_frame && m_frame->selection().isCaretBlinkingSuspended())
3443 m_frame->selection().setCaretBlinkingSuspended(false);
3444
3445 m_frame->editor().handleKeyboardEvent(event);
3446 if (event->defaultHandled())
3447 return;
3448 if (event->keyIdentifier() == "U+0009") {
3449 defaultTabEventHandler(event);
3450 } else if (event->keyIdentifier() == "U+0008") {
3451 defaultBackspaceEventHandler(event);
3452 } else if (event->keyIdentifier() == "U+001B") {
3453 defaultEscapeEventHandler(event);
3454 } else {
3455 WebFocusType type = focusDirectionForKey(AtomicString(event->keyIden tifier()));
3456 if (type != WebFocusTypeNone)
3457 defaultArrowEventHandler(type, event);
3458 }
3459 }
3460 if (event->type() == EventTypeNames::keypress) {
3461 m_frame->editor().handleKeyboardEvent(event);
3462 if (event->defaultHandled())
3463 return;
3464 if (event->charCode() == ' ')
3465 defaultSpaceEventHandler(event);
3466 }
3467 }
3468
3469 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragLocationInRootFram e) const
3470 {
3471 FrameView* view = m_frame->view();
3472 if (!view)
3473 return false;
3474 IntPoint dragLocation = view->rootFrameToContents(dragLocationInRootFrame);
3475 IntSize delta = dragLocation - m_mouseDownPos;
3476
3477 int threshold = GeneralDragHysteresis;
3478 switch (dragState().m_dragType) {
3479 case DragSourceActionSelection:
3480 threshold = TextDragHysteresis;
3481 break;
3482 case DragSourceActionImage:
3483 threshold = ImageDragHysteresis;
3484 break;
3485 case DragSourceActionLink:
3486 threshold = LinkDragHysteresis;
3487 break;
3488 case DragSourceActionDHTML:
3489 break;
3490 case DragSourceActionNone:
3491 ASSERT_NOT_REACHED();
3492 }
3493
3494 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3495 }
3496
3497 void EventHandler::clearDragDataTransfer()
3498 {
3499 if (dragState().m_dragDataTransfer) {
3500 dragState().m_dragDataTransfer->clearDragImage();
3501 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferNumb);
3502 }
3503 }
3504
3505 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperat ion operation)
3506 {
3507 // Send a hit test request so that Layer gets a chance to update the :hover and :active pseudoclasses.
3508 HitTestRequest request(HitTestRequest::Release);
3509 prepareMouseEvent(request, event);
3510
3511 if (dragState().m_dragSrc) {
3512 dragState().m_dragDataTransfer->setDestinationOperation(operation);
3513 // for now we don't care if event handler cancels default behavior, sinc e there is none
3514 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3515 }
3516 clearDragDataTransfer();
3517 dragState().m_dragSrc = nullptr;
3518 // In case the drag was ended due to an escape key press we need to ensure
3519 // that consecutive mousemove events don't reinitiate the drag and drop.
3520 m_mouseDownMayStartDrag = false;
3521 }
3522
3523 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableEle ment)
3524 {
3525 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3526 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3527 dragState().m_dragSrc = rootEditableElement;
3528 }
3529
3530 // returns if we should continue "default processing", i.e., whether eventhandle r canceled
3531 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const Pla tformMouseEvent& event)
3532 {
3533 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dra gState().m_dragDataTransfer.get());
3534 }
3535
3536 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, DragIni tiator initiator)
3537 {
3538 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3539 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3540 // events, causing page/FrameView to go away.
3541 ASSERT(m_frame);
3542 ASSERT(m_frame->view());
3543 if (!m_frame->page())
3544 return false;
3545
3546 if (m_mouseDownMayStartDrag) {
3547 HitTestRequest request(HitTestRequest::ReadOnly);
3548 HitTestResult result(request, m_mouseDownPos);
3549 m_frame->contentLayoutObject()->hitTest(result);
3550 Node* node = result.innerNode();
3551 if (node) {
3552 DragController::SelectionDragPolicy selectionDragPolicy = event.even t().timestamp() - m_mouseDownTimestamp < TextDragDelay
3553 ? DragController::DelayedSelectionDragResolution
3554 : DragController::ImmediateSelectionDragResolution;
3555 dragState().m_dragSrc = m_frame->page()->dragController().draggableN ode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3556 } else {
3557 dragState().m_dragSrc = nullptr;
3558 }
3559
3560 if (!dragState().m_dragSrc)
3561 m_mouseDownMayStartDrag = false; // no element is draggable
3562 }
3563
3564 if (!m_mouseDownMayStartDrag)
3565 return initiator == DragInitiator::Mouse && !mouseDownMayStartSelect() & & !m_mouseDownMayStartAutoscroll;
3566
3567 // We are starting a text/image/url drag, so the cursor should be an arrow
3568 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and d rop (default to pointer).
3569 m_frame->view()->setCursor(pointerCursor());
3570
3571 if (initiator == DragInitiator::Mouse && !dragHysteresisExceeded(event.event ().position()))
3572 return true;
3573
3574 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3575 invalidateClick();
3576
3577 if (!tryStartDrag(event)) {
3578 // Something failed to start the drag, clean up.
3579 clearDragDataTransfer();
3580 dragState().m_dragSrc = nullptr;
3581 }
3582
3583 m_mouseDownMayStartDrag = false;
3584 // Whether or not the drag actually started, no more default handling (like selection).
3585 return true;
3586 }
3587
3588 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3589 {
3590 // The DataTransfer would only be non-empty if we missed a dragEnd.
3591 // Clear it anyway, just to make sure it gets numbified.
3592 clearDragDataTransfer();
3593
3594 dragState().m_dragDataTransfer = createDraggingDataTransfer();
3595
3596 // Check to see if this a DOM based drag, if it is get the DOM specified dra g
3597 // image and offset
3598 if (dragState().m_dragType == DragSourceActionDHTML) {
3599 if (LayoutObject* layoutObject = dragState().m_dragSrc->layoutObject()) {
3600 FloatPoint absPos = layoutObject->localToAbsolute(FloatPoint(), UseT ransforms);
3601 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3602 dragState().m_dragDataTransfer->setDragImageElement(dragState().m_dr agSrc.get(), IntPoint(delta));
3603 } else {
3604 // The layoutObject has disappeared, this can happen if the onStartD rag handler has hidden
3605 // the element in some way. In this case we just kill the drag.
3606 return false;
3607 }
3608 }
3609
3610 DragController& dragController = m_frame->page()->dragController();
3611 if (!dragController.populateDragDataTransfer(m_frame, dragState(), m_mouseDo wnPos))
3612 return false;
3613
3614 // If dispatching dragstart brings about another mouse down -- one way
3615 // this will happen is if a DevTools user breaks within a dragstart
3616 // handler and then clicks on the suspended page -- the drag state is
3617 // reset. Hence, need to check if this particular drag operation can
3618 // continue even if dispatchEvent() indicates no (direct) cancellation.
3619 // Do that by checking if m_dragSrc is still set.
3620 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_ mouseDown)
3621 && !m_frame->selection().isInPasswordField() && dragState().m_dragSrc;
3622
3623 // Invalidate clipboard here against anymore pasteboard writing for security . The drag
3624 // image can still be changed as we drag, but not the pasteboard data.
3625 dragState().m_dragDataTransfer->setAccessPolicy(DataTransferImageWritable);
3626
3627 if (m_mouseDownMayStartDrag) {
3628 // Dispatching the event could cause Page to go away. Make sure it's sti ll valid before trying to use DragController.
3629 if (m_frame->page() && dragController.startDrag(m_frame, dragState(), ev ent.event(), m_mouseDownPos))
3630 return true;
3631 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3632 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3633 }
3634
3635 return false;
3636 }
3637
3638 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve nt, TextEventInputType inputType)
3639 {
3640 // Platforms should differentiate real commands like selectAll from text inp ut in disguise (like insertNewline),
3641 // and avoid dispatching text input events from keydown default handlers.
3642 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboard Event(underlyingEvent)->type() == EventTypeNames::keypress);
3643
3644 if (!m_frame)
3645 return false;
3646
3647 EventTarget* target;
3648 if (underlyingEvent)
3649 target = underlyingEvent->target();
3650 else
3651 target = eventTargetNodeForDocument(m_frame->document());
3652 if (!target)
3653 return false;
3654
3655 RefPtrWillBeRawPtr<TextEvent> event = TextEvent::create(m_frame->domWindow() , text, inputType);
3656 event->setUnderlyingEvent(underlyingEvent);
3657
3658 target->dispatchEvent(event, IGNORE_EXCEPTION);
3659 return event->defaultHandled();
3660 }
3661
3662 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3663 {
3664 if (m_frame->editor().handleTextEvent(event))
3665 event->setDefaultHandled();
3666 }
3667
3668 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3669 {
3670 ASSERT(event->type() == EventTypeNames::keypress);
3671
3672 if (event->ctrlKey() || event->metaKey() || event->altKey())
3673 return;
3674
3675 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3676
3677 // FIXME: enable scroll customization in this case. See crbug.com/410974.
3678 if (scroll(direction, ScrollByPage).didScroll) {
3679 event->setDefaultHandled();
3680 return;
3681 }
3682
3683 FrameView* view = m_frame->view();
3684 if (!view)
3685 return;
3686
3687 ScrollDirectionPhysical physicalDirection =
3688 toPhysicalDirection(direction, view->isVerticalDocument(), view->isFlipp edDocument());
3689
3690 if (view->scrollableArea()->userScroll(physicalDirection, ScrollByPage).didS croll)
3691 event->setDefaultHandled();
3692 }
3693
3694 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3695 {
3696 ASSERT(event->type() == EventTypeNames::keydown);
3697
3698 if (event->ctrlKey() || event->metaKey() || event->altKey())
3699 return;
3700
3701 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3702 return;
3703 bool handledEvent = m_frame->loader().client()->navigateBackForward(event->s hiftKey() ? 1 : -1);
3704 if (handledEvent)
3705 event->setDefaultHandled();
3706 }
3707
3708 void EventHandler::defaultArrowEventHandler(WebFocusType focusType, KeyboardEven t* event)
3709 {
3710 ASSERT(event->type() == EventTypeNames::keydown);
3711
3712 if (event->ctrlKey() || event->metaKey() || event->shiftKey())
3713 return;
3714
3715 Page* page = m_frame->page();
3716 if (!page)
3717 return;
3718
3719 if (!isSpatialNavigationEnabled(m_frame))
3720 return;
3721
3722 // Arrows and other possible directional navigation keys can be used in desi gn
3723 // mode editing.
3724 if (m_frame->document()->inDesignMode())
3725 return;
3726
3727 if (page->focusController().advanceFocus(focusType))
3728 event->setDefaultHandled();
3729 }
3730
3731 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3732 {
3733 ASSERT(event->type() == EventTypeNames::keydown);
3734
3735 // We should only advance focus on tabs if no special modifier keys are held down.
3736 if (event->ctrlKey() || event->metaKey())
3737 return;
3738
3739 #if !OS(MACOSX)
3740 // Option-Tab is a shortcut based on a system-wide preference on Mac but
3741 // should be ignored on all other platforms.
3742 if (event->altKey())
3743 return;
3744 #endif
3745
3746 Page* page = m_frame->page();
3747 if (!page)
3748 return;
3749 if (!page->tabKeyCyclesThroughElements())
3750 return;
3751
3752 WebFocusType focusType = event->shiftKey() ? WebFocusTypeBackward : WebFocus TypeForward;
3753
3754 // Tabs can be used in design mode editing.
3755 if (m_frame->document()->inDesignMode())
3756 return;
3757
3758 if (page->focusController().advanceFocus(focusType))
3759 event->setDefaultHandled();
3760 }
3761
3762 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3763 {
3764 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3765 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3766 }
3767
3768 void EventHandler::capsLockStateMayHaveChanged()
3769 {
3770 if (Element* element = m_frame->document()->focusedElement()) {
3771 if (LayoutObject* r = element->layoutObject()) {
3772 if (r->isTextField())
3773 toLayoutTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3774 }
3775 }
3776 }
3777
3778 void EventHandler::setFrameWasScrolledByUser()
3779 {
3780 if (FrameView* view = m_frame->view())
3781 view->setWasScrolledByUser(true);
3782 }
3783
3784 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev)
3785 {
3786 Scrollbar* scrollbar = mev.scrollbar();
3787 updateLastScrollbarUnderMouse(scrollbar, true);
3788
3789 if (!scrollbar || !scrollbar->enabled())
3790 return false;
3791 setFrameWasScrolledByUser();
3792 scrollbar->mouseDown(mev.event());
3793 return true;
3794 }
3795
3796 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3797 // last to scrollbar if setLast is true; else set last to 0.
3798 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setL ast)
3799 {
3800 if (m_lastScrollbarUnderMouse != scrollbar) {
3801 // Send mouse exited to the old scrollbar.
3802 if (m_lastScrollbarUnderMouse)
3803 m_lastScrollbarUnderMouse->mouseExited();
3804
3805 // Send mouse entered if we're setting a new scrollbar.
3806 if (scrollbar && setLast)
3807 scrollbar->mouseEntered();
3808
3809 m_lastScrollbarUnderMouse = setLast ? scrollbar : nullptr;
3810 }
3811 }
3812
3813 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3814 {
3815 switch (state) {
3816 case PlatformTouchPoint::TouchReleased:
3817 return EventTypeNames::touchend;
3818 case PlatformTouchPoint::TouchCancelled:
3819 return EventTypeNames::touchcancel;
3820 case PlatformTouchPoint::TouchPressed:
3821 return EventTypeNames::touchstart;
3822 case PlatformTouchPoint::TouchMoved:
3823 return EventTypeNames::touchmove;
3824 case PlatformTouchPoint::TouchStationary:
3825 // TouchStationary state is not converted to touch events, so fall throu gh to assert.
3826 default:
3827 ASSERT_NOT_REACHED();
3828 return emptyAtom;
3829 }
3830 }
3831
3832 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const Layout Point& point, HitTestRequest::HitTestRequestType hitType)
3833 {
3834 HitTestResult result(HitTestRequest(hitType), point);
3835
3836 if (!frame || !frame->contentLayoutObject())
3837 return result;
3838 if (frame->view()) {
3839 IntRect rect = frame->view()->visibleContentRect(IncludeScrollbars);
3840 if (!rect.contains(roundedIntPoint(point)))
3841 return result;
3842 }
3843 frame->contentLayoutObject()->hitTest(result);
3844 return result;
3845 }
3846
3847 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3848 {
3849 TRACE_EVENT0("blink", "EventHandler::handleTouchEvent");
3850
3851 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3852
3853 unsigned i;
3854 bool freshTouchEvents = true;
3855 bool allTouchReleased = true;
3856 for (i = 0; i < points.size(); ++i) {
3857 const PlatformTouchPoint& point = points[i];
3858 if (point.state() != PlatformTouchPoint::TouchPressed)
3859 freshTouchEvents = false;
3860 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3861 allTouchReleased = false;
3862 }
3863 if (freshTouchEvents) {
3864 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3865 // have cleared the active document when we saw the last release. But we
3866 // have some tests that violate this, ClusterFuzz could trigger it, and
3867 // there may be cases where the browser doesn't reliably release all
3868 // touches. http://crbug.com/345372 tracks this.
3869 m_touchSequenceDocument.clear();
3870 m_touchSequenceUserGestureToken.clear();
3871 }
3872
3873 OwnPtr<UserGestureIndicator> gestureIndicator;
3874
3875 if (m_touchSequenceUserGestureToken)
3876 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequenceUser GestureToken.release()));
3877 else
3878 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessin gUserGesture));
3879
3880 m_touchSequenceUserGestureToken = gestureIndicator->currentToken();
3881
3882 ASSERT(m_frame->view());
3883 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) {
3884 // If the active touch document has no frame or view, it's probably bein g destroyed
3885 // so we can't dispatch events.
3886 return false;
3887 }
3888
3889 // First do hit tests for any new touch points.
3890 for (i = 0; i < points.size(); ++i) {
3891 const PlatformTouchPoint& point = points[i];
3892
3893 // Touch events implicitly capture to the touched node, and don't change
3894 // active/hover states themselves (Gesture events do). So we only need
3895 // to hit-test on touchstart, and it can be read-only.
3896 if (point.state() == PlatformTouchPoint::TouchPressed) {
3897 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEv ent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3898 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->rootFram eToContents(point.pos()));
3899 HitTestResult result;
3900 if (!m_touchSequenceDocument) {
3901 result = hitTestResultAtPoint(pagePoint, hitType);
3902 } else if (m_touchSequenceDocument->frame()) {
3903 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocum ent->frame()->view()->rootFrameToContents(point.pos()));
3904 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), framePoint, hitType);
3905 } else {
3906 continue;
3907 }
3908
3909 Node* node = result.innerNode();
3910 if (!node)
3911 continue;
3912
3913 // Touch events should not go to text nodes
3914 if (node->isTextNode())
3915 node = ComposedTreeTraversal::parent(*node);
3916
3917 if (!m_touchSequenceDocument) {
3918 // Keep track of which document should receive all touch events
3919 // in the active sequence. This must be a single document to
3920 // ensure we don't leak Nodes between documents.
3921 m_touchSequenceDocument = &(result.innerNode()->document());
3922 ASSERT(m_touchSequenceDocument->frame()->view());
3923 }
3924
3925 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3926 // since we shouldn't get a touchstart for a touch that's already
3927 // down. However EventSender allows this to be violated and there's
3928 // some tests that take advantage of it. There may also be edge
3929 // cases in the browser where this happens.
3930 // See http://crbug.com/345372.
3931 m_targetForTouchID.set(point.id(), node);
3932
3933 TouchAction effectiveTouchAction = computeEffectiveTouchAction(*node );
3934 if (effectiveTouchAction != TouchActionAuto)
3935 m_frame->page()->chromeClient().setTouchAction(effectiveTouchAct ion);
3936 }
3937 }
3938
3939 m_touchPressed = !allTouchReleased;
3940
3941 // If there's no document receiving touch events, or no handlers on the
3942 // document set to receive the events, then we can skip all the rest of
3943 // this work.
3944 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !m_ touchSequenceDocument->frameHost()->eventHandlerRegistry().hasEventHandlers(Even tHandlerRegistry::TouchEvent) || !m_touchSequenceDocument->frame()) {
3945 if (allTouchReleased) {
3946 m_touchSequenceDocument.clear();
3947 m_touchSequenceUserGestureToken.clear();
3948 }
3949 return false;
3950 }
3951
3952 // Build up the lists to use for the 'touches', 'targetTouches' and
3953 // 'changedTouches' attributes in the JS event. See
3954 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3955 // lists fit together.
3956
3957 // Holds the complete set of touches on the screen.
3958 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3959
3960 // A different view on the 'touches' list above, filtered and grouped by
3961 // event target. Used for the 'targetTouches' list in the JS event.
3962 using TargetTouchesHeapMap = WillBeHeapHashMap<EventTarget*, RefPtrWillBeMem ber<TouchList>>;
3963 TargetTouchesHeapMap touchesByTarget;
3964
3965 // Array of touches per state, used to assemble the 'changedTouches' list.
3966 using EventTargetSet = WillBeHeapHashSet<RefPtrWillBeMember<EventTarget>>;
3967 struct {
3968 // The touches corresponding to the particular change state this struct
3969 // instance represents.
3970 RefPtrWillBeMember<TouchList> m_touches;
3971 // Set of targets involved in m_touches.
3972 EventTargetSet m_targets;
3973 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3974
3975 for (i = 0; i < points.size(); ++i) {
3976 const PlatformTouchPoint& point = points[i];
3977 PlatformTouchPoint::State pointState = point.state();
3978 RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr;
3979
3980 if (pointState == PlatformTouchPoint::TouchReleased || pointState == Pla tformTouchPoint::TouchCancelled) {
3981 // The target should be the original target for this touch, so get
3982 // it from the hashmap. As it's a release or cancel we also remove
3983 // it from the map.
3984 touchTarget = m_targetForTouchID.take(point.id());
3985 } else {
3986 // No hittest is performed on move or stationary, since the target
3987 // is not allowed to change anyway.
3988 touchTarget = m_targetForTouchID.get(point.id());
3989 }
3990
3991 LocalFrame* targetFrame = nullptr;
3992 bool knownTarget = false;
3993 if (touchTarget) {
3994 Document& doc = touchTarget->toNode()->document();
3995 // If the target node has moved to a new document while it was being touched,
3996 // we can't send events to the new document because that could leak nodes
3997 // from one document to another. See http://crbug.com/394339.
3998 if (&doc == m_touchSequenceDocument.get()) {
3999 targetFrame = doc.frame();
4000 knownTarget = true;
4001 }
4002 }
4003 if (!knownTarget) {
4004 // If we don't have a target registered for the point it means we've
4005 // missed our opportunity to do a hit test for it (due to some
4006 // optimization that prevented blink from ever seeing the
4007 // touchstart), or that the touch started outside the active touch
4008 // sequence document. We should still include the touch in the
4009 // Touches list reported to the application (eg. so it can
4010 // differentiate between a one and two finger gesture), but we won't
4011 // actually dispatch any events for it. Set the target to the
4012 // Document so that there's some valid node here. Perhaps this
4013 // should really be LocalDOMWindow, but in all other cases the targe t of
4014 // a Touch is a Node so using the window could be a breaking change.
4015 // Since we know there was no handler invoked, the specific target
4016 // should be completely irrelevant to the application.
4017 touchTarget = m_touchSequenceDocument;
4018 targetFrame = m_touchSequenceDocument->frame();
4019 }
4020 ASSERT(targetFrame);
4021
4022 // pagePoint should always be in the target element's document coordinat es.
4023 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents(point.po s());
4024
4025 float scaleFactor = 1.0f / targetFrame->pageZoomFactor();
4026
4027 FloatPoint adjustedPagePoint = pagePoint.scaledBy(scaleFactor);
4028 FloatSize adjustedRadius = point.radius().scaledBy(scaleFactor);
4029
4030 RefPtrWillBeRawPtr<Touch> touch = Touch::create(
4031 targetFrame, touchTarget.get(), point.id(), point.screenPos(), adjus tedPagePoint, adjustedRadius, point.rotationAngle(), point.force());
4032
4033 // Ensure this target's touch list exists, even if it ends up empty, so
4034 // it can always be passed to TouchEvent::Create below.
4035 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.f ind(touchTarget.get());
4036 if (targetTouchesIterator == touchesByTarget.end()) {
4037 touchesByTarget.set(touchTarget.get(), TouchList::create());
4038 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
4039 }
4040
4041 // touches and targetTouches should only contain information about
4042 // touches still on the screen, so if this point is released or
4043 // cancelled it will only appear in the changedTouches list.
4044 if (pointState != PlatformTouchPoint::TouchReleased && pointState != Pla tformTouchPoint::TouchCancelled) {
4045 touches->append(touch);
4046 targetTouchesIterator->value->append(touch);
4047 }
4048
4049 // Now build up the correct list for changedTouches.
4050 // Note that any touches that are in the TouchStationary state (e.g. if
4051 // the user had several points touched but did not move them all) should
4052 // never be in the changedTouches list so we do not handle them
4053 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
4054 // for further discussion about the TouchStationary state.
4055 if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) {
4056 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
4057 if (!changedTouches[pointState].m_touches)
4058 changedTouches[pointState].m_touches = TouchList::create();
4059 changedTouches[pointState].m_touches->append(touch);
4060 changedTouches[pointState].m_targets.add(touchTarget);
4061 }
4062 }
4063 if (allTouchReleased) {
4064 m_touchSequenceDocument.clear();
4065 m_touchSequenceUserGestureToken.clear();
4066 }
4067
4068 // Now iterate the changedTouches list and m_targets within it, sending
4069 // events to the targets as required.
4070 bool swallowedEvent = false;
4071 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state ) {
4072 if (!changedTouches[state].m_touches)
4073 continue;
4074
4075 const AtomicString& stateName(eventNameForTouchPointState(static_cast<Pl atformTouchPoint::State>(state)));
4076 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
4077 for (const RefPtrWillBeMember<EventTarget>& eventTarget : targetsForStat e) {
4078 EventTarget* touchEventTarget = eventTarget.get();
4079 RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create(
4080 touches.get(), touchesByTarget.get(touchEventTarget), changedTou ches[state].m_touches.get(),
4081 stateName, touchEventTarget->toNode()->document().domWindow(),
4082 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey (), event.cancelable(), event.causesScrollingIfUncanceled(), event.timestamp());
4083 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
4084 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
4085 }
4086 }
4087
4088 return swallowedEvent;
4089 }
4090
4091 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
4092 {
4093 if (action1 == TouchActionNone || action2 == TouchActionNone)
4094 return TouchActionNone;
4095 if (action1 == TouchActionAuto)
4096 return action2;
4097 if (action2 == TouchActionAuto)
4098 return action1;
4099 if (!(action1 & action2))
4100 return TouchActionNone;
4101 return action1 & action2;
4102 }
4103
4104 // touch-action applies to all elements with both width AND height properties.
4105 // According to the CSS Box Model Spec (http://dev.w3.org/csswg/css-box/#the-wid th-and-height-properties)
4106 // width applies to all elements but non-replaced inline elements, table rows, a nd row groups and
4107 // height applies to all elements but non-replaced inline elements, table column s, and column groups.
4108 static inline bool supportsTouchAction(const LayoutObject& object)
4109 {
4110 if (object.isInline() && !object.isReplaced())
4111 return false;
4112 if (object.isTableRow() || object.isLayoutTableCol())
4113 return false;
4114
4115 return true;
4116 }
4117
4118 TouchAction EventHandler::computeEffectiveTouchAction(const Node& node)
4119 {
4120 // Start by permitting all actions, then walk the elements supporting
4121 // touch-action from the target node up to the nearest scrollable ancestor
4122 // and exclude any prohibited actions.
4123 TouchAction effectiveTouchAction = TouchActionAuto;
4124 for (const Node* curNode = &node; curNode; curNode = ComposedTreeTraversal:: parent(*curNode)) {
4125 if (LayoutObject* layoutObject = curNode->layoutObject()) {
4126 if (supportsTouchAction(*layoutObject)) {
4127 TouchAction action = layoutObject->style()->touchAction();
4128 effectiveTouchAction = intersectTouchAction(action, effectiveTou chAction);
4129 if (effectiveTouchAction == TouchActionNone)
4130 break;
4131 }
4132
4133 // If we've reached an ancestor that supports a touch action, search no further.
4134 if (layoutObject->isBox() && toLayoutBox(layoutObject)->scrollsOverf low())
4135 break;
4136 }
4137 }
4138 return effectiveTouchAction;
4139 }
4140
4141 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
4142 {
4143 m_mousePositionIsUnknown = false;
4144 m_lastKnownMousePosition = event.position();
4145 m_lastKnownMouseGlobalPosition = event.globalPosition();
4146 }
4147
4148 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& m ev, LocalFrame* subframe)
4149 { 532 {
4150 // If we're clicking into a frame that is selected, the frame will appear 533 // If we're clicking into a frame that is selected, the frame will appear
4151 // greyed out even though we're clicking on the selection. This looks 534 // greyed out even though we're clicking on the selection. This looks
4152 // really strange (having the whole frame be greyed out), so we deselect the 535 // really strange (having the whole frame be greyed out), so we deselect the
4153 // selection. 536 // selection.
4154 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position()); 537 IntPoint p = m_frame->view()->rootFrameToContents(mev.event().position());
4155 if (m_frame->selection().contains(p)) { 538 if (m_frame->selection().contains(p)) {
4156 VisiblePosition visiblePos( 539 VisiblePosition visiblePos(
4157 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())) ; 540 mev.innerNode()->layoutObject()->positionForPoint(mev.localPoint())) ;
4158 VisibleSelection newSelection(visiblePos); 541 VisibleSelection newSelection(visiblePos);
4159 m_frame->selection().setSelection(newSelection); 542 m_frame->selection().setSelection(newSelection);
4160 } 543 }
4161
4162 subframe->eventHandler().handleMousePressEvent(mev.event());
4163 return true;
4164 } 544 }
4165 545
4166 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& me v, LocalFrame* subframe, HitTestResult* hoveredNode) 546 void SelectionController::initializeSelectionState()
4167 { 547 {
4168 if (m_mouseDownMayStartDrag) 548 m_selectionInitiationState = HaveNotStartedSelection;
4169 return false;
4170 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNod e);
4171 return true;
4172 } 549 }
4173 550
4174 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe) 551 void SelectionController::setMouseDownMayStartSelect(bool mayStartSelect)
4175 { 552 {
4176 subframe->eventHandler().handleMouseReleaseEvent(mev.event()); 553 m_mouseDownMayStartSelect = mayStartSelect;
4177 return true;
4178 } 554 }
4179 555
4180 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget& widget) 556 bool SelectionController::mouseDownMayStartSelect() const
4181 { 557 {
4182 // If not a FrameView, then probably a plugin widget. Those will receive 558 return m_mouseDownMayStartSelect;
4183 // the event via an EventTargetNode dispatch when this returns false.
4184 if (!widget.isFrameView())
4185 return false;
4186
4187 return toFrameView(&widget)->frame().eventHandler().handleWheelEvent(wheelEv ent);
4188 } 559 }
4189 560
4190 DataTransfer* EventHandler::createDraggingDataTransfer() const 561 bool SelectionController::mouseDownWasSingleClickInSelection() const
4191 { 562 {
4192 return DataTransfer::create(DataTransfer::DragAndDrop, DataTransferWritable, DataObject::create()); 563 return m_mouseDownWasSingleClickInSelection;
4193 }
4194
4195 void EventHandler::focusDocumentView()
4196 {
4197 Page* page = m_frame->page();
4198 if (!page)
4199 return;
4200 page->focusController().focusDocumentView(m_frame);
4201 }
4202
4203 unsigned EventHandler::accessKeyModifiers()
4204 {
4205 #if OS(MACOSX)
4206 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
4207 #else
4208 return PlatformEvent::AltKey;
4209 #endif
4210 } 564 }
4211 565
4212 } // namespace blink 566 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/editing/SelectionController.h ('k') | Source/core/html/HTMLLabelElement.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698