Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/input/TouchEventManager.h" | 5 #include "core/input/TouchEventManager.h" |
| 6 | 6 |
| 7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
| 8 #include "core/events/TouchEvent.h" | 8 #include "core/events/TouchEvent.h" |
| 9 #include "core/frame/EventHandlerRegistry.h" | 9 #include "core/frame/EventHandlerRegistry.h" |
| 10 #include "core/frame/FrameHost.h" | 10 #include "core/frame/FrameHost.h" |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 TargetTouchesHeapMap touchesByTarget; | 162 TargetTouchesHeapMap touchesByTarget; |
| 163 | 163 |
| 164 // Array of touches per state, used to assemble the |changedTouches| list. | 164 // Array of touches per state, used to assemble the |changedTouches| list. |
| 165 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; | 165 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; |
| 166 | 166 |
| 167 for (unsigned i = 0; i < touchInfos.size(); ++i) { | 167 for (unsigned i = 0; i < touchInfos.size(); ++i) { |
| 168 const TouchInfo& touchInfo = touchInfos[i]; | 168 const TouchInfo& touchInfo = touchInfos[i]; |
| 169 const PlatformTouchPoint& point = touchInfo.point; | 169 const PlatformTouchPoint& point = touchInfo.point; |
| 170 PlatformTouchPoint::TouchState pointState = point.state(); | 170 PlatformTouchPoint::TouchState pointState = point.state(); |
| 171 | 171 |
| 172 if (touchInfo.consumed) | |
| 173 continue; | |
| 174 | |
| 175 Touch* touch = Touch::create( | 172 Touch* touch = Touch::create( |
| 176 touchInfo.targetFrame.get(), | 173 touchInfo.targetFrame.get(), |
| 177 touchInfo.touchNode.get(), | 174 touchInfo.touchNode.get(), |
| 178 point.id(), | 175 point.id(), |
| 179 point.screenPos(), | 176 point.screenPos(), |
| 180 touchInfo.contentPoint, | 177 touchInfo.contentPoint, |
| 181 touchInfo.adjustedRadius, | 178 touchInfo.adjustedRadius, |
| 182 point.rotationAngle(), | 179 point.rotationAngle(), |
| 183 point.force(), | 180 point.force(), |
| 184 touchInfo.region); | 181 touchInfo.region); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( | 259 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( |
| 263 HeapVector<TouchInfo>& touchInfos) | 260 HeapVector<TouchInfo>& touchInfos) |
| 264 { | 261 { |
| 265 for (auto& touchInfo : touchInfos) { | 262 for (auto& touchInfo : touchInfos) { |
| 266 // Touch events implicitly capture to the touched node, and don't change | 263 // Touch events implicitly capture to the touched node, and don't change |
| 267 // active/hover states themselves (Gesture events do). So we only need | 264 // active/hover states themselves (Gesture events do). So we only need |
| 268 // to hit-test on touchstart and when the target could be different than | 265 // to hit-test on touchstart and when the target could be different than |
| 269 // the corresponding pointer event target. | 266 // the corresponding pointer event target. |
| 270 if (touchInfo.point.state() == PlatformTouchPoint::TouchPressed) { | 267 if (touchInfo.point.state() == PlatformTouchPoint::TouchPressed) { |
| 271 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEv ent | HitTestRequest::ReadOnly | HitTestRequest::Active; | 268 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEv ent | HitTestRequest::ReadOnly | HitTestRequest::Active; |
| 272 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->rootFram eToContents(touchInfo.point.pos())); | |
| 273 HitTestResult result; | 269 HitTestResult result; |
| 274 if (!m_touchSequenceDocument) { | 270 // For the touchPressed points hit-testing is done in |
| 275 result = m_frame->eventHandler().hitTestResultAtPoint(pagePoint, hitType); | 271 // PointerEventManager. If it was the second touch there is a |
| 276 } else if (m_touchSequenceDocument->frame()) { | 272 // capturing documents for the touch and |m_touchSequenceDocument| |
| 277 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocum ent->frame()->view()->rootFrameToContents(touchInfo.point.pos())); | 273 // is not null. So if PointerEventManager should hit-test again |
| 278 result = EventHandler::hitTestResultInFrame(m_touchSequenceDocum ent->frame(), framePoint, hitType); | 274 // against |m_touchSequenceDocument| if the target set by |
| 279 } else { | 275 // PointerEventManager was either null or not in |
| 276 // |m_touchSequenceDocument|. | |
| 277 if (m_touchSequenceDocument && (!touchInfo.touchNode | |
| 278 || &touchInfo.touchNode->document() != m_touchSequenceDocument)) { | |
| 279 if (m_touchSequenceDocument->frame()) { | |
|
Rick Byers
2016/05/17 14:20:01
this code is mostly copy/paste with the code in Po
Navid Zolghadr
2016/05/17 16:40:44
I have looked at this a little bit more. They do l
Rick Byers
2016/05/18 21:44:52
Sure, thanks!
| |
| 280 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceD ocument->frame()->view()->rootFrameToContents(touchInfo.point.pos())); | |
| 281 result = EventHandler::hitTestResultInFrame(m_touchSequenceD ocument->frame(), framePoint, hitType); | |
| 282 Node* node = result.innerNode(); | |
| 283 if (!node) | |
| 284 continue; | |
| 285 if (isHTMLCanvasElement(node)) { | |
| 286 std::pair<Element*, String> regionInfo = toHTMLCanvasEle ment(node)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame()); | |
| 287 if (regionInfo.first) | |
| 288 node = regionInfo.first; | |
| 289 touchInfo.region = regionInfo.second; | |
| 290 } | |
| 291 // Touch events should not go to text nodes. | |
| 292 if (node->isTextNode()) | |
| 293 node = FlatTreeTraversal::parent(*node); | |
| 294 touchInfo.touchNode = node; | |
| 295 } else { | |
| 296 continue; | |
| 297 } | |
| 298 } | |
| 299 if (!touchInfo.touchNode) | |
| 280 continue; | 300 continue; |
| 281 } | |
| 282 | |
| 283 Node* node = result.innerNode(); | |
| 284 if (!node) | |
| 285 continue; | |
| 286 if (isHTMLCanvasElement(node)) { | |
| 287 std::pair<Element*, String> regionInfo = toHTMLCanvasElement(nod e)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame()); | |
| 288 if (regionInfo.first) | |
| 289 node = regionInfo.first; | |
| 290 touchInfo.region = regionInfo.second; | |
| 291 } | |
| 292 // Touch events should not go to text nodes. | |
| 293 if (node->isTextNode()) | |
| 294 node = FlatTreeTraversal::parent(*node); | |
| 295 touchInfo.touchNode = node; | |
| 296 | |
| 297 if (!m_touchSequenceDocument) { | 301 if (!m_touchSequenceDocument) { |
| 298 // Keep track of which document should receive all touch events | 302 // Keep track of which document should receive all touch events |
| 299 // in the active sequence. This must be a single document to | 303 // in the active sequence. This must be a single document to |
| 300 // ensure we don't leak Nodes between documents. | 304 // ensure we don't leak Nodes between documents. |
| 301 m_touchSequenceDocument = &(touchInfo.touchNode->document()); | 305 m_touchSequenceDocument = &(touchInfo.touchNode->document()); |
| 302 ASSERT(m_touchSequenceDocument->frame()->view()); | 306 ASSERT(m_touchSequenceDocument->frame()->view()); |
| 303 } | 307 } |
| 304 | 308 |
| 305 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) | 309 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) |
| 306 // since we shouldn't get a touchstart for a touch that's already | 310 // since we shouldn't get a touchstart for a touch that's already |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 // pagePoint should always be in the target element's document coordinat es. | 381 // pagePoint should always be in the target element's document coordinat es. |
| 378 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( | 382 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( |
| 379 touchInfo.point.pos()); | 383 touchInfo.point.pos()); |
| 380 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); | 384 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); |
| 381 | 385 |
| 382 touchInfo.touchNode = touchNode; | 386 touchInfo.touchNode = touchNode; |
| 383 touchInfo.targetFrame = targetFrame; | 387 touchInfo.targetFrame = targetFrame; |
| 384 touchInfo.contentPoint = pagePoint.scaledBy(scaleFactor); | 388 touchInfo.contentPoint = pagePoint.scaledBy(scaleFactor); |
| 385 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor ); | 389 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor ); |
| 386 touchInfo.knownTarget = knownTarget; | 390 touchInfo.knownTarget = knownTarget; |
| 387 touchInfo.consumed = false; | |
| 388 touchInfo.region = regionID; | 391 touchInfo.region = regionID; |
| 389 } | 392 } |
| 390 } | 393 } |
| 391 | 394 |
| 392 bool TouchEventManager::generateTouchInfosAfterHittest( | 395 bool TouchEventManager::reHitTestTouchPointsIfNeeded( |
| 393 const PlatformTouchEvent& event, | 396 const PlatformTouchEvent& event, |
| 394 HeapVector<TouchInfo>& touchInfos) | 397 HeapVector<TouchInfo>& touchInfos) |
| 395 { | 398 { |
| 396 bool newTouchSequence = true; | 399 bool newTouchSequence = true; |
| 397 bool allTouchesReleased = true; | 400 bool allTouchesReleased = true; |
| 398 | 401 |
| 399 for (const auto& point : event.touchPoints()) { | 402 for (const auto& point : event.touchPoints()) { |
| 400 if (point.state() != PlatformTouchPoint::TouchPressed) | 403 if (point.state() != PlatformTouchPoint::TouchPressed) |
| 401 newTouchSequence = false; | 404 newTouchSequence = false; |
| 402 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) | 405 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) |
| 403 allTouchesReleased = false; | 406 allTouchesReleased = false; |
| 404 } | 407 } |
| 405 if (newTouchSequence) { | 408 if (newTouchSequence) { |
| 406 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should | 409 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should |
| 407 // have cleared the active document when we saw the last release. But we | 410 // have cleared the active document when we saw the last release. But we |
| 408 // have some tests that violate this, ClusterFuzz could trigger it, and | 411 // have some tests that violate this, ClusterFuzz could trigger it, and |
| 409 // there may be cases where the browser doesn't reliably release all | 412 // there may be cases where the browser doesn't reliably release all |
| 410 // touches. http://crbug.com/345372 tracks this. | 413 // touches. http://crbug.com/345372 tracks this. |
| 411 m_touchSequenceDocument.clear(); | 414 m_touchSequenceDocument.clear(); |
| 412 m_touchSequenceUserGestureToken.clear(); | 415 m_touchSequenceUserGestureToken.clear(); |
| 413 } | 416 } |
| 414 | 417 |
| 415 ASSERT(m_frame->view()); | 418 ASSERT(m_frame->view()); |
| 416 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) { | 419 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) { |
| 417 // If the active touch document has no frame or view, it's probably bein g destroyed | 420 // If the active touch document has no frame or view, it's probably bein g destroyed |
| 418 // so we can't dispatch events. | 421 // so we can't dispatch events. |
| 419 return false; | 422 return false; |
| 420 } | 423 } |
| 421 | 424 |
| 422 for (const auto& point : event.touchPoints()) { | |
| 423 TouchEventManager::TouchInfo touchInfo; | |
| 424 touchInfo.point = point; | |
| 425 touchInfos.append(touchInfo); | |
| 426 } | |
| 427 | |
| 428 updateTargetAndRegionMapsForTouchStarts(touchInfos); | 425 updateTargetAndRegionMapsForTouchStarts(touchInfos); |
| 429 | 426 |
| 430 m_touchPressed = !allTouchesReleased; | 427 m_touchPressed = !allTouchesReleased; |
| 431 | 428 |
| 432 // If there's no document receiving touch events, or no handlers on the | 429 // If there's no document receiving touch events, or no handlers on the |
| 433 // document set to receive the events, then we can skip all the rest of | 430 // document set to receive the events, then we can skip all the rest of |
| 434 // this work. | 431 // this work. |
| 435 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) { | 432 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) { |
| 436 if (allTouchesReleased) { | 433 if (allTouchesReleased) { |
| 437 m_touchSequenceDocument.clear(); | 434 m_touchSequenceDocument.clear(); |
| 438 m_touchSequenceUserGestureToken.clear(); | 435 m_touchSequenceUserGestureToken.clear(); |
| 439 } | 436 } |
| 440 return false; | 437 return false; |
| 441 } | 438 } |
| 442 | 439 |
| 443 setAllPropertiesOfTouchInfos(touchInfos); | 440 setAllPropertiesOfTouchInfos(touchInfos); |
| 444 | 441 |
| 445 return true; | 442 return true; |
| 446 } | 443 } |
| 447 | 444 |
| 448 WebInputEventResult TouchEventManager::handleTouchEvent( | 445 WebInputEventResult TouchEventManager::handleTouchEvent( |
| 449 const PlatformTouchEvent& event, | 446 const PlatformTouchEvent& event, |
| 450 const HeapVector<TouchInfo>& touchInfos) | 447 HeapVector<TouchInfo>& touchInfos) |
| 451 { | 448 { |
| 449 if (!reHitTestTouchPointsIfNeeded(event, touchInfos)) | |
| 450 return WebInputEventResult::NotHandled; | |
| 451 | |
| 452 // Note that the disposition of any pointer events affects only the generati on of touch | 452 // Note that the disposition of any pointer events affects only the generati on of touch |
| 453 // events. If all pointer events were handled (and hence no touch events wer e fired), that | 453 // events. If all pointer events were handled (and hence no touch events wer e fired), that |
| 454 // is still equivalent to the touch events going unhandled because pointer e vent handler | 454 // is still equivalent to the touch events going unhandled because pointer e vent handler |
| 455 // don't block scroll gesture generation. | 455 // don't block scroll gesture generation. |
| 456 | 456 |
| 457 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won 't see TEs until after | 457 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won 't see TEs until after |
| 458 // scrolling starts because the scrolling would suppress upcoming PEs. This sudden "break" in TE | 458 // scrolling starts because the scrolling would suppress upcoming PEs. This sudden "break" in TE |
| 459 // suppression can make the visible TEs inconsistent (e.g. touchmove without a touchstart). | 459 // suppression can make the visible TEs inconsistent (e.g. touchmove without a touchstart). |
| 460 | 460 |
| 461 bool allTouchesReleased = true; | 461 bool allTouchesReleased = true; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 518 } | 518 } |
| 519 | 519 |
| 520 DEFINE_TRACE(TouchEventManager) | 520 DEFINE_TRACE(TouchEventManager) |
| 521 { | 521 { |
| 522 visitor->trace(m_frame); | 522 visitor->trace(m_frame); |
| 523 visitor->trace(m_touchSequenceDocument); | 523 visitor->trace(m_touchSequenceDocument); |
| 524 visitor->trace(m_targetForTouchID); | 524 visitor->trace(m_targetForTouchID); |
| 525 } | 525 } |
| 526 | 526 |
| 527 } // namespace blink | 527 } // namespace blink |
| OLD | NEW |