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.adjustedPagePoint, | 177 touchInfo.adjustedPagePoint, |
| 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 if (m_touchSequenceDocument && (!touchInfo.touchNode |
|
dtapuska
2016/05/13 16:51:36
Can we add a comment what the intent of this code
Navid Zolghadr
2016/05/16 20:01:50
Done.
| |
| 275 result = m_frame->eventHandler().hitTestResultAtPoint(pagePoint, hitType); | 271 || &touchInfo.touchNode->document() != m_touchSequenceDocument)) { |
|
mustaq
2016/05/11 14:30:55
Looks like we are not covering this case anymore.
Navid Zolghadr
2016/05/11 16:43:42
We are not. This scenario (which is generally the
| |
| 276 } else if (m_touchSequenceDocument->frame()) { | 272 if (m_touchSequenceDocument->frame()) { |
| 277 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocum ent->frame()->view()->rootFrameToContents(touchInfo.point.pos())); | 273 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceD ocument->frame()->view()->rootFrameToContents(touchInfo.point.pos())); |
| 278 result = EventHandler::hitTestResultInFrame(m_touchSequenceDocum ent->frame(), framePoint, hitType); | 274 result = EventHandler::hitTestResultInFrame(m_touchSequenceD ocument->frame(), framePoint, hitType); |
| 279 } else { | 275 Node* node = result.innerNode(); |
| 276 if (!node) | |
| 277 continue; | |
| 278 if (isHTMLCanvasElement(node)) { | |
| 279 std::pair<Element*, String> regionInfo = toHTMLCanvasEle ment(node)->getControlAndIdIfHitRegionExists(result.pointInInnerNodeFrame()); | |
| 280 if (regionInfo.first) | |
| 281 node = regionInfo.first; | |
| 282 touchInfo.region = regionInfo.second; | |
| 283 } | |
| 284 // Touch events should not go to text nodes. | |
| 285 if (node->isTextNode()) | |
| 286 node = FlatTreeTraversal::parent(*node); | |
| 287 touchInfo.touchNode = node; | |
| 288 } else { | |
| 289 continue; | |
| 290 } | |
| 291 } | |
| 292 if (!touchInfo.touchNode) | |
| 280 continue; | 293 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) { | 294 if (!m_touchSequenceDocument) { |
| 298 // Keep track of which document should receive all touch events | 295 // Keep track of which document should receive all touch events |
| 299 // in the active sequence. This must be a single document to | 296 // in the active sequence. This must be a single document to |
| 300 // ensure we don't leak Nodes between documents. | 297 // ensure we don't leak Nodes between documents. |
| 301 m_touchSequenceDocument = &(touchInfo.touchNode->document()); | 298 m_touchSequenceDocument = &(touchInfo.touchNode->document()); |
| 302 ASSERT(m_touchSequenceDocument->frame()->view()); | 299 ASSERT(m_touchSequenceDocument->frame()->view()); |
| 303 } | 300 } |
| 304 | 301 |
| 305 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) | 302 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) |
| 306 // since we shouldn't get a touchstart for a touch that's already | 303 // since we shouldn't get a touchstart for a touch that's already |
| 307 // down. However EventSender allows this to be violated and there's | 304 // down. However EventSender allows this to be violated and there's |
| 308 // some tests that take advantage of it. There may also be edge | 305 // some tests that take advantage of it. There may also be edge |
| 309 // cases in the browser where this happens. | 306 // cases in the browser where this happens. |
| 310 // See http://crbug.com/345372. | 307 // See http://crbug.com/345372. |
| 311 m_targetForTouchID.set(touchInfo.point.id(), touchInfo.touchNode); | 308 m_targetForTouchID.set(touchInfo.point.id(), touchInfo.touchNode); |
| 312 | 309 |
| 313 m_regionForTouchID.set(touchInfo.point.id(), touchInfo.region); | 310 m_regionForTouchID.set(touchInfo.point.id(), touchInfo.region); |
| 314 | |
| 315 TouchAction effectiveTouchAction = | |
| 316 TouchActionUtil::computeEffectiveTouchAction( | |
| 317 *touchInfo.touchNode); | |
| 318 if (effectiveTouchAction != TouchActionAuto) | |
| 319 m_frame->page()->chromeClient().setTouchAction(effectiveTouchAct ion); | |
| 320 } | 311 } |
| 321 } | 312 } |
| 322 } | 313 } |
| 323 | 314 |
| 324 void TouchEventManager::setAllPropertiesOfTouchInfos( | 315 void TouchEventManager::setAllPropertiesOfTouchInfos( |
| 325 HeapVector<TouchInfo>& touchInfos) | 316 HeapVector<TouchInfo>& touchInfos) |
| 326 { | 317 { |
| 327 for (auto& touchInfo : touchInfos) { | 318 for (auto& touchInfo : touchInfos) { |
| 328 PlatformTouchPoint::TouchState pointState = touchInfo.point.state(); | 319 PlatformTouchPoint::TouchState pointState = touchInfo.point.state(); |
| 329 Node* touchNode = nullptr; | 320 Node* touchNode = nullptr; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 // pagePoint should always be in the target element's document coordinat es. | 368 // pagePoint should always be in the target element's document coordinat es. |
| 378 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( | 369 FloatPoint pagePoint = targetFrame->view()->rootFrameToContents( |
| 379 touchInfo.point.pos()); | 370 touchInfo.point.pos()); |
| 380 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); | 371 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); |
| 381 | 372 |
| 382 touchInfo.touchNode = touchNode; | 373 touchInfo.touchNode = touchNode; |
| 383 touchInfo.targetFrame = targetFrame; | 374 touchInfo.targetFrame = targetFrame; |
| 384 touchInfo.adjustedPagePoint = pagePoint.scaledBy(scaleFactor); | 375 touchInfo.adjustedPagePoint = pagePoint.scaledBy(scaleFactor); |
| 385 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor ); | 376 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor ); |
| 386 touchInfo.knownTarget = knownTarget; | 377 touchInfo.knownTarget = knownTarget; |
| 387 touchInfo.consumed = false; | |
| 388 touchInfo.region = regionID; | 378 touchInfo.region = regionID; |
| 389 } | 379 } |
| 390 } | 380 } |
| 391 | 381 |
| 392 bool TouchEventManager::generateTouchInfosAfterHittest( | 382 bool TouchEventManager::reHitTestTouchPointsIfNeeded( |
| 393 const PlatformTouchEvent& event, | 383 const PlatformTouchEvent& event, |
| 394 HeapVector<TouchInfo>& touchInfos) | 384 HeapVector<TouchInfo>& touchInfos) |
| 395 { | 385 { |
| 396 bool newTouchSequence = true; | 386 bool newTouchSequence = true; |
| 397 bool allTouchesReleased = true; | 387 bool allTouchesReleased = true; |
| 398 | 388 |
| 399 for (const auto& point : event.touchPoints()) { | 389 for (const auto& point : event.touchPoints()) { |
| 400 if (point.state() != PlatformTouchPoint::TouchPressed) | 390 if (point.state() != PlatformTouchPoint::TouchPressed) |
| 401 newTouchSequence = false; | 391 newTouchSequence = false; |
| 402 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) | 392 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled) |
| 403 allTouchesReleased = false; | 393 allTouchesReleased = false; |
| 404 } | 394 } |
| 405 if (newTouchSequence) { | 395 if (newTouchSequence) { |
| 406 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should | 396 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should |
| 407 // have cleared the active document when we saw the last release. But we | 397 // 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 | 398 // have some tests that violate this, ClusterFuzz could trigger it, and |
| 409 // there may be cases where the browser doesn't reliably release all | 399 // there may be cases where the browser doesn't reliably release all |
| 410 // touches. http://crbug.com/345372 tracks this. | 400 // touches. http://crbug.com/345372 tracks this. |
| 411 m_touchSequenceDocument.clear(); | 401 m_touchSequenceDocument.clear(); |
| 412 m_touchSequenceUserGestureToken.clear(); | 402 m_touchSequenceUserGestureToken.clear(); |
| 413 } | 403 } |
| 414 | 404 |
| 415 ASSERT(m_frame->view()); | 405 ASSERT(m_frame->view()); |
| 416 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touc hSequenceDocument->frame()->view())) { | 406 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 | 407 // If the active touch document has no frame or view, it's probably bein g destroyed |
| 418 // so we can't dispatch events. | 408 // so we can't dispatch events. |
| 419 return false; | 409 return false; |
| 420 } | 410 } |
| 421 | 411 |
| 422 for (const auto& point : event.touchPoints()) { | |
| 423 TouchEventManager::TouchInfo touchInfo; | |
| 424 touchInfo.point = point; | |
| 425 touchInfos.append(touchInfo); | |
| 426 } | |
| 427 | |
| 428 updateTargetAndRegionMapsForTouchStarts(touchInfos); | 412 updateTargetAndRegionMapsForTouchStarts(touchInfos); |
| 429 | 413 |
| 430 m_touchPressed = !allTouchesReleased; | 414 m_touchPressed = !allTouchesReleased; |
| 431 | 415 |
| 432 // If there's no document receiving touch events, or no handlers on the | 416 // 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 | 417 // document set to receive the events, then we can skip all the rest of |
| 434 // this work. | 418 // this work. |
| 435 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) { | 419 if (!m_touchSequenceDocument || !m_touchSequenceDocument->frameHost() || !ha sTouchHandlers(m_touchSequenceDocument->frameHost()->eventHandlerRegistry()) || !m_touchSequenceDocument->frame()) { |
| 436 if (allTouchesReleased) { | 420 if (allTouchesReleased) { |
| 437 m_touchSequenceDocument.clear(); | 421 m_touchSequenceDocument.clear(); |
| 438 m_touchSequenceUserGestureToken.clear(); | 422 m_touchSequenceUserGestureToken.clear(); |
| 439 } | 423 } |
| 440 return false; | 424 return false; |
| 441 } | 425 } |
| 442 | 426 |
| 443 setAllPropertiesOfTouchInfos(touchInfos); | 427 setAllPropertiesOfTouchInfos(touchInfos); |
| 444 | 428 |
| 445 return true; | 429 return true; |
| 446 } | 430 } |
| 447 | 431 |
| 448 WebInputEventResult TouchEventManager::handleTouchEvent( | 432 WebInputEventResult TouchEventManager::handleTouchEvent( |
| 449 const PlatformTouchEvent& event, | 433 const PlatformTouchEvent& event, |
| 450 const HeapVector<TouchInfo>& touchInfos) | 434 HeapVector<TouchInfo>& touchInfos) |
| 451 { | 435 { |
| 436 if (!reHitTestTouchPointsIfNeeded(event, touchInfos)) | |
| 437 return WebInputEventResult::NotHandled; | |
| 438 | |
| 452 // Note that the disposition of any pointer events affects only the generati on of touch | 439 // 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 | 440 // 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 | 441 // is still equivalent to the touch events going unhandled because pointer e vent handler |
| 455 // don't block scroll gesture generation. | 442 // don't block scroll gesture generation. |
| 456 | 443 |
| 457 // TODO(crbug.com/507408): If PE handlers always call preventDefault, we won 't see TEs until after | 444 // 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 | 445 // 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). | 446 // suppression can make the visible TEs inconsistent (e.g. touchmove without a touchstart). |
| 460 | 447 |
| 461 bool allTouchesReleased = true; | 448 bool allTouchesReleased = true; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 } | 491 } |
| 505 | 492 |
| 506 DEFINE_TRACE(TouchEventManager) | 493 DEFINE_TRACE(TouchEventManager) |
| 507 { | 494 { |
| 508 visitor->trace(m_frame); | 495 visitor->trace(m_frame); |
| 509 visitor->trace(m_touchSequenceDocument); | 496 visitor->trace(m_touchSequenceDocument); |
| 510 visitor->trace(m_targetForTouchID); | 497 visitor->trace(m_targetForTouchID); |
| 511 } | 498 } |
| 512 | 499 |
| 513 } // namespace blink | 500 } // namespace blink |
| OLD | NEW |