| 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 } |
| 101 |
| 102 TouchEventManager::TouchEventManager(LocalFrame* frame) |
| 103 : m_frame(frame) |
| 104 { |
| 105 clear(); |
| 106 } |
| 107 |
| 108 TouchEventManager::~TouchEventManager() |
| 109 { |
| 110 } |
| 111 |
| 112 namespace { |
| 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 HeapVector<TouchInfo>& touchInfos, |
| 138 bool allTouchReleased) |
| 139 { |
| 140 bool touchStartOrFirstTouchMove = false; |
| 141 if (event.type() == PlatformEvent::TouchStart) { |
| 142 m_waitingForFirstTouchMove = true; |
| 143 touchStartOrFirstTouchMove = true; |
| 144 } else if (event.type() == PlatformEvent::TouchMove) { |
| 145 touchStartOrFirstTouchMove = m_waitingForFirstTouchMove; |
| 146 m_waitingForFirstTouchMove = false; |
| 147 } |
| 148 |
| 149 // Build up the lists to use for the 'touches', 'targetTouches' and |
| 150 // 'changedTouches' attributes in the JS event. See |
| 151 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these |
| 152 // lists fit together. |
| 153 |
| 154 // Holds the complete set of touches on the screen. |
| 155 TouchList* touches = TouchList::create(); |
| 156 |
| 157 // A different view on the 'touches' list above, filtered and grouped by |
| 158 // event target. Used for the 'targetTouches' list in the JS event. |
| 159 using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>; |
| 160 TargetTouchesHeapMap touchesByTarget; |
| 161 |
| 162 // Array of touches per state, used to assemble the 'changedTouches' list. |
| 163 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; |
| 164 |
| 165 for (unsigned i = 0; i < touchInfos.size(); ++i) { |
| 166 const TouchInfo& touchInfo = touchInfos[i]; |
| 167 const PlatformTouchPoint& point = touchInfo.point; |
| 168 PlatformTouchPoint::TouchState pointState = point.state(); |
| 169 |
| 170 Touch* touch = Touch::create( |
| 171 touchInfo.targetFrame.get(), |
| 172 touchInfo.touchNode.get(), |
| 173 point.id(), |
| 174 point.screenPos(), |
| 175 touchInfo.adjustedPagePoint, |
| 176 touchInfo.adjustedRadius, |
| 177 point.rotationAngle(), |
| 178 point.force(), |
| 179 touchInfo.region); |
| 180 |
| 181 // Ensure this target's touch list exists, even if it ends up empty, so |
| 182 // it can always be passed to TouchEvent::Create below. |
| 183 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.f
ind(touchInfo.touchNode.get()); |
| 184 if (targetTouchesIterator == touchesByTarget.end()) { |
| 185 touchesByTarget.set(touchInfo.touchNode.get(), TouchList::create()); |
| 186 targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get
()); |
| 187 } |
| 188 |
| 189 // touches and targetTouches should only contain information about |
| 190 // touches still on the screen, so if this point is released or |
| 191 // cancelled it will only appear in the changedTouches list. |
| 192 if (pointState != PlatformTouchPoint::TouchReleased && pointState != Pla
tformTouchPoint::TouchCancelled) { |
| 193 touches->append(touch); |
| 194 targetTouchesIterator->value->append(touch); |
| 195 } |
| 196 |
| 197 // Now build up the correct list for changedTouches. |
| 198 // Note that any touches that are in the TouchStationary state (e.g. if |
| 199 // the user had several points touched but did not move them all) should |
| 200 // never be in the changedTouches list so we do not handle them |
| 201 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 |
| 202 // for further discussion about the TouchStationary state. |
| 203 if (pointState != PlatformTouchPoint::TouchStationary && touchInfo.known
Target) { |
| 204 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); |
| 205 if (!changedTouches[pointState].m_touches) |
| 206 changedTouches[pointState].m_touches = TouchList::create(); |
| 207 changedTouches[pointState].m_touches->append(touch); |
| 208 changedTouches[pointState].m_targets.add(touchInfo.touchNode); |
| 209 } |
| 210 } |
| 211 if (allTouchReleased) { |
| 212 m_touchSequenceDocument.clear(); |
| 213 m_touchSequenceUserGestureToken.clear(); |
| 214 } |
| 215 |
| 216 WebInputEventResult eventResult = WebInputEventResult::NotHandled; |
| 217 |
| 218 // Now iterate through the changedTouches list and m_targets within it, send
ing |
| 219 // TouchEvents to the targets as required. |
| 220 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state
) { |
| 221 if (!changedTouches[state].m_touches) |
| 222 continue; |
| 223 |
| 224 const AtomicString& eventName(touchEventNameForTouchPointState(static_ca
st<PlatformTouchPoint::TouchState>(state))); |
| 225 for (const auto& eventTarget : changedTouches[state].m_targets) { |
| 226 EventTarget* touchEventTarget = eventTarget; |
| 227 TouchEvent* touchEvent = TouchEvent::create( |
| 228 touches, touchesByTarget.get(touchEventTarget), changedTouches[s
tate].m_touches.get(), |
| 229 eventName, touchEventTarget->toNode()->document().domWindow(), |
| 230 event.getModifiers(), event.cancelable(), event.causesScrollingI
fUncanceled(), event.timestamp()); |
| 231 |
| 232 DispatchEventResult domDispatchResult = touchEventTarget->dispatchEv
ent(touchEvent); |
| 233 |
| 234 // Only report for top level documents with a single touch on |
| 235 // touch-start or the first touch-move. |
| 236 if (touchStartOrFirstTouchMove && touchInfos.size() == 1 && event.ca
ncelable() && !m_frame->document()->ownerElement()) { |
| 237 DEFINE_STATIC_LOCAL(EnumerationHistogram, rootDocumentListenerHi
stogram, ("Event.Touch.TargetAndDispatchResult", TouchTargetAndDispatchResultTyp
eMax)); |
| 238 rootDocumentListenerHistogram.count(toTouchTargetHistogramValue(
eventTarget, domDispatchResult)); |
| 239 } |
| 240 eventResult = EventHandler::mergeEventResult(eventResult, |
| 241 EventHandler::toWebInputEventResult(domDispatchResult)); |
| 242 } |
| 243 } |
| 244 |
| 245 return eventResult; |
| 246 } |
| 247 |
| 248 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( |
| 249 HeapVector<TouchInfo>& touchInfos) |
| 250 { |
| 251 for (auto& touchInfo : touchInfos) { |
| 252 // Touch events implicitly capture to the touched node, and don't change |
| 253 // active/hover states themselves (Gesture events do). So we only need |
| 254 // to hit-test on touchstart and when the target could be different than |
| 255 // the corresponding pointer event target. |
| 256 if (touchInfo.point.state() == PlatformTouchPoint::TouchPressed) { |
| 257 if (m_touchSequenceDocument) { |
| 258 if (!m_touchSequenceDocument->frame()) |
| 259 continue; |
| 260 if (!touchInfo.touchNode || m_touchSequenceDocument.get() |
| 261 != touchInfo.touchNode->document()) { |
| 262 HitTestRequest::HitTestRequestType hitType = HitTestRequest:
:TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active; |
| 263 // Hittest this touch point again as its original hittest fr
ame is different from the first touched frame. |
| 264 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceD
ocument->frame()->view()->rootFrameToContents(touchInfo.point.pos())); |
| 265 HitTestResult result = EventHandler::hitTestResultInFrame(m_
touchSequenceDocument->frame(), framePoint, hitType); |
| 266 Node* node = result.innerNode(); |
| 267 if (!node) |
| 268 continue; |
| 269 if (isHTMLCanvasElement(node)) { |
| 270 std::pair<Element*, String> regionInfo = toHTMLCanvasEle
ment(node)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame()); |
| 271 if (regionInfo.first) |
| 272 node = regionInfo.first; |
| 273 touchInfo.region = regionInfo.second; |
| 274 } |
| 275 // Touch events should not go to text nodes. |
| 276 if (node->isTextNode()) |
| 277 node = FlatTreeTraversal::parent(*node); |
| 278 touchInfo.touchNode = node; |
| 279 } |
| 280 } |
| 281 |
| 282 if (!touchInfo.touchNode) |
| 283 continue; |
| 284 |
| 285 if (!m_touchSequenceDocument) { |
| 286 // Keep track of which document should receive all touch events |
| 287 // in the active sequence. This must be a single document to |
| 288 // ensure we don't leak Nodes between documents. |
| 289 m_touchSequenceDocument = &(touchInfo.touchNode->document()); |
| 290 ASSERT(m_touchSequenceDocument->frame()->view()); |
| 291 } |
| 292 |
| 293 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) |
| 294 // since we shouldn't get a touchstart for a touch that's already |
| 295 // down. However EventSender allows this to be violated and there's |
| 296 // some tests that take advantage of it. There may also be edge |
| 297 // cases in the browser where this happens. |
| 298 // See http://crbug.com/345372. |
| 299 m_targetForTouchID.set(touchInfo.point.id(), touchInfo.touchNode); |
| 300 |
| 301 m_regionForTouchID.set(touchInfo.point.id(), touchInfo.region); |
| 302 |
| 303 TouchAction effectiveTouchAction = |
| 304 TouchActionUtil::computeEffectiveTouchAction( |
| 305 *touchInfo.touchNode); |
| 306 if (effectiveTouchAction != TouchActionAuto) |
| 307 m_frame->page()->chromeClient().setTouchAction(effectiveTouchAct
ion); |
| 308 } |
| 309 } |
| 310 } |
| 311 |
| 312 void TouchEventManager::setAllPropertiesOfTouchInfos( |
| 313 HeapVector<TouchInfo>& touchInfos) |
| 314 { |
| 315 for (auto& touchInfo : touchInfos) { |
| 316 PlatformTouchPoint::TouchState pointState = touchInfo.point.state(); |
| 317 Node* touchNode = nullptr; |
| 318 String regionID; |
| 319 |
| 320 if (pointState == PlatformTouchPoint::TouchReleased |
| 321 || pointState == PlatformTouchPoint::TouchCancelled) { |
| 322 // The target should be the original target for this touch, so get |
| 323 // it from the hashmap. As it's a release or cancel we also remove |
| 324 // it from the map. |
| 325 touchNode = m_targetForTouchID.take(touchInfo.point.id()); |
| 326 regionID = m_regionForTouchID.take(touchInfo.point.id()); |
| 327 } else { |
| 328 // No hittest is performed on move or stationary, since the target |
| 329 // is not allowed to change anyway. |
| 330 touchNode = m_targetForTouchID.get(touchInfo.point.id()); |
| 331 regionID = m_regionForTouchID.get(touchInfo.point.id()); |
| 332 } |
| 333 |
| 334 LocalFrame* targetFrame = nullptr; |
| 335 bool knownTarget = false; |
| 336 if (touchNode) { |
| 337 Document& doc = touchNode->document(); |
| 338 // If the target node has moved to a new document while it was being
touched, |
| 339 // we can't send events to the new document because that could leak
nodes |
| 340 // from one document to another. See http://crbug.com/394339. |
| 341 if (&doc == m_touchSequenceDocument.get()) { |
| 342 targetFrame = doc.frame(); |
| 343 knownTarget = true; |
| 344 } |
| 345 } |
| 346 if (!knownTarget) { |
| 347 // If we don't have a target registered for the point it means we've |
| 348 // missed our opportunity to do a hit test for it (due to some |
| 349 // optimization that prevented blink from ever seeing the |
| 350 // touchstart), or that the touch started outside the active touch |
| 351 // sequence document. We should still include the touch in the |
| 352 // Touches list reported to the application (eg. so it can |
| 353 // differentiate between a one and two finger gesture), but we won't |
| 354 // actually dispatch any events for it. Set the target to the |
| 355 // Document so that there's some valid node here. Perhaps this |
| 356 // should really be LocalDOMWindow, but in all other cases the targe
t of |
| 357 // a Touch is a Node so using the window could be a breaking change. |
| 358 // Since we know there was no handler invoked, the specific target |
| 359 // should be completely irrelevant to the application. |
| 360 touchNode = m_touchSequenceDocument; |
| 361 targetFrame = m_touchSequenceDocument->frame(); |
| 362 } |
| 363 ASSERT(targetFrame); |
| 364 |
| 365 // pagePoint should always be in the target element's document coordinat
es. |
| 366 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( |
| 367 touchInfo.point.pos()); |
| 368 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); |
| 369 |
| 370 touchInfo.touchNode = touchNode; |
| 371 touchInfo.targetFrame = targetFrame; |
| 372 touchInfo.adjustedPagePoint = pagePoint.scaledBy(scaleFactor); |
| 373 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor
); |
| 374 touchInfo.knownTarget = knownTarget; |
| 375 touchInfo.region = regionID; |
| 376 } |
| 377 } |
| 378 |
| 379 WebInputEventResult TouchEventManager::handleTouchEvent( |
| 380 const PlatformTouchEvent& event, |
| 381 HeapVector<TouchInfo>& touchInfos) |
| 382 { |
| 383 bool newTouchSequence = true; |
| 384 bool allTouchReleased = true; |
| 385 |
| 386 for (const auto& point : event.touchPoints()) { |
| 387 if (point.state() != PlatformTouchPoint::TouchPressed) |
| 388 newTouchSequence = false; |
| 389 if (point.state() != PlatformTouchPoint::TouchReleased && point.state()
!= PlatformTouchPoint::TouchCancelled) |
| 390 allTouchReleased = false; |
| 391 } |
| 392 if (newTouchSequence) { |
| 393 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should |
| 394 // have cleared the active document when we saw the last release. But we |
| 395 // have some tests that violate this, ClusterFuzz could trigger it, and |
| 396 // there may be cases where the browser doesn't reliably release all |
| 397 // touches. http://crbug.com/345372 tracks this. |
| 398 m_touchSequenceDocument.clear(); |
| 399 m_touchSequenceUserGestureToken.clear(); |
| 400 } |
| 401 |
| 402 ASSERT(m_frame->view()); |
| 403 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc
hSequenceDocument->frame()->view())) { |
| 404 // If the active touch document has no frame or view, it's probably bein
g destroyed |
| 405 // so we can't dispatch events. |
| 406 return WebInputEventResult::NotHandled; |
| 407 } |
| 408 |
| 409 updateTargetAndRegionMapsForTouchStarts(touchInfos); |
| 410 |
| 411 m_touchPressed = !allTouchReleased; |
| 412 |
| 413 // If there's no document receiving touch events, or no handlers on the |
| 414 // document set to receive the events, then we can skip all the rest of |
| 415 // this work. |
| 416 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha
sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) ||
!m_touchSequenceDocument->frame()) { |
| 417 if (allTouchReleased) { |
| 418 m_touchSequenceDocument.clear(); |
| 419 m_touchSequenceUserGestureToken.clear(); |
| 420 } |
| 421 return WebInputEventResult::NotHandled; |
| 422 } |
| 423 |
| 424 // Whether a touch should be considered a "user gesture" or not is a tricky
question. |
| 425 // https://docs.google.com/document/d/1oF1T3O7_E4t1PYHV6gyCwHxOi3ystm0eSL5xZ
u7nvOg/edit# |
| 426 // TODO(rbyers): Disable user gesture in some cases but retain logging for n
ow (crbug.com/582140). |
| 427 OwnPtr<UserGestureIndicator> gestureIndicator; |
| 428 if (event.touchPoints().size() == 1 |
| 429 && event.touchPoints()[0].state() == PlatformTouchPoint::TouchReleased |
| 430 && !event.causesScrollingIfUncanceled()) { |
| 431 // This is a touchend corresponding to a tap, definitely a user gesture.
So don't supply |
| 432 // a UserGestureUtilizedCallback. |
| 433 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessin
gUserGesture)); |
| 434 } else { |
| 435 // This is some other touch event that perhaps shouldn't be considered a
user gesture. So |
| 436 // use a UserGestureUtilizedCallback to get metrics / deprecation warnin
gs. |
| 437 if (m_touchSequenceUserGestureToken) |
| 438 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequence
UserGestureToken.release(), &m_touchSequenceDocument->frame()->eventHandler())); |
| 439 else |
| 440 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProce
ssingUserGesture, &m_touchSequenceDocument->frame()->eventHandler())); |
| 441 m_touchSequenceUserGestureToken = UserGestureIndicator::currentToken(); |
| 442 } |
| 443 |
| 444 setAllPropertiesOfTouchInfos(touchInfos); |
| 445 |
| 446 // Note that the disposition of any pointer events affects only the generati
on of touch |
| 447 // events. If all pointer events were handled (and hence no touch events wer
e fired), that |
| 448 // is still equivalent to the touch events going unhandled because pointer e
vent handler |
| 449 // don't block scroll gesture generation. |
| 450 |
| 451 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won
't see TEs until after |
| 452 // scrolling starts because the scrolling would suppress upcoming PEs. This
sudden "break" in TE |
| 453 // suppression can make the visible TEs inconsistent (e.g. touchmove without
a touchstart). |
| 454 |
| 455 return dispatchTouchEvents(event, touchInfos, allTouchReleased); |
| 456 } |
| 457 |
| 458 void TouchEventManager::clear() |
| 459 { |
| 460 m_touchSequenceDocument.clear(); |
| 461 m_touchSequenceUserGestureToken.clear(); |
| 462 m_targetForTouchID.clear(); |
| 463 m_regionForTouchID.clear(); |
| 464 m_touchPressed = false; |
| 465 m_waitingForFirstTouchMove = false; |
| 466 } |
| 467 |
| 468 bool TouchEventManager::isAnyTouchActive() |
| 469 { |
| 470 return m_touchPressed; |
| 471 } |
| 472 |
| 473 DEFINE_TRACE(TouchEventManager) |
| 474 { |
| 475 visitor->trace(m_frame); |
| 476 visitor->trace(m_touchSequenceDocument); |
| 477 visitor->trace(m_targetForTouchID); |
| 478 } |
| 479 |
| 480 } // namespace blink |
| OLD | NEW |