| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/browser/renderer_host/input/legacy_touch_event_queue.h" | 5 #include "content/browser/renderer_host/input/legacy_touch_event_queue.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 using blink::WebTouchPoint; | 21 using blink::WebTouchPoint; |
| 22 using ui::LatencyInfo; | 22 using ui::LatencyInfo; |
| 23 | 23 |
| 24 namespace content { | 24 namespace content { |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 // Time interval at which touchmove events will be forwarded to the client while | 27 // Time interval at which touchmove events will be forwarded to the client while |
| 28 // scrolling is active and possible. | 28 // scrolling is active and possible. |
| 29 const double kAsyncTouchMoveIntervalSec = .2; | 29 const double kAsyncTouchMoveIntervalSec = .2; |
| 30 | 30 |
| 31 // A sanity check on touches received to ensure that touch movement outside | |
| 32 // the platform slop region will cause scrolling. | |
| 33 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; | |
| 34 | |
| 35 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | 31 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
| 36 const TouchEventWithLatencyInfo& event_to_cancel) { | 32 const TouchEventWithLatencyInfo& event_to_cancel) { |
| 37 TouchEventWithLatencyInfo event = event_to_cancel; | 33 TouchEventWithLatencyInfo event = event_to_cancel; |
| 38 WebTouchEventTraits::ResetTypeAndTouchStates( | 34 WebTouchEventTraits::ResetTypeAndTouchStates( |
| 39 WebInputEvent::TouchCancel, | 35 WebInputEvent::TouchCancel, |
| 40 // TODO(rbyers): Shouldn't we use a fresh timestamp? | 36 // TODO(rbyers): Shouldn't we use a fresh timestamp? |
| 41 event.event.timeStampSeconds(), &event.event); | 37 event.event.timeStampSeconds(), &event.event); |
| 42 return event; | 38 return event; |
| 43 } | 39 } |
| 44 | 40 |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 TimeoutMonitor timeout_monitor_; | 268 TimeoutMonitor timeout_monitor_; |
| 273 | 269 |
| 274 bool enabled_; | 270 bool enabled_; |
| 275 bool enabled_for_current_sequence_; | 271 bool enabled_for_current_sequence_; |
| 276 | 272 |
| 277 // Bookkeeping to classify and log whether a touch sequence times out. | 273 // Bookkeeping to classify and log whether a touch sequence times out. |
| 278 bool sequence_awaiting_uma_update_; | 274 bool sequence_awaiting_uma_update_; |
| 279 bool sequence_using_mobile_timeout_; | 275 bool sequence_using_mobile_timeout_; |
| 280 }; | 276 }; |
| 281 | 277 |
| 282 // Provides touchmove slop suppression for a touch sequence until a | |
| 283 // (unprevented) touch will trigger immediate scrolling. | |
| 284 class LegacyTouchEventQueue::TouchMoveSlopSuppressor { | |
| 285 public: | |
| 286 TouchMoveSlopSuppressor() : suppressing_touchmoves_(false) {} | |
| 287 | |
| 288 bool FilterEvent(const WebTouchEvent& event) { | |
| 289 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { | |
| 290 suppressing_touchmoves_ = true; | |
| 291 touch_start_location_ = gfx::PointF(event.touches[0].position); | |
| 292 } | |
| 293 | |
| 294 if (event.type() == WebInputEvent::TouchEnd || | |
| 295 event.type() == WebInputEvent::TouchCancel) | |
| 296 suppressing_touchmoves_ = false; | |
| 297 | |
| 298 if (event.type() != WebInputEvent::TouchMove) | |
| 299 return false; | |
| 300 | |
| 301 if (suppressing_touchmoves_) { | |
| 302 if (event.touchesLength > 1) { | |
| 303 suppressing_touchmoves_ = false; | |
| 304 } else if (event.movedBeyondSlopRegion) { | |
| 305 suppressing_touchmoves_ = false; | |
| 306 } else { | |
| 307 // No sane slop region should be larger than 60 DIPs. | |
| 308 DCHECK_LT( | |
| 309 (gfx::PointF(event.touches[0].position) - touch_start_location_) | |
| 310 .LengthSquared(), | |
| 311 kMaxConceivablePlatformSlopRegionLengthDipsSquared); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 return suppressing_touchmoves_; | |
| 316 } | |
| 317 | |
| 318 void ConfirmTouchEvent(InputEventAckState ack_result) { | |
| 319 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | |
| 320 suppressing_touchmoves_ = false; | |
| 321 } | |
| 322 | |
| 323 bool suppressing_touchmoves() const { return suppressing_touchmoves_; } | |
| 324 | |
| 325 private: | |
| 326 bool suppressing_touchmoves_; | |
| 327 | |
| 328 // Sanity check that the upstream touch provider is properly reporting whether | |
| 329 // the touch sequence will cause scrolling. | |
| 330 gfx::PointF touch_start_location_; | |
| 331 | |
| 332 DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor); | |
| 333 }; | |
| 334 | |
| 335 // This class represents a single coalesced touch event. However, it also keeps | 278 // This class represents a single coalesced touch event. However, it also keeps |
| 336 // track of all the original touch-events that were coalesced into a single | 279 // track of all the original touch-events that were coalesced into a single |
| 337 // event. The coalesced event is forwarded to the renderer, while the original | 280 // event. The coalesced event is forwarded to the renderer, while the original |
| 338 // touch-events are sent to the Client (on ACK for the coalesced event) so that | 281 // touch-events are sent to the Client (on ACK for the coalesced event) so that |
| 339 // the Client receives the event with their original timestamp. | 282 // the Client receives the event with their original timestamp. |
| 340 class CoalescedWebTouchEvent { | 283 class CoalescedWebTouchEvent { |
| 341 public: | 284 public: |
| 342 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, | 285 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, |
| 343 bool suppress_client_ack) | 286 bool suppress_client_ack) |
| 344 : coalesced_event_(event), suppress_client_ack_(suppress_client_ack) { | 287 : coalesced_event_(event), suppress_client_ack_(suppress_client_ack) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 }; | 362 }; |
| 420 | 363 |
| 421 LegacyTouchEventQueue::LegacyTouchEventQueue(TouchEventQueueClient* client, | 364 LegacyTouchEventQueue::LegacyTouchEventQueue(TouchEventQueueClient* client, |
| 422 const Config& config) | 365 const Config& config) |
| 423 : client_(client), | 366 : client_(client), |
| 424 dispatching_touch_ack_(false), | 367 dispatching_touch_ack_(false), |
| 425 dispatching_touch_(false), | 368 dispatching_touch_(false), |
| 426 has_handlers_(true), | 369 has_handlers_(true), |
| 427 has_handler_for_current_sequence_(false), | 370 has_handler_for_current_sequence_(false), |
| 428 drop_remaining_touches_in_sequence_(false), | 371 drop_remaining_touches_in_sequence_(false), |
| 429 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), | |
| 430 send_touch_events_async_(false), | 372 send_touch_events_async_(false), |
| 431 last_sent_touch_timestamp_sec_(0) { | 373 last_sent_touch_timestamp_sec_(0) { |
| 432 if (config.touch_ack_timeout_supported) { | 374 if (config.touch_ack_timeout_supported) { |
| 433 timeout_handler_.reset( | 375 timeout_handler_.reset( |
| 434 new TouchTimeoutHandler(this, config.desktop_touch_ack_timeout_delay, | 376 new TouchTimeoutHandler(this, config.desktop_touch_ack_timeout_delay, |
| 435 config.mobile_touch_ack_timeout_delay)); | 377 config.mobile_touch_ack_timeout_delay)); |
| 436 } | 378 } |
| 437 } | 379 } |
| 438 | 380 |
| 439 LegacyTouchEventQueue::~LegacyTouchEventQueue() {} | 381 LegacyTouchEventQueue::~LegacyTouchEventQueue() {} |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 } | 468 } |
| 527 return; | 469 return; |
| 528 } | 470 } |
| 529 | 471 |
| 530 DCHECK(!dispatching_touch_ack_); | 472 DCHECK(!dispatching_touch_ack_); |
| 531 dispatching_touch_ = false; | 473 dispatching_touch_ = false; |
| 532 | 474 |
| 533 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) | 475 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) |
| 534 return; | 476 return; |
| 535 | 477 |
| 536 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); | |
| 537 | |
| 538 if (touch_queue_.empty()) | 478 if (touch_queue_.empty()) |
| 539 return; | 479 return; |
| 540 | 480 |
| 541 // We don't care about the ordering of the acks vs the ordering of the | 481 // We don't care about the ordering of the acks vs the ordering of the |
| 542 // dispatched events because we can receive the ack for event B before the ack | 482 // dispatched events because we can receive the ack for event B before the ack |
| 543 // for event A even though A was sent before B. This seems to be happening | 483 // for event A even though A was sent before B. This seems to be happening |
| 544 // when, for example, A is acked from renderer but B isn't, so the ack for B | 484 // when, for example, A is acked from renderer but B isn't, so the ack for B |
| 545 // is synthesized "locally" in InputRouter. | 485 // is synthesized "locally" in InputRouter. |
| 546 // | 486 // |
| 547 // TODO(crbug.com/600773): Bring the id checks back when dispatch triggering | 487 // TODO(crbug.com/600773): Bring the id checks back when dispatch triggering |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 std::move(pending_async_touchmove_); | 589 std::move(pending_async_touchmove_); |
| 650 touch->event.dispatchType = WebInputEvent::EventNonBlocking; | 590 touch->event.dispatchType = WebInputEvent::EventNonBlocking; |
| 651 touch_queue_.push_front( | 591 touch_queue_.push_front( |
| 652 base::MakeUnique<CoalescedWebTouchEvent>(*touch, true)); | 592 base::MakeUnique<CoalescedWebTouchEvent>(*touch, true)); |
| 653 SendTouchEventImmediately(touch.get()); | 593 SendTouchEventImmediately(touch.get()); |
| 654 } | 594 } |
| 655 | 595 |
| 656 void LegacyTouchEventQueue::OnGestureScrollEvent( | 596 void LegacyTouchEventQueue::OnGestureScrollEvent( |
| 657 const GestureEventWithLatencyInfo& gesture_event) { | 597 const GestureEventWithLatencyInfo& gesture_event) { |
| 658 if (gesture_event.event.type() == blink::WebInputEvent::GestureScrollBegin) { | 598 if (gesture_event.event.type() == blink::WebInputEvent::GestureScrollBegin) { |
| 659 if (has_handler_for_current_sequence_ && | |
| 660 !drop_remaining_touches_in_sequence_) { | |
| 661 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) | |
| 662 << "A touch handler should be offered a touchmove before scrolling."; | |
| 663 } | |
| 664 | |
| 665 pending_async_touchmove_.reset(); | 599 pending_async_touchmove_.reset(); |
| 666 | 600 |
| 667 return; | 601 return; |
| 668 } | 602 } |
| 669 | 603 |
| 670 if (gesture_event.event.type() == blink::WebInputEvent::GestureScrollUpdate && | 604 if (gesture_event.event.type() == blink::WebInputEvent::GestureScrollUpdate && |
| 671 gesture_event.event.resendingPluginId == -1) { | 605 gesture_event.event.resendingPluginId == -1) { |
| 672 send_touch_events_async_ = true; | 606 send_touch_events_async_ = true; |
| 673 } | 607 } |
| 674 } | 608 } |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 864 drop_remaining_touches_in_sequence_ = false; | 798 drop_remaining_touches_in_sequence_ = false; |
| 865 if (!has_handlers_) { | 799 if (!has_handlers_) { |
| 866 drop_remaining_touches_in_sequence_ = true; | 800 drop_remaining_touches_in_sequence_ = true; |
| 867 return ACK_WITH_NO_CONSUMER_EXISTS; | 801 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 868 } | 802 } |
| 869 } | 803 } |
| 870 | 804 |
| 871 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) | 805 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) |
| 872 return ACK_WITH_NO_CONSUMER_EXISTS; | 806 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 873 | 807 |
| 874 if (touchmove_slop_suppressor_->FilterEvent(event)) | |
| 875 return ACK_WITH_NOT_CONSUMED; | |
| 876 | |
| 877 if (drop_remaining_touches_in_sequence_ && | 808 if (drop_remaining_touches_in_sequence_ && |
| 878 event.type() != WebInputEvent::TouchCancel) { | 809 event.type() != WebInputEvent::TouchCancel) { |
| 879 return ACK_WITH_NO_CONSUMER_EXISTS; | 810 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 880 } | 811 } |
| 881 | 812 |
| 882 if (event.type() == WebInputEvent::TouchStart) { | 813 if (event.type() == WebInputEvent::TouchStart) { |
| 883 return (has_handlers_ || has_handler_for_current_sequence_) | 814 return (has_handlers_ || has_handler_for_current_sequence_) |
| 884 ? FORWARD_TO_RENDERER | 815 ? FORWARD_TO_RENDERER |
| 885 : ACK_WITH_NO_CONSUMER_EXISTS; | 816 : ACK_WITH_NO_CONSUMER_EXISTS; |
| 886 } | 817 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 929 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 860 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
| 930 send_touch_events_async_ = false; | 861 send_touch_events_async_ = false; |
| 931 has_handler_for_current_sequence_ |= | 862 has_handler_for_current_sequence_ |= |
| 932 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | 863 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
| 933 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { | 864 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { |
| 934 has_handler_for_current_sequence_ = false; | 865 has_handler_for_current_sequence_ = false; |
| 935 } | 866 } |
| 936 } | 867 } |
| 937 | 868 |
| 938 } // namespace content | 869 } // namespace content |
| OLD | NEW |