Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "core/input/TouchEventManager.h" | |
| 6 | |
| 7 #include "core/dom/Document.h" | |
| 8 #include "core/events/TouchEvent.h" | |
| 9 #include "core/frame/EventHandlerRegistry.h" | |
| 10 #include "core/frame/FrameHost.h" | |
| 11 #include "core/frame/FrameView.h" | |
| 12 #include "core/html/HTMLCanvasElement.h" | |
| 13 #include "core/input/EventHandler.h" | |
| 14 #include "core/input/TouchActionUtil.h" | |
| 15 #include "core/page/ChromeClient.h" | |
| 16 #include "core/page/Page.h" | |
| 17 #include "platform/Histogram.h" | |
| 18 #include "platform/PlatformTouchEvent.h" | |
| 19 | |
| 20 | |
| 21 | |
| 22 namespace blink { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 bool hasTouchHandlers(const EventHandlerRegistry& registry) | |
| 27 { | |
| 28 return registry.hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEvent Blocking) | |
| 29 || registry.hasEventHandlers(EventHandlerRegistry::TouchStartOrMoveEvent Passive) | |
| 30 || registry.hasEventHandlers(EventHandlerRegistry::TouchEndOrCancelEvent Blocking) | |
| 31 || registry.hasEventHandlers(EventHandlerRegistry::TouchEndOrCancelEvent Passive); | |
| 32 } | |
| 33 | |
| 34 const AtomicString& touchEventNameForTouchPointState(PlatformTouchPoint::TouchSt ate state) | |
| 35 { | |
| 36 switch (state) { | |
| 37 case PlatformTouchPoint::TouchReleased: | |
| 38 return EventTypeNames::touchend; | |
| 39 case PlatformTouchPoint::TouchCancelled: | |
| 40 return EventTypeNames::touchcancel; | |
| 41 case PlatformTouchPoint::TouchPressed: | |
| 42 return EventTypeNames::touchstart; | |
| 43 case PlatformTouchPoint::TouchMoved: | |
| 44 return EventTypeNames::touchmove; | |
| 45 case PlatformTouchPoint::TouchStationary: | |
| 46 // Fall through to default | |
| 47 default: | |
| 48 ASSERT_NOT_REACHED(); | |
| 49 return emptyAtom; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 // These offsets change indicies into the ListenerHistogram | |
| 54 // enumeration. The addition of a series of offsets then | |
| 55 // produces the resulting ListenerHistogram value. | |
| 56 const size_t kTouchTargetHistogramRootScrollerOffset = 4; | |
| 57 const size_t kTouchTargetHistogramScrollableDocumentOffset = 2; | |
| 58 const size_t kTouchTargetHistogramHandledOffset = 1; | |
| 59 | |
| 60 enum TouchTargetAndDispatchResultType { | |
| 61 NonRootScrollerNonScrollableNotHandled, // Non-root-scroller, non-scrollable document, not handled. | |
| 62 NonRootScrollerNonScrollableHandled, // Non-root-scroller, non-scrollable do cument, handled application. | |
| 63 NonRootScrollerScrollableDocumentNotHandled, // Non-root-scroller, scrollabl e document, not handled. | |
| 64 NonRootScrollerScrollableDocumentHandled, // Non-root-scroller, scrollable d ocument, handled application. | |
| 65 RootScrollerNonScrollableNotHandled, // Root-scroller, non-scrollable docume nt, not handled. | |
| 66 RootScrollerNonScrollableHandled, // Root-scroller, non-scrollable document, handled. | |
| 67 RootScrollerScrollableDocumentNotHandled, // Root-scroller, scrollable docum ent, not handled. | |
| 68 RootScrollerScrollableDocumentHandled, // Root-scroller, scrollable document , handled. | |
| 69 TouchTargetAndDispatchResultTypeMax, | |
| 70 }; | |
| 71 | |
| 72 TouchTargetAndDispatchResultType toTouchTargetHistogramValue(EventTarget* eventT arget, DispatchEventResult dispatchResult) | |
| 73 { | |
| 74 int result = 0; | |
| 75 Document* document = nullptr; | |
| 76 | |
| 77 if (const LocalDOMWindow* domWindow = eventTarget->toLocalDOMWindow()) { | |
| 78 // Treat the window as a root scroller as well. | |
| 79 document = domWindow->document(); | |
| 80 result += kTouchTargetHistogramRootScrollerOffset; | |
| 81 } else if (Node* node = eventTarget->toNode()) { | |
| 82 // Report if the target node is the document or body. | |
| 83 if (node->isDocumentNode() || static_cast<Node*>(node->document().docume ntElement()) == node || static_cast<Node*>(node->document().body()) == node) { | |
| 84 result += kTouchTargetHistogramRootScrollerOffset; | |
| 85 } | |
| 86 document = &node->document(); | |
| 87 } | |
| 88 | |
| 89 if (document) { | |
| 90 FrameView* view = document->view(); | |
| 91 if (view && view->isScrollable()) | |
| 92 result += kTouchTargetHistogramScrollableDocumentOffset; | |
| 93 } | |
| 94 | |
| 95 if (dispatchResult != DispatchEventResult::NotCanceled) | |
| 96 result += kTouchTargetHistogramHandledOffset; | |
| 97 return static_cast<TouchTargetAndDispatchResultType>(result); | |
| 98 } | |
| 99 | |
| 100 } | |
|
dtapuska
2016/04/27 17:07:04
ending comment terminating the namespace " // name
Navid Zolghadr
2016/04/28 15:13:11
Done.
| |
| 101 | |
| 102 TouchEventManager::TouchEventManager(LocalFrame* frame) | |
| 103 : m_frame(frame) | |
| 104 { | |
| 105 clear(); | |
| 106 } | |
| 107 | |
| 108 TouchEventManager::~TouchEventManager() | |
| 109 { | |
| 110 } | |
| 111 | |
| 112 namespace { | |
|
dtapuska
2016/04/27 17:07:05
Why double annonymous namespaces; can we collapse
Navid Zolghadr
2016/04/28 15:13:11
It was the case from EventHandler. So I thought th
| |
| 113 | |
| 114 // Defining this class type local to dispatchTouchEvents() and annotating | |
| 115 // it with STACK_ALLOCATED(), runs into MSVC(VS 2013)'s C4822 warning | |
| 116 // that the local class doesn't provide a local definition for 'operator new'. | |
| 117 // Which it intentionally doesn't and shouldn't. | |
| 118 // | |
| 119 // Work around such toolchain bugginess by lifting out the type, thereby | |
| 120 // taking it out of C4822's reach. | |
| 121 class ChangedTouches final { | |
| 122 STACK_ALLOCATED(); | |
| 123 public: | |
| 124 // The touches corresponding to the particular change state this struct | |
| 125 // instance represents. | |
| 126 Member<TouchList> m_touches; | |
| 127 | |
| 128 using EventTargetSet = HeapHashSet<Member<EventTarget>>; | |
| 129 // Set of targets involved in m_touches. | |
| 130 EventTargetSet m_targets; | |
| 131 }; | |
| 132 | |
| 133 } // namespace | |
| 134 | |
| 135 WebInputEventResult TouchEventManager::dispatchTouchEvents( | |
| 136 const PlatformTouchEvent& event, | |
| 137 const HeapVector<TouchInfo>& touchInfos) | |
| 138 { | |
| 139 bool touchStartOrFirstTouchMove = false; | |
| 140 if (event.type() == PlatformEvent::TouchStart) { | |
| 141 m_waitingForFirstTouchMove = true; | |
| 142 touchStartOrFirstTouchMove = true; | |
| 143 } else if (event.type() == PlatformEvent::TouchMove) { | |
| 144 touchStartOrFirstTouchMove = m_waitingForFirstTouchMove; | |
| 145 m_waitingForFirstTouchMove = false; | |
| 146 } | |
| 147 | |
| 148 // Build up the lists to use for the 'touches', 'targetTouches' and | |
| 149 // 'changedTouches' attributes in the JS event. See | |
| 150 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these | |
| 151 // lists fit together. | |
| 152 | |
| 153 // Holds the complete set of touches on the screen. | |
| 154 TouchList* touches = TouchList::create(); | |
| 155 | |
| 156 // A different view on the 'touches' list above, filtered and grouped by | |
| 157 // event target. Used for the 'targetTouches' list in the JS event. | |
| 158 using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>; | |
| 159 TargetTouchesHeapMap touchesByTarget; | |
| 160 | |
| 161 // Array of touches per state, used to assemble the 'changedTouches' list. | |
| 162 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; | |
| 163 | |
| 164 for (unsigned i = 0; i < touchInfos.size(); ++i) { | |
| 165 const TouchInfo& touchInfo = touchInfos[i]; | |
| 166 const PlatformTouchPoint& point = touchInfo.point; | |
| 167 PlatformTouchPoint::TouchState pointState = point.state(); | |
| 168 | |
| 169 if (touchInfo.consumed) | |
| 170 continue; | |
| 171 | |
| 172 Touch* touch = Touch::create( | |
| 173 touchInfo.targetFrame.get(), | |
| 174 touchInfo.touchNode.get(), | |
| 175 point.id(), | |
| 176 point.screenPos(), | |
| 177 touchInfo.adjustedPagePoint, | |
| 178 touchInfo.adjustedRadius, | |
| 179 point.rotationAngle(), | |
| 180 point.force(), | |
| 181 touchInfo.region); | |
| 182 | |
| 183 // Ensure this target's touch list exists, even if it ends up empty, so | |
| 184 // it can always be passed to TouchEvent::Create below. | |
| 185 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.f ind(touchInfo.touchNode.get()); | |
| 186 if (targetTouchesIterator == touchesByTarget.end()) { | |
| 187 touchesByTarget.set(touchInfo.touchNode.get(), TouchList::create()); | |
| 188 targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get ()); | |
| 189 } | |
| 190 | |
| 191 // touches and targetTouches should only contain information about | |
|
dtapuska
2016/04/27 17:07:04
Refer to variables enclosed in |
Navid Zolghadr
2016/04/28 15:13:11
There was quite a few occurrence of this in this e
| |
| 192 // touches still on the screen, so if this point is released or | |
| 193 // cancelled it will only appear in the changedTouches list. | |
| 194 if (pointState != PlatformTouchPoint::TouchReleased && pointState != Pla tformTouchPoint::TouchCancelled) { | |
| 195 touches->append(touch); | |
| 196 targetTouchesIterator->value->append(touch); | |
| 197 } | |
| 198 | |
| 199 // Now build up the correct list for changedTouches. | |
| 200 // Note that any touches that are in the TouchStationary state (e.g. if | |
|
dtapuska
2016/04/27 17:07:05
ditto
Navid Zolghadr
2016/04/28 15:13:11
Done.
| |
| 201 // the user had several points touched but did not move them all) should | |
| 202 // never be in the changedTouches list so we do not handle them | |
| 203 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 | |
| 204 // for further discussion about the TouchStationary state. | |
| 205 if (pointState != PlatformTouchPoint::TouchStationary && touchInfo.known Target) { | |
| 206 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); | |
| 207 if (!changedTouches[pointState].m_touches) | |
| 208 changedTouches[pointState].m_touches = TouchList::create(); | |
| 209 changedTouches[pointState].m_touches->append(touch); | |
| 210 changedTouches[pointState].m_targets.add(touchInfo.touchNode); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 WebInputEventResult eventResult = WebInputEventResult::NotHandled; | |
| 215 | |
| 216 // Now iterate through the changedTouches list and m_targets within it, send ing | |
| 217 // TouchEvents to the targets as required. | |
| 218 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state ) { | |
| 219 if (!changedTouches[state].m_touches) | |
| 220 continue; | |
| 221 | |
| 222 const AtomicString& eventName(touchEventNameForTouchPointState(static_ca st<PlatformTouchPoint::TouchState>(state))); | |
| 223 for (const auto& eventTarget : changedTouches[state].m_targets) { | |
| 224 EventTarget* touchEventTarget = eventTarget; | |
| 225 TouchEvent* touchEvent = TouchEvent::create( | |
| 226 touches, touchesByTarget.get(touchEventTarget), changedTouches[s tate].m_touches.get(), | |
| 227 eventName, touchEventTarget->toNode()->document().domWindow(), | |
| 228 event.getModifiers(), event.cancelable(), event.causesScrollingI fUncanceled(), event.timestamp()); | |
| 229 | |
| 230 DispatchEventResult domDispatchResult = touchEventTarget->dispatchEv ent(touchEvent); | |
| 231 | |
| 232 // Only report for top level documents with a single touch on | |
| 233 // touch-start or the first touch-move. | |
| 234 if (touchStartOrFirstTouchMove && touchInfos.size() == 1 && event.ca ncelable() && !m_frame->document()->ownerElement()) { | |
| 235 DEFINE_STATIC_LOCAL(EnumerationHistogram, rootDocumentListenerHi stogram, ("Event.Touch.TargetAndDispatchResult", TouchTargetAndDispatchResultTyp eMax)); | |
| 236 rootDocumentListenerHistogram.count(toTouchTargetHistogramValue( eventTarget, domDispatchResult)); | |
| 237 } | |
| 238 eventResult = EventHandler::mergeEventResult(eventResult, | |
| 239 EventHandler::toWebInputEventResult(domDispatchResult)); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 return eventResult; | |
| 244 } | |
| 245 | |
| 246 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( | |
| 247 HeapVector<TouchInfo>& touchInfos) | |
| 248 { | |
| 249 for (auto& touchInfo : touchInfos) { | |
| 250 // Touch events implicitly capture to the touched node, and don't change | |
| 251 // active/hover states themselves (Gesture events do). So we only need | |
| 252 // to hit-test on touchstart and when the target could be different than | |
| 253 // the corresponding pointer event target. | |
| 254 if (touchInfo.point.state() == PlatformTouchPoint::TouchPressed) { | |
| 255 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEv ent | HitTestRequest::ReadOnly | HitTestRequest::Active; | |
| 256 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->rootFram eToContents(touchInfo.point.pos())); | |
| 257 HitTestResult result; | |
| 258 if (!m_touchSequenceDocument) { | |
| 259 result = m_frame->eventHandler().hitTestResultAtPoint(pagePoint, hitType); | |
| 260 } else if (m_touchSequenceDocument->frame()) { | |
| 261 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocum ent->frame()->view()->rootFrameToContents(touchInfo.point.pos())); | |
| 262 result = EventHandler::hitTestResultInFrame(m_touchSequenceDocum ent->frame(), framePoint, hitType); | |
| 263 } else { | |
| 264 continue; | |
| 265 } | |
| 266 | |
| 267 Node* node = result.innerNode(); | |
| 268 if (!node) | |
| 269 continue; | |
| 270 if (isHTMLCanvasElement(node)) { | |
| 271 std::pair<Element*, String> regionInfo = toHTMLCanvasElement(nod e)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame()); | |
| 272 if (regionInfo.first) | |
| 273 node = regionInfo.first; | |
| 274 touchInfo.region = regionInfo.second; | |
| 275 } | |
| 276 // Touch events should not go to text nodes. | |
| 277 if (node->isTextNode()) | |
| 278 node = FlatTreeTraversal::parent(*node); | |
| 279 touchInfo.touchNode = node; | |
| 280 | |
|
mustaq
2016/04/27 14:36:11
Double empty-lines.
Navid Zolghadr
2016/04/28 15:13:11
Done.
| |
| 281 | |
| 282 if (!m_touchSequenceDocument) { | |
| 283 // Keep track of which document should receive all touch events | |
| 284 // in the active sequence. This must be a single document to | |
| 285 // ensure we don't leak Nodes between documents. | |
| 286 m_touchSequenceDocument = &(touchInfo.touchNode->document()); | |
| 287 ASSERT(m_touchSequenceDocument->frame()->view()); | |
| 288 } | |
| 289 | |
| 290 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) | |
| 291 // since we shouldn't get a touchstart for a touch that's already | |
| 292 // down. However EventSender allows this to be violated and there's | |
| 293 // some tests that take advantage of it. There may also be edge | |
| 294 // cases in the browser where this happens. | |
| 295 // See http://crbug.com/345372. | |
| 296 m_targetForTouchID.set(touchInfo.point.id(), touchInfo.touchNode); | |
| 297 | |
| 298 m_regionForTouchID.set(touchInfo.point.id(), touchInfo.region); | |
| 299 | |
| 300 TouchAction effectiveTouchAction = | |
| 301 TouchActionUtil::computeEffectiveTouchAction( | |
| 302 *touchInfo.touchNode); | |
| 303 if (effectiveTouchAction != TouchActionAuto) | |
| 304 m_frame->page()->chromeClient().setTouchAction(effectiveTouchAct ion); | |
| 305 } | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 void TouchEventManager::setAllPropertiesOfTouchInfos( | |
| 310 HeapVector<TouchInfo>& touchInfos) | |
| 311 { | |
| 312 for (auto& touchInfo : touchInfos) { | |
| 313 PlatformTouchPoint::TouchState pointState = touchInfo.point.state(); | |
| 314 Node* touchNode = nullptr; | |
| 315 String regionID; | |
| 316 | |
| 317 if (pointState == PlatformTouchPoint::TouchReleased | |
| 318 || pointState == PlatformTouchPoint::TouchCancelled) { | |
| 319 // The target should be the original target for this touch, so get | |
| 320 // it from the hashmap. As it's a release or cancel we also remove | |
| 321 // it from the map. | |
| 322 touchNode = m_targetForTouchID.take(touchInfo.point.id()); | |
| 323 regionID = m_regionForTouchID.take(touchInfo.point.id()); | |
| 324 } else { | |
| 325 // No hittest is performed on move or stationary, since the target | |
| 326 // is not allowed to change anyway. | |
| 327 touchNode = m_targetForTouchID.get(touchInfo.point.id()); | |
| 328 regionID = m_regionForTouchID.get(touchInfo.point.id()); | |
| 329 } | |
| 330 | |
| 331 LocalFrame* targetFrame = nullptr; | |
| 332 bool knownTarget = false; | |
| 333 if (touchNode) { | |
| 334 Document& doc = touchNode->document(); | |
| 335 // If the target node has moved to a new document while it was being touched, | |
| 336 // we can't send events to the new document because that could leak nodes | |
| 337 // from one document to another. See http://crbug.com/394339. | |
| 338 if (&doc == m_touchSequenceDocument.get()) { | |
| 339 targetFrame = doc.frame(); | |
| 340 knownTarget = true; | |
| 341 } | |
| 342 } | |
| 343 if (!knownTarget) { | |
| 344 // If we don't have a target registered for the point it means we've | |
| 345 // missed our opportunity to do a hit test for it (due to some | |
| 346 // optimization that prevented blink from ever seeing the | |
| 347 // touchstart), or that the touch started outside the active touch | |
| 348 // sequence document. We should still include the touch in the | |
| 349 // Touches list reported to the application (eg. so it can | |
| 350 // differentiate between a one and two finger gesture), but we won't | |
| 351 // actually dispatch any events for it. Set the target to the | |
| 352 // Document so that there's some valid node here. Perhaps this | |
| 353 // should really be LocalDOMWindow, but in all other cases the targe t of | |
| 354 // a Touch is a Node so using the window could be a breaking change. | |
| 355 // Since we know there was no handler invoked, the specific target | |
| 356 // should be completely irrelevant to the application. | |
| 357 touchNode = m_touchSequenceDocument; | |
| 358 targetFrame = m_touchSequenceDocument->frame(); | |
| 359 } | |
| 360 ASSERT(targetFrame); | |
| 361 | |
| 362 // pagePoint should always be in the target element's document coordinat es. | |
| 363 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( | |
| 364 touchInfo.point.pos()); | |
| 365 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); | |
| 366 | |
| 367 touchInfo.touchNode = touchNode; | |
| 368 touchInfo.targetFrame = targetFrame; | |
| 369 touchInfo.adjustedPagePoint = pagePoint.scaledBy(scaleFactor); | |
| 370 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor ); | |
| 371 touchInfo.knownTarget = knownTarget; | |
| 372 touchInfo.consumed = false; | |
| 373 touchInfo.region = regionID; | |
| 374 } | |
| 375 } | |
| 376 | |
| 377 bool TouchEventManager::generateTouchInfos( | |
|
mustaq
2016/04/27 14:36:11
Make the hittesting explicit in the name here so t
Navid Zolghadr
2016/04/28 15:13:11
Done.
| |
| 378 const PlatformTouchEvent& event, | |
| 379 HeapVector<TouchInfo>& touchInfos) | |
| 380 { | |
| 381 bool newTouchSequence = true; | |
| 382 bool allTouchReleased = true; | |
| 383 | |
| 384 for (const auto& point : event.touchPoints()) { | |
| 385 if (point.state() != PlatformTouchPoint::TouchPressed) | |
| 386 newTouchSequence = false; | |
| 387 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) | |
| 388 allTouchReleased = false; | |
| 389 } | |
| 390 if (newTouchSequence) { | |
| 391 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should | |
| 392 // have cleared the active document when we saw the last release. But we | |
| 393 // have some tests that violate this, ClusterFuzz could trigger it, and | |
| 394 // there may be cases where the browser doesn't reliably release all | |
| 395 // touches. http://crbug.com/345372 tracks this. | |
| 396 m_touchSequenceDocument.clear(); | |
| 397 m_touchSequenceUserGestureToken.clear(); | |
| 398 } | |
| 399 | |
| 400 ASSERT(m_frame->view()); | |
| 401 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) { | |
| 402 // If the active touch document has no frame or view, it's probably bein g destroyed | |
| 403 // so we can't dispatch events. | |
| 404 return false; | |
| 405 } | |
| 406 | |
| 407 for (const auto& point : event.touchPoints()) { | |
| 408 TouchEventManager::TouchInfo touchInfo; | |
| 409 touchInfo.point = point; | |
| 410 touchInfos.append(touchInfo); | |
| 411 } | |
| 412 | |
| 413 updateTargetAndRegionMapsForTouchStarts(touchInfos); | |
| 414 | |
| 415 m_touchPressed = !allTouchReleased; | |
| 416 | |
| 417 // If there's no document receiving touch events, or no handlers on the | |
| 418 // document set to receive the events, then we can skip all the rest of | |
| 419 // this work. | |
| 420 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) { | |
| 421 if (allTouchReleased) { | |
| 422 m_touchSequenceDocument.clear(); | |
| 423 m_touchSequenceUserGestureToken.clear(); | |
| 424 } | |
| 425 return false; | |
| 426 } | |
| 427 | |
| 428 // Whether a touch should be considered a "user gesture" or not is a tricky question. | |
| 429 // https://docs.google.com/document/d/1oF1T3O7_E4t1PYHV6gyCwHxOi3ystm0eSL5xZ u7nvOg/edit# | |
| 430 // TODO(rbyers): Disable user gesture in some cases but retain logging for n ow (crbug.com/582140). | |
| 431 OwnPtr<UserGestureIndicator> gestureIndicator; | |
| 432 if (event.touchPoints().size() == 1 | |
| 433 && event.touchPoints()[0].state() == PlatformTouchPoint::TouchReleased | |
| 434 && !event.causesScrollingIfUncanceled()) { | |
| 435 // This is a touchend corresponding to a tap, definitely a user gesture. So don't supply | |
| 436 // a UserGestureUtilizedCallback. | |
| 437 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessin gUserGesture)); | |
| 438 } else { | |
| 439 // This is some other touch event that perhaps shouldn't be considered a user gesture. So | |
| 440 // use a UserGestureUtilizedCallback to get metrics / deprecation warnin gs. | |
| 441 if (m_touchSequenceUserGestureToken) | |
| 442 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequence UserGestureToken.release(), &m_touchSequenceDocument->frame()->eventHandler())); | |
| 443 else | |
| 444 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProce ssingUserGesture, &m_touchSequenceDocument->frame()->eventHandler())); | |
| 445 m_touchSequenceUserGestureToken = UserGestureIndicator::currentToken(); | |
| 446 } | |
| 447 | |
| 448 setAllPropertiesOfTouchInfos(touchInfos); | |
| 449 | |
| 450 if (allTouchReleased) { | |
| 451 m_touchSequenceDocument.clear(); | |
| 452 m_touchSequenceUserGestureToken.clear(); | |
| 453 } | |
| 454 | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 WebInputEventResult TouchEventManager::handleTouchEvent( | |
| 459 const PlatformTouchEvent& event, | |
| 460 const HeapVector<TouchInfo>& touchInfos) | |
| 461 { | |
| 462 // Note that the disposition of any pointer events affects only the generati on of touch | |
| 463 // events. If all pointer events were handled (and hence no touch events wer e fired), that | |
| 464 // is still equivalent to the touch events going unhandled because pointer e vent handler | |
| 465 // don't block scroll gesture generation. | |
| 466 | |
| 467 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won 't see TEs until after | |
| 468 // scrolling starts because the scrolling would suppress upcoming PEs. This sudden "break" in TE | |
| 469 // suppression can make the visible TEs inconsistent (e.g. touchmove without a touchstart). | |
| 470 | |
| 471 return dispatchTouchEvents(event, touchInfos); | |
| 472 } | |
| 473 | |
| 474 void TouchEventManager::clear() | |
| 475 { | |
| 476 m_touchSequenceDocument.clear(); | |
| 477 m_touchSequenceUserGestureToken.clear(); | |
| 478 m_targetForTouchID.clear(); | |
| 479 m_regionForTouchID.clear(); | |
| 480 m_touchPressed = false; | |
| 481 m_waitingForFirstTouchMove = false; | |
| 482 } | |
| 483 | |
| 484 bool TouchEventManager::isAnyTouchActive() const | |
| 485 { | |
| 486 return m_touchPressed; | |
| 487 } | |
| 488 | |
| 489 DEFINE_TRACE(TouchEventManager) | |
| 490 { | |
| 491 visitor->trace(m_frame); | |
| 492 visitor->trace(m_touchSequenceDocument); | |
| 493 visitor->trace(m_targetForTouchID); | |
| 494 } | |
| 495 | |
| 496 } // namespace blink | |
| OLD | NEW |