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

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