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

Side by Side Diff: third_party/WebKit/Source/core/input/EventHandler.cpp

Issue 1892653003: Extract touch handling logic from EventHandler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add TODO Created 4 years, 7 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
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 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 #include "core/fetch/ImageResource.h" 52 #include "core/fetch/ImageResource.h"
53 #include "core/frame/Deprecation.h" 53 #include "core/frame/Deprecation.h"
54 #include "core/frame/EventHandlerRegistry.h" 54 #include "core/frame/EventHandlerRegistry.h"
55 #include "core/frame/FrameHost.h" 55 #include "core/frame/FrameHost.h"
56 #include "core/frame/FrameView.h" 56 #include "core/frame/FrameView.h"
57 #include "core/frame/LocalFrame.h" 57 #include "core/frame/LocalFrame.h"
58 #include "core/frame/Settings.h" 58 #include "core/frame/Settings.h"
59 #include "core/frame/TopControls.h" 59 #include "core/frame/TopControls.h"
60 #include "core/frame/UseCounter.h" 60 #include "core/frame/UseCounter.h"
61 #include "core/frame/VisualViewport.h" 61 #include "core/frame/VisualViewport.h"
62 #include "core/html/HTMLCanvasElement.h"
63 #include "core/html/HTMLDialogElement.h" 62 #include "core/html/HTMLDialogElement.h"
64 #include "core/html/HTMLFrameElementBase.h" 63 #include "core/html/HTMLFrameElementBase.h"
65 #include "core/html/HTMLFrameSetElement.h" 64 #include "core/html/HTMLFrameSetElement.h"
66 #include "core/html/HTMLInputElement.h" 65 #include "core/html/HTMLInputElement.h"
67 #include "core/input/InputDeviceCapabilities.h" 66 #include "core/input/InputDeviceCapabilities.h"
68 #include "core/input/TouchActionUtil.h" 67 #include "core/input/TouchActionUtil.h"
69 #include "core/layout/HitTestRequest.h" 68 #include "core/layout/HitTestRequest.h"
70 #include "core/layout/HitTestResult.h" 69 #include "core/layout/HitTestResult.h"
71 #include "core/layout/LayoutPart.h" 70 #include "core/layout/LayoutPart.h"
72 #include "core/layout/LayoutTextControlSingleLine.h" 71 #include "core/layout/LayoutTextControlSingleLine.h"
73 #include "core/layout/LayoutView.h" 72 #include "core/layout/LayoutView.h"
74 #include "core/layout/api/LayoutViewItem.h" 73 #include "core/layout/api/LayoutViewItem.h"
75 #include "core/loader/DocumentLoader.h" 74 #include "core/loader/DocumentLoader.h"
76 #include "core/loader/FrameLoader.h" 75 #include "core/loader/FrameLoader.h"
77 #include "core/loader/FrameLoaderClient.h" 76 #include "core/loader/FrameLoaderClient.h"
78 #include "core/page/AutoscrollController.h" 77 #include "core/page/AutoscrollController.h"
79 #include "core/page/ChromeClient.h" 78 #include "core/page/ChromeClient.h"
80 #include "core/page/DragController.h" 79 #include "core/page/DragController.h"
81 #include "core/page/DragState.h" 80 #include "core/page/DragState.h"
82 #include "core/page/FocusController.h" 81 #include "core/page/FocusController.h"
83 #include "core/page/FrameTree.h" 82 #include "core/page/FrameTree.h"
84 #include "core/page/Page.h" 83 #include "core/page/Page.h"
85 #include "core/page/SpatialNavigation.h" 84 #include "core/page/SpatialNavigation.h"
86 #include "core/page/TouchAdjustment.h" 85 #include "core/page/TouchAdjustment.h"
87 #include "core/page/scrolling/OverscrollController.h" 86 #include "core/page/scrolling/OverscrollController.h"
88 #include "core/page/scrolling/ScrollState.h" 87 #include "core/page/scrolling/ScrollState.h"
89 #include "core/paint/PaintLayer.h" 88 #include "core/paint/PaintLayer.h"
90 #include "core/style/ComputedStyle.h" 89 #include "core/style/ComputedStyle.h"
91 #include "core/svg/SVGDocumentExtensions.h" 90 #include "core/svg/SVGDocumentExtensions.h"
92 #include "platform/Histogram.h"
93 #include "platform/PlatformGestureEvent.h" 91 #include "platform/PlatformGestureEvent.h"
94 #include "platform/PlatformKeyboardEvent.h" 92 #include "platform/PlatformKeyboardEvent.h"
95 #include "platform/PlatformTouchEvent.h" 93 #include "platform/PlatformTouchEvent.h"
96 #include "platform/PlatformWheelEvent.h" 94 #include "platform/PlatformWheelEvent.h"
97 #include "platform/RuntimeEnabledFeatures.h" 95 #include "platform/RuntimeEnabledFeatures.h"
98 #include "platform/TraceEvent.h" 96 #include "platform/TraceEvent.h"
99 #include "platform/WindowsKeyboardCodes.h" 97 #include "platform/WindowsKeyboardCodes.h"
100 #include "platform/geometry/FloatPoint.h" 98 #include "platform/geometry/FloatPoint.h"
101 #include "platform/graphics/Image.h" 99 #include "platform/graphics/Image.h"
102 #include "platform/heap/Handle.h" 100 #include "platform/heap/Handle.h"
103 #include "platform/scroll/ScrollAnimatorBase.h" 101 #include "platform/scroll/ScrollAnimatorBase.h"
104 #include "platform/scroll/Scrollbar.h" 102 #include "platform/scroll/Scrollbar.h"
105 #include "wtf/Assertions.h" 103 #include "wtf/Assertions.h"
106 #include "wtf/CurrentTime.h" 104 #include "wtf/CurrentTime.h"
107 #include "wtf/StdLibExtras.h" 105 #include "wtf/StdLibExtras.h"
108 #include "wtf/TemporaryChange.h" 106 #include "wtf/TemporaryChange.h"
109 107
110 namespace blink { 108 namespace blink {
111 109
112 namespace { 110 namespace {
113 111
114 bool hasTouchHandlers(const EventHandlerRegistry& registry)
115 {
116 return registry.hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEvent Blocking)
117 || registry.hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEvent Passive)
118 || registry.hasEventHandlers(EventHandlerRegistry::TouchEndOrCancelEvent Blocking)
119 || registry.hasEventHandlers(EventHandlerRegistry::TouchEndOrCancelEvent Passive);
120 }
121
122 const AtomicString& touchEventNameForTouchPointState(PlatformTouchPoint::TouchSt ate state)
123 {
124 switch (state) {
125 case PlatformTouchPoint::TouchReleased:
126 return EventTypeNames::touchend;
127 case PlatformTouchPoint::TouchCancelled:
128 return EventTypeNames::touchcancel;
129 case PlatformTouchPoint::TouchPressed:
130 return EventTypeNames::touchstart;
131 case PlatformTouchPoint::TouchMoved:
132 return EventTypeNames::touchmove;
133 case PlatformTouchPoint::TouchStationary:
134 // Fall through to default
135 default:
136 ASSERT_NOT_REACHED();
137 return emptyAtom;
138 }
139 }
140
141 // Convert |event->deltaMode()| to scroll granularity and output as |granularity |. 112 // Convert |event->deltaMode()| to scroll granularity and output as |granularity |.
142 bool wheelGranularityToScrollGranularity(const WheelEvent* event, ScrollGranular ity* granularity) 113 bool wheelGranularityToScrollGranularity(const WheelEvent* event, ScrollGranular ity* granularity)
143 { 114 {
144 DCHECK(granularity); 115 DCHECK(granularity);
145 switch (event->deltaMode()) { 116 switch (event->deltaMode()) {
146 case WheelEvent::DOM_DELTA_PAGE: 117 case WheelEvent::DOM_DELTA_PAGE:
147 *granularity = ScrollByPage; 118 *granularity = ScrollByPage;
148 return true; 119 return true;
149 case WheelEvent::DOM_DELTA_LINE: 120 case WheelEvent::DOM_DELTA_LINE:
150 *granularity = ScrollByLine; 121 *granularity = ScrollByLine;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 } 175 }
205 // TODO(tdresser): this should sometimes be excluded, as part of crbug.com/4 10974. 176 // TODO(tdresser): this should sometimes be excluded, as part of crbug.com/4 10974.
206 // We need to ensure that the scrollingElement is always part of 177 // We need to ensure that the scrollingElement is always part of
207 // the scroll chain. In quirks mode, when the scrollingElement is 178 // the scroll chain. In quirks mode, when the scrollingElement is
208 // the body, some elements may use the documentElement as their 179 // the body, some elements may use the documentElement as their
209 // containingBlock, so we ensure the scrollingElement is added 180 // containingBlock, so we ensure the scrollingElement is added
210 // here. 181 // here.
211 scrollChain.push_front(DOMNodeIds::idForNode(frame.document()->scrollingElem ent())); 182 scrollChain.push_front(DOMNodeIds::idForNode(frame.document()->scrollingElem ent()));
212 } 183 }
213 184
214 // These offsets change indicies into the ListenerHistogram
215 // enumeration. The addition of a series of offsets then
216 // produces the resulting ListenerHistogram value.
217 const size_t kTouchTargetHistogramRootScrollerOffset = 4;
218 const size_t kTouchTargetHistogramScrollableDocumentOffset = 2;
219 const size_t kTouchTargetHistogramHandledOffset = 1;
220
221 enum TouchTargetAndDispatchResultType {
222 NonRootScrollerNonScrollableNotHandled, // Non-root-scroller, non-scrollable document, not handled.
223 NonRootScrollerNonScrollableHandled, // Non-root-scroller, non-scrollable do cument, handled application.
224 NonRootScrollerScrollableDocumentNotHandled, // Non-root-scroller, scrollabl e document, not handled.
225 NonRootScrollerScrollableDocumentHandled, // Non-root-scroller, scrollable d ocument, handled application.
226 RootScrollerNonScrollableNotHandled, // Root-scroller, non-scrollable docume nt, not handled.
227 RootScrollerNonScrollableHandled, // Root-scroller, non-scrollable document, handled.
228 RootScrollerScrollableDocumentNotHandled, // Root-scroller, scrollable docum ent, not handled.
229 RootScrollerScrollableDocumentHandled, // Root-scroller, scrollable document , handled.
230 TouchTargetAndDispatchResultTypeMax,
231 };
232
233 TouchTargetAndDispatchResultType toTouchTargetHistogramValue(EventTarget* eventT arget, DispatchEventResult dispatchResult)
234 {
235 int result = 0;
236 Document* document = nullptr;
237
238 if (const LocalDOMWindow* domWindow = eventTarget->toLocalDOMWindow()) {
239 // Treat the window as a root scroller as well.
240 document = domWindow->document();
241 result += kTouchTargetHistogramRootScrollerOffset;
242 } else if (Node* node = eventTarget->toNode()) {
243 // Report if the target node is the document or body.
244 if (node->isDocumentNode() || static_cast<Node*>(node->document().docume ntElement()) == node || static_cast<Node*>(node->document().body()) == node) {
245 result += kTouchTargetHistogramRootScrollerOffset;
246 }
247 document = &node->document();
248 }
249
250 if (document) {
251 FrameView* view = document->view();
252 if (view && view->isScrollable())
253 result += kTouchTargetHistogramScrollableDocumentOffset;
254 }
255
256 if (dispatchResult != DispatchEventResult::NotCanceled)
257 result += kTouchTargetHistogramHandledOffset;
258 return static_cast<TouchTargetAndDispatchResultType>(result);
259 }
260
261 enum TouchEventDispatchResultType {
262 UnhandledTouches, // Unhandled touch events.
263 HandledTouches, // Handled touch events.
264 TouchEventDispatchResultTypeMax,
265 };
266
267 } // namespace 185 } // namespace
268 186
269 using namespace HTMLNames; 187 using namespace HTMLNames;
270 188
271 // The link drag hysteresis is much larger than the others because there 189 // The link drag hysteresis is much larger than the others because there
272 // needs to be enough space to cancel the link press without starting a link dra g, 190 // needs to be enough space to cancel the link press without starting a link dra g,
273 // and because dragging links is rare. 191 // and because dragging links is rare.
274 static const int LinkDragHysteresis = 40; 192 static const int LinkDragHysteresis = 40;
275 static const int ImageDragHysteresis = 5; 193 static const int ImageDragHysteresis = 5;
276 static const int TextDragHysteresis = 3; 194 static const int TextDragHysteresis = 3;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired) 246 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
329 , m_mouseDownMayStartAutoscroll(false) 247 , m_mouseDownMayStartAutoscroll(false)
330 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFire d) 248 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFire d)
331 , m_svgPan(false) 249 , m_svgPan(false)
332 , m_resizeScrollableArea(nullptr) 250 , m_resizeScrollableArea(nullptr)
333 , m_eventHandlerWillResetCapturingMouseEventsNode(0) 251 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
334 , m_clickCount(0) 252 , m_clickCount(0)
335 , m_shouldOnlyFireDragOverEvent(false) 253 , m_shouldOnlyFireDragOverEvent(false)
336 , m_mousePositionIsUnknown(true) 254 , m_mousePositionIsUnknown(true)
337 , m_mouseDownTimestamp(0) 255 , m_mouseDownTimestamp(0)
338 , m_touchPressed(false) 256 , m_pointerEventManager(frame)
339 , m_scrollGestureHandlingNode(nullptr) 257 , m_scrollGestureHandlingNode(nullptr)
340 , m_lastGestureScrollOverWidget(false) 258 , m_lastGestureScrollOverWidget(false)
341 , m_longTapShouldInvokeContextMenu(false) 259 , m_longTapShouldInvokeContextMenu(false)
342 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired) 260 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
343 , m_lastShowPressTimestamp(0) 261 , m_lastShowPressTimestamp(0)
344 , m_deltaConsumedForScrollSequence(false) 262 , m_deltaConsumedForScrollSequence(false)
345 , m_waitingForFirstTouchMove(false)
346 { 263 {
347 } 264 }
348 265
349 EventHandler::~EventHandler() 266 EventHandler::~EventHandler()
350 { 267 {
351 ASSERT(!m_fakeMouseMoveEventTimer.isActive()); 268 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
352 } 269 }
353 270
354 DEFINE_TRACE(EventHandler) 271 DEFINE_TRACE(EventHandler)
355 { 272 {
356 visitor->trace(m_frame); 273 visitor->trace(m_frame);
357 visitor->trace(m_mousePressNode); 274 visitor->trace(m_mousePressNode);
358 visitor->trace(m_resizeScrollableArea); 275 visitor->trace(m_resizeScrollableArea);
359 visitor->trace(m_capturingMouseEventsNode); 276 visitor->trace(m_capturingMouseEventsNode);
360 visitor->trace(m_nodeUnderMouse); 277 visitor->trace(m_nodeUnderMouse);
361 visitor->trace(m_lastMouseMoveEventSubframe); 278 visitor->trace(m_lastMouseMoveEventSubframe);
362 visitor->trace(m_lastScrollbarUnderMouse); 279 visitor->trace(m_lastScrollbarUnderMouse);
363 visitor->trace(m_clickNode); 280 visitor->trace(m_clickNode);
364 visitor->trace(m_dragTarget); 281 visitor->trace(m_dragTarget);
365 visitor->trace(m_frameSetBeingResized); 282 visitor->trace(m_frameSetBeingResized);
366 visitor->trace(m_scrollbarHandlingScrollGesture); 283 visitor->trace(m_scrollbarHandlingScrollGesture);
367 visitor->trace(m_targetForTouchID);
368 visitor->trace(m_touchSequenceDocument);
369 visitor->trace(m_scrollGestureHandlingNode); 284 visitor->trace(m_scrollGestureHandlingNode);
370 visitor->trace(m_previousGestureScrolledNode); 285 visitor->trace(m_previousGestureScrolledNode);
371 visitor->trace(m_lastDeferredTapElement); 286 visitor->trace(m_lastDeferredTapElement);
372 visitor->trace(m_selectionController); 287 visitor->trace(m_selectionController);
373 visitor->trace(m_pointerEventManager); 288 visitor->trace(m_pointerEventManager);
374 } 289 }
375 290
376 DragState& EventHandler::dragState() 291 DragState& EventHandler::dragState()
377 { 292 {
378 DEFINE_STATIC_LOCAL(DragState, state, (new DragState)); 293 DEFINE_STATIC_LOCAL(DragState, state, (new DragState));
(...skipping 16 matching lines...) Expand all
395 m_dragTarget = nullptr; 310 m_dragTarget = nullptr;
396 m_shouldOnlyFireDragOverEvent = false; 311 m_shouldOnlyFireDragOverEvent = false;
397 m_mousePositionIsUnknown = true; 312 m_mousePositionIsUnknown = true;
398 m_lastKnownMousePosition = IntPoint(); 313 m_lastKnownMousePosition = IntPoint();
399 m_lastKnownMouseGlobalPosition = IntPoint(); 314 m_lastKnownMouseGlobalPosition = IntPoint();
400 m_lastMouseDownUserGestureToken.clear(); 315 m_lastMouseDownUserGestureToken.clear();
401 m_mousePressNode = nullptr; 316 m_mousePressNode = nullptr;
402 m_mousePressed = false; 317 m_mousePressed = false;
403 m_capturesDragging = false; 318 m_capturesDragging = false;
404 m_capturingMouseEventsNode = nullptr; 319 m_capturingMouseEventsNode = nullptr;
405 m_targetForTouchID.clear();
406 m_touchSequenceDocument.clear();
407 m_touchSequenceUserGestureToken.clear();
408 clearGestureScrollState(); 320 clearGestureScrollState();
409 m_lastGestureScrollOverWidget = false; 321 m_lastGestureScrollOverWidget = false;
410 m_scrollbarHandlingScrollGesture = nullptr; 322 m_scrollbarHandlingScrollGesture = nullptr;
411 m_touchPressed = false;
412 m_pointerEventManager.clear(); 323 m_pointerEventManager.clear();
413 m_mouseDownMayStartDrag = false; 324 m_mouseDownMayStartDrag = false;
414 m_lastShowPressTimestamp = 0; 325 m_lastShowPressTimestamp = 0;
415 m_lastDeferredTapElement = nullptr; 326 m_lastDeferredTapElement = nullptr;
416 m_eventHandlerWillResetCapturingMouseEventsNode = false; 327 m_eventHandlerWillResetCapturingMouseEventsNode = false;
417 m_mouseDownMayStartAutoscroll = false; 328 m_mouseDownMayStartAutoscroll = false;
418 m_svgPan = false; 329 m_svgPan = false;
419 m_mouseDownPos = IntPoint(); 330 m_mouseDownPos = IntPoint();
420 m_mouseDownTimestamp = 0; 331 m_mouseDownTimestamp = 0;
421 m_longTapShouldInvokeContextMenu = false; 332 m_longTapShouldInvokeContextMenu = false;
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after
1355 hitType |= HitTestRequest::Active; 1266 hitType |= HitTestRequest::Active;
1356 } else if (onlyUpdateScrollbars) { 1267 } else if (onlyUpdateScrollbars) {
1357 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This 1268 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1358 // means that :hover and :active freeze in the state they were in, rathe r than updating 1269 // means that :hover and :active freeze in the state they were in, rathe r than updating
1359 // for nodes the mouse moves while the window is not key (which will be the case if 1270 // for nodes the mouse moves while the window is not key (which will be the case if
1360 // onlyUpdateScrollbars is true). 1271 // onlyUpdateScrollbars is true).
1361 hitType |= HitTestRequest::ReadOnly; 1272 hitType |= HitTestRequest::ReadOnly;
1362 } 1273 }
1363 1274
1364 // Treat any mouse move events as readonly if the user is currently touching the screen. 1275 // Treat any mouse move events as readonly if the user is currently touching the screen.
1365 if (m_touchPressed) 1276 if (m_pointerEventManager.isAnyTouchActive())
1366 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly; 1277 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1367 HitTestRequest request(hitType); 1278 HitTestRequest request(hitType);
1368 MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(mouseEvent, HitTestResult(request, LayoutPoint())); 1279 MouseEventWithHitTestResults mev = MouseEventWithHitTestResults(mouseEvent, HitTestResult(request, LayoutPoint()));
1369 1280
1370 // 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. 1281 // 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.
1371 // So we must force the hit-test to fail, while still clearing hover/active state. 1282 // So we must force the hit-test to fail, while still clearing hover/active state.
1372 if (forceLeave) 1283 if (forceLeave)
1373 m_frame->document()->updateHoverActiveState(request, 0); 1284 m_frame->document()->updateHoverActiveState(request, 0);
1374 else 1285 else
1375 mev = prepareMouseEvent(request, mouseEvent); 1286 mev = prepareMouseEvent(request, mouseEvent);
(...skipping 2341 matching lines...) Expand 10 before | Expand all | Expand 10 after
3717 return result; 3628 return result;
3718 if (frame->view()) { 3629 if (frame->view()) {
3719 IntRect rect = frame->view()->visibleContentRect(IncludeScrollbars); 3630 IntRect rect = frame->view()->visibleContentRect(IncludeScrollbars);
3720 if (!rect.contains(roundedIntPoint(point))) 3631 if (!rect.contains(roundedIntPoint(point)))
3721 return result; 3632 return result;
3722 } 3633 }
3723 frame->contentLayoutItem().hitTest(result); 3634 frame->contentLayoutItem().hitTest(result);
3724 return result; 3635 return result;
3725 } 3636 }
3726 3637
3727 void EventHandler::dispatchPointerEvents(const PlatformTouchEvent& event,
3728 HeapVector<TouchInfo>& touchInfos)
3729 {
3730 if (!RuntimeEnabledFeatures::pointerEventEnabled())
3731 return;
3732
3733 // Iterate through the touch points, sending PointerEvents to the targets as required.
3734 for (unsigned i = 0; i < touchInfos.size(); ++i) {
3735 TouchInfo& touchInfo = touchInfos[i];
3736 const PlatformTouchPoint& touchPoint = touchInfo.point;
3737
3738
3739 if (touchPoint.state() == PlatformTouchPoint::TouchStationary
3740 || !touchInfo.knownTarget)
3741 continue;
3742
3743 WebInputEventResult result =
3744 m_pointerEventManager.sendTouchPointerEvent(
3745 touchInfo.touchTarget, touchPoint, event.getModifiers(),
3746 touchInfo.adjustedRadius.width(), touchInfo.adjustedRadius.height(),
3747 touchInfo.adjustedPagePoint.x(), touchInfo.adjustedPagePoint.y());
3748 touchInfo.consumed = result != WebInputEventResult::NotHandled;
3749 }
3750 }
3751
3752 namespace {
3753
3754 // Defining this class type local to dispatchTouchEvents() and annotating
3755 // it with STACK_ALLOCATED(), runs into MSVC(VS 2013)'s C4822 warning
3756 // that the local class doesn't provide a local definition for 'operator new'.
3757 // Which it intentionally doesn't and shouldn't.
3758 //
3759 // Work around such toolchain bugginess by lifting out the type, thereby
3760 // taking it out of C4822's reach.
3761 class ChangedTouches final {
3762 STACK_ALLOCATED();
3763 public:
3764 // The touches corresponding to the particular change state this struct
3765 // instance represents.
3766 Member<TouchList> m_touches;
3767
3768 using EventTargetSet = HeapHashSet<Member<EventTarget>>;
3769 // Set of targets involved in m_touches.
3770 EventTargetSet m_targets;
3771 };
3772
3773 } // namespace
3774
3775 WebInputEventResult EventHandler::dispatchTouchEvents(const PlatformTouchEvent& event,
3776 HeapVector<TouchInfo>& touchInfos, bool allTouchReleased)
3777 {
3778 bool touchStartOrFirstTouchMove = false;
3779 if (event.type() == PlatformEvent::TouchStart) {
3780 m_waitingForFirstTouchMove = true;
3781 touchStartOrFirstTouchMove = true;
3782 } else if (event.type() == PlatformEvent::TouchMove) {
3783 touchStartOrFirstTouchMove = m_waitingForFirstTouchMove;
3784 m_waitingForFirstTouchMove = false;
3785 }
3786
3787 // Build up the lists to use for the 'touches', 'targetTouches' and
3788 // 'changedTouches' attributes in the JS event. See
3789 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3790 // lists fit together.
3791
3792 // Holds the complete set of touches on the screen.
3793 TouchList* touches = TouchList::create();
3794
3795 // A different view on the 'touches' list above, filtered and grouped by
3796 // event target. Used for the 'targetTouches' list in the JS event.
3797 using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>;
3798 TargetTouchesHeapMap touchesByTarget;
3799
3800 // Array of touches per state, used to assemble the 'changedTouches' list.
3801 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd];
3802
3803 for (unsigned i = 0; i < touchInfos.size(); ++i) {
3804 const TouchInfo& touchInfo = touchInfos[i];
3805 const PlatformTouchPoint& point = touchInfo.point;
3806 PlatformTouchPoint::TouchState pointState = point.state();
3807
3808 if (touchInfo.consumed)
3809 continue;
3810
3811 Touch* touch = Touch::create(
3812 touchInfo.targetFrame.get(),
3813 touchInfo.touchTarget.get(),
3814 point.id(),
3815 point.screenPos(),
3816 touchInfo.adjustedPagePoint,
3817 touchInfo.adjustedRadius,
3818 point.rotationAngle(),
3819 point.force(),
3820 touchInfo.region);
3821
3822 // Ensure this target's touch list exists, even if it ends up empty, so
3823 // it can always be passed to TouchEvent::Create below.
3824 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.f ind(touchInfo.touchTarget.get());
3825 if (targetTouchesIterator == touchesByTarget.end()) {
3826 touchesByTarget.set(touchInfo.touchTarget.get(), TouchList::create() );
3827 targetTouchesIterator = touchesByTarget.find(touchInfo.touchTarget.g et());
3828 }
3829
3830 // touches and targetTouches should only contain information about
3831 // touches still on the screen, so if this point is released or
3832 // cancelled it will only appear in the changedTouches list.
3833 if (pointState != PlatformTouchPoint::TouchReleased && pointState != Pla tformTouchPoint::TouchCancelled) {
3834 touches->append(touch);
3835 targetTouchesIterator->value->append(touch);
3836 }
3837
3838 // Now build up the correct list for changedTouches.
3839 // Note that any touches that are in the TouchStationary state (e.g. if
3840 // the user had several points touched but did not move them all) should
3841 // never be in the changedTouches list so we do not handle them
3842 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
3843 // for further discussion about the TouchStationary state.
3844 if (pointState != PlatformTouchPoint::TouchStationary && touchInfo.known Target) {
3845 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3846 if (!changedTouches[pointState].m_touches)
3847 changedTouches[pointState].m_touches = TouchList::create();
3848 changedTouches[pointState].m_touches->append(touch);
3849 changedTouches[pointState].m_targets.add(touchInfo.touchTarget);
3850 }
3851 }
3852 if (allTouchReleased) {
3853 m_touchSequenceDocument.clear();
3854 m_touchSequenceUserGestureToken.clear();
3855 }
3856
3857 WebInputEventResult eventResult = WebInputEventResult::NotHandled;
3858
3859 // Now iterate through the changedTouches list and m_targets within it, send ing
3860 // TouchEvents to the targets as required.
3861 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state ) {
3862 if (!changedTouches[state].m_touches)
3863 continue;
3864
3865 const AtomicString& eventName(touchEventNameForTouchPointState(static_ca st<PlatformTouchPoint::TouchState>(state)));
3866 for (const auto& eventTarget : changedTouches[state].m_targets) {
3867 EventTarget* touchEventTarget = eventTarget;
3868 TouchEvent* touchEvent = TouchEvent::create(
3869 touches, touchesByTarget.get(touchEventTarget), changedTouches[s tate].m_touches.get(),
3870 eventName, touchEventTarget->toNode()->document().domWindow(),
3871 event.getModifiers(), event.cancelable(), event.causesScrollingI fUncanceled(), event.timestamp());
3872
3873 DispatchEventResult domDispatchResult = touchEventTarget->dispatchEv ent(touchEvent);
3874
3875 // Only report for top level documents with a single touch on
3876 // touch-start or the first touch-move.
3877 if (touchStartOrFirstTouchMove && touchInfos.size() == 1 && event.ca ncelable() && !m_frame->document()->ownerElement()) {
3878 DEFINE_STATIC_LOCAL(EnumerationHistogram, rootDocumentListenerHi stogram, ("Event.Touch.TargetAndDispatchResult", TouchTargetAndDispatchResultTyp eMax));
3879 rootDocumentListenerHistogram.count(toTouchTargetHistogramValue( eventTarget, domDispatchResult));
3880
3881 // Count the handled touch starts and first touch moves before a nd after the page is fully loaded respectively.
3882 if (m_frame->document()->isLoadCompleted()) {
3883 DEFINE_STATIC_LOCAL(EnumerationHistogram, touchDispositionsA fterPageLoadHistogram, ("Event.Touch.TouchDispositionsAfterPageLoad", TouchEvent DispatchResultTypeMax));
3884 touchDispositionsAfterPageLoadHistogram.count((domDispatchRe sult != DispatchEventResult::NotCanceled) ? HandledTouches : UnhandledTouches);
3885 } else {
3886 DEFINE_STATIC_LOCAL(EnumerationHistogram, touchDispositionsB eforePageLoadHistogram, ("Event.Touch.TouchDispositionsBeforePageLoad", TouchEve ntDispatchResultTypeMax));
3887 touchDispositionsBeforePageLoadHistogram.count((domDispatchR esult != DispatchEventResult::NotCanceled) ? HandledTouches : UnhandledTouches);
3888 }
3889 }
3890 eventResult = mergeEventResult(eventResult, toWebInputEventResult(do mDispatchResult));
3891 }
3892 }
3893 return eventResult;
3894 }
3895
3896 WebInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEvent& eve nt) 3638 WebInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEvent& eve nt)
3897 { 3639 {
3898 TRACE_EVENT0("blink", "EventHandler::handleTouchEvent"); 3640 TRACE_EVENT0("blink", "EventHandler::handleTouchEvent");
3899 3641
3900 if (event.type() == PlatformEvent::TouchScrollStarted) { 3642 return m_pointerEventManager.handleTouchEvents(event);
3901 m_pointerEventManager.blockTouchPointers();
3902 return WebInputEventResult::HandledSystem;
3903 }
3904
3905 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3906
3907 bool newTouchSequence = true;
3908 bool allTouchReleased = true;
3909 for (unsigned i = 0; i < points.size(); ++i) {
3910 const PlatformTouchPoint& point = points[i];
3911
3912 if (point.state() != PlatformTouchPoint::TouchPressed)
3913 newTouchSequence = false;
3914 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3915 allTouchReleased = false;
3916 }
3917
3918 if (newTouchSequence) {
3919 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3920 // have cleared the active document when we saw the last release. But we
3921 // have some tests that violate this, ClusterFuzz could trigger it, and
3922 // there may be cases where the browser doesn't reliably release all
3923 // touches. http://crbug.com/345372 tracks this.
3924 m_touchSequenceDocument.clear();
3925 m_touchSequenceUserGestureToken.clear();
3926 m_pointerEventManager.unblockTouchPointers();
3927 }
3928
3929 ASSERT(m_frame->view());
3930 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) {
3931 // If the active touch document has no frame or view, it's probably bein g destroyed
3932 // so we can't dispatch events.
3933 return WebInputEventResult::NotHandled;
3934 }
3935
3936 // First do hit tests for any new touch points.
3937 for (unsigned i = 0; i < points.size(); ++i) {
3938 const PlatformTouchPoint& point = points[i];
3939
3940 // Touch events implicitly capture to the touched node, and don't change
3941 // active/hover states themselves (Gesture events do). So we only need
3942 // to hit-test on touchstart, and it can be read-only.
3943 if (point.state() == PlatformTouchPoint::TouchPressed) {
3944 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEv ent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3945 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->rootFram eToContents(point.pos()));
3946 HitTestResult result;
3947 if (!m_touchSequenceDocument) {
3948 result = hitTestResultAtPoint(pagePoint, hitType);
3949 } else if (m_touchSequenceDocument->frame()) {
3950 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocum ent->frame()->view()->rootFrameToContents(point.pos()));
3951 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), framePoint, hitType);
3952 } else {
3953 continue;
3954 }
3955
3956 Node* node = result.innerNode();
3957 if (!node)
3958 continue;
3959
3960 if (isHTMLCanvasElement(node)) {
3961 std::pair<Element*, String> regionInfo = toHTMLCanvasElement(nod e)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame());
3962 if (regionInfo.first)
3963 node = regionInfo.first;
3964 m_regionForTouchID.set(point.id(), regionInfo.second);
3965 }
3966
3967 // Touch events should not go to text nodes
3968 if (node->isTextNode())
3969 node = FlatTreeTraversal::parent(*node);
3970
3971 if (!m_touchSequenceDocument) {
3972 // Keep track of which document should receive all touch events
3973 // in the active sequence. This must be a single document to
3974 // ensure we don't leak Nodes between documents.
3975 m_touchSequenceDocument = &(result.innerNode()->document());
3976 ASSERT(m_touchSequenceDocument->frame()->view());
3977 }
3978
3979 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3980 // since we shouldn't get a touchstart for a touch that's already
3981 // down. However EventSender allows this to be violated and there's
3982 // some tests that take advantage of it. There may also be edge
3983 // cases in the browser where this happens.
3984 // See http://crbug.com/345372.
3985 m_targetForTouchID.set(point.id(), node);
3986
3987 TouchAction effectiveTouchAction = TouchActionUtil::computeEffective TouchAction(*node);
3988 if (effectiveTouchAction != TouchActionAuto)
3989 m_frame->page()->chromeClient().setTouchAction(effectiveTouchAct ion);
3990 }
3991 }
3992
3993 m_touchPressed = !allTouchReleased;
3994
3995 // If there's no document receiving touch events, or no handlers on the
3996 // document set to receive the events, then we can skip all the rest of
3997 // this work.
3998 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) {
3999 if (allTouchReleased) {
4000 m_touchSequenceDocument.clear();
4001 m_touchSequenceUserGestureToken.clear();
4002 }
4003 return WebInputEventResult::NotHandled;
4004 }
4005
4006 // Whether a touch should be considered a "user gesture" or not is a tricky question.
4007 // https://docs.google.com/document/d/1oF1T3O7_E4t1PYHV6gyCwHxOi3ystm0eSL5xZ u7nvOg/edit#
4008 // TODO(rbyers): Disable user gesture in some cases but retain logging for n ow (crbug.com/582140).
4009 OwnPtr<UserGestureIndicator> gestureIndicator;
4010 if (event.touchPoints().size() == 1
4011 && event.touchPoints()[0].state() == PlatformTouchPoint::TouchReleased
4012 && !event.causesScrollingIfUncanceled()) {
4013 // This is a touchend corresponding to a tap, definitely a user gesture. So don't supply
4014 // a UserGestureUtilizedCallback.
4015 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessin gUserGesture));
4016 } else {
4017 // This is some other touch event that perhaps shouldn't be considered a user gesture. So
4018 // use a UserGestureUtilizedCallback to get metrics / deprecation warnin gs.
4019 if (m_touchSequenceUserGestureToken)
4020 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequence UserGestureToken.release(), &m_touchSequenceDocument->frame()->eventHandler()));
4021 else
4022 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProce ssingUserGesture, &m_touchSequenceDocument->frame()->eventHandler()));
4023 m_touchSequenceUserGestureToken = UserGestureIndicator::currentToken();
4024 }
4025
4026 // Compute and store the common info used by both PointerEvent and TouchEven t.
4027 HeapVector<TouchInfo> touchInfos(points.size());
4028
4029 for (unsigned i = 0; i < points.size(); ++i) {
4030 const PlatformTouchPoint& point = points[i];
4031 PlatformTouchPoint::TouchState pointState = point.state();
4032 EventTarget* touchTarget = nullptr;
4033 String regionID;
4034
4035 if (pointState == PlatformTouchPoint::TouchReleased || pointState == Pla tformTouchPoint::TouchCancelled) {
4036 // The target should be the original target for this touch, so get
4037 // it from the hashmap. As it's a release or cancel we also remove
4038 // it from the map.
4039 touchTarget = m_targetForTouchID.take(point.id());
4040 regionID = m_regionForTouchID.take(point.id());
4041 } else {
4042 // No hittest is performed on move or stationary, since the target
4043 // is not allowed to change anyway.
4044 touchTarget = m_targetForTouchID.get(point.id());
4045 regionID = m_regionForTouchID.get(point.id());
4046 }
4047
4048 LocalFrame* targetFrame = nullptr;
4049 bool knownTarget = false;
4050 if (touchTarget) {
4051 Document& doc = touchTarget->toNode()->document();
4052 // If the target node has moved to a new document while it was being touched,
4053 // we can't send events to the new document because that could leak nodes
4054 // from one document to another. See http://crbug.com/394339.
4055 if (&doc == m_touchSequenceDocument.get()) {
4056 targetFrame = doc.frame();
4057 knownTarget = true;
4058 }
4059 }
4060 if (!knownTarget) {
4061 // If we don't have a target registered for the point it means we've
4062 // missed our opportunity to do a hit test for it (due to some
4063 // optimization that prevented blink from ever seeing the
4064 // touchstart), or that the touch started outside the active touch
4065 // sequence document. We should still include the touch in the
4066 // Touches list reported to the application (eg. so it can
4067 // differentiate between a one and two finger gesture), but we won't
4068 // actually dispatch any events for it. Set the target to the
4069 // Document so that there's some valid node here. Perhaps this
4070 // should really be LocalDOMWindow, but in all other cases the targe t of
4071 // a Touch is a Node so using the window could be a breaking change.
4072 // Since we know there was no handler invoked, the specific target
4073 // should be completely irrelevant to the application.
4074 touchTarget = m_touchSequenceDocument;
4075 targetFrame = m_touchSequenceDocument->frame();
4076 }
4077 ASSERT(targetFrame);
4078
4079 // pagePoint should always be in the target element's document coordinat es.
4080 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents(point.po s());
4081 float scaleFactor = 1.0f / targetFrame->pageZoomFactor();
4082
4083 TouchInfo& touchInfo = touchInfos[i];
4084 touchInfo.point = point;
4085 touchInfo.touchTarget = touchTarget;
4086 touchInfo.targetFrame = targetFrame;
4087 touchInfo.adjustedPagePoint = pagePoint.scaledBy(scaleFactor);
4088 touchInfo.adjustedRadius = point.radius().scaledBy(scaleFactor);
4089 touchInfo.knownTarget = knownTarget;
4090 touchInfo.consumed = false;
4091 touchInfo.region = regionID;
4092 }
4093
4094 dispatchPointerEvents(event, touchInfos);
4095 // Note that the disposition of any pointer events affects only the generati on of touch
4096 // events. If all pointer events were handled (and hence no touch events wer e fired), that
4097 // is still equivalent to the touch events going unhandled because pointer e vent handler
4098 // don't block scroll gesture generation.
4099
4100 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won 't see TEs until after
4101 // scrolling starts because the scrolling would suppress upcoming PEs. This sudden "break" in TE
4102 // suppression can make the visible TEs inconsistent (e.g. touchmove without a touchstart).
4103
4104 return dispatchTouchEvents(event, touchInfos, allTouchReleased);
4105 } 3643 }
4106 3644
4107 void EventHandler::userGestureUtilized() 3645 void EventHandler::userGestureUtilized()
4108 { 3646 {
4109 // This is invoked for UserGestureIndicators created in handleTouchEvent whi ch perhaps represent 3647 // This is invoked for UserGestureIndicators created in handleTouchEvent whi ch perhaps represent
4110 // touch actions which shouldn't be considered a user-gesture. 3648 // touch actions which shouldn't be considered a user-gesture.
4111 UseCounter::count(m_frame, UseCounter::TouchDragUserGestureUsed); 3649 UseCounter::count(m_frame, UseCounter::TouchDragUserGestureUsed);
4112 Deprecation::countDeprecationCrossOriginIframe(m_frame, UseCounter::TouchDra gUserGestureUsedCrossOrigin); 3650 Deprecation::countDeprecationCrossOriginIframe(m_frame, UseCounter::TouchDra gUserGestureUsedCrossOrigin);
4113 } 3651 }
4114 3652
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
4170 3708
4171 FrameHost* EventHandler::frameHost() 3709 FrameHost* EventHandler::frameHost()
4172 { 3710 {
4173 if (!m_frame->page()) 3711 if (!m_frame->page())
4174 return nullptr; 3712 return nullptr;
4175 3713
4176 return &m_frame->page()->frameHost(); 3714 return &m_frame->page()->frameHost();
4177 } 3715 }
4178 3716
4179 } // namespace blink 3717 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/input/EventHandler.h ('k') | third_party/WebKit/Source/core/input/PointerEventManager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698