Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: content/browser/renderer_host/input/touch_event_queue.cc

Issue 872633005: Stop sending an async touchmove for the app slop region (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/touch_event_queue.h" 5 #include "content/browser/renderer_host/input/touch_event_queue.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "content/browser/renderer_host/input/timeout_monitor.h" 10 #include "content/browser/renderer_host/input/timeout_monitor.h"
11 #include "content/common/input/web_touch_event_traits.h" 11 #include "content/common/input/web_touch_event_traits.h"
12 #include "ui/gfx/geometry/point_f.h" 12 #include "ui/gfx/geometry/point_f.h"
13 13
14 using blink::WebInputEvent; 14 using blink::WebInputEvent;
15 using blink::WebTouchEvent; 15 using blink::WebTouchEvent;
16 using blink::WebTouchPoint; 16 using blink::WebTouchPoint;
17 using ui::LatencyInfo; 17 using ui::LatencyInfo;
18 18
19 namespace content { 19 namespace content {
20 namespace { 20 namespace {
21 21
22 // Time interval at which touchmove events will be forwarded to the client while 22 // Time interval at which touchmove events will be forwarded to the client while
23 // scrolling is active and possible. 23 // scrolling is active and possible.
24 const double kAsyncTouchMoveIntervalSec = .2; 24 const double kAsyncTouchMoveIntervalSec = .2;
25 25
26 // A slop region just larger than that used by many web applications. When
27 // touchmove's are being sent asynchronously, movement outside this region will
28 // trigger an immediate async touchmove to cancel potential tap-related logic.
29 const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.;
30
31 // A sanity check on touches received to ensure that touch movement outside 26 // A sanity check on touches received to ensure that touch movement outside
32 // the platform slop region will cause scrolling, as indicated by the event's 27 // the platform slop region will cause scrolling, as indicated by the event's
33 // |causesScrollingIfUncanceled| bit. 28 // |causesScrollingIfUncanceled| bit.
34 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; 29 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.;
35 30
36 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( 31 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent(
37 const TouchEventWithLatencyInfo& event_to_cancel) { 32 const TouchEventWithLatencyInfo& event_to_cancel) {
38 TouchEventWithLatencyInfo event = event_to_cancel; 33 TouchEventWithLatencyInfo event = event_to_cancel;
39 WebTouchEventTraits::ResetTypeAndTouchStates( 34 WebTouchEventTraits::ResetTypeAndTouchStates(
40 WebInputEvent::TouchCancel, 35 WebInputEvent::TouchCancel,
41 // TODO(rbyers): Shouldn't we use a fresh timestamp? 36 // TODO(rbyers): Shouldn't we use a fresh timestamp?
42 event.event.timeStampSeconds, 37 event.event.timeStampSeconds,
43 &event.event); 38 &event.event);
44 return event; 39 return event;
45 } 40 }
46 41
47 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) { 42 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
48 return (event.type == WebInputEvent::TouchStart || 43 return (event.type == WebInputEvent::TouchStart ||
49 event.type == WebInputEvent::TouchMove) && 44 event.type == WebInputEvent::TouchMove) &&
50 !WebInputEventTraits::IgnoresAckDisposition(event); 45 !WebInputEventTraits::IgnoresAckDisposition(event);
51 } 46 }
52 47
53 bool OutsideApplicationSlopRegion(const WebTouchEvent& event,
54 const gfx::PointF& anchor) {
55 return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() >
56 kApplicationSlopRegionLengthDipsSqared;
57 }
58
59 } // namespace 48 } // namespace
60 49
61 50
62 // Cancels a touch sequence if a touchstart or touchmove ack response is 51 // Cancels a touch sequence if a touchstart or touchmove ack response is
63 // sufficiently delayed. 52 // sufficiently delayed.
64 class TouchEventQueue::TouchTimeoutHandler { 53 class TouchEventQueue::TouchTimeoutHandler {
65 public: 54 public:
66 TouchTimeoutHandler(TouchEventQueue* touch_queue, 55 TouchTimeoutHandler(TouchEventQueue* touch_queue,
67 base::TimeDelta timeout_delay) 56 base::TimeDelta timeout_delay)
68 : touch_queue_(touch_queue), 57 : touch_queue_(touch_queue),
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 350
362 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, 351 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
363 const Config& config) 352 const Config& config)
364 : client_(client), 353 : client_(client),
365 dispatching_touch_ack_(NULL), 354 dispatching_touch_ack_(NULL),
366 dispatching_touch_(false), 355 dispatching_touch_(false),
367 has_handlers_(true), 356 has_handlers_(true),
368 drop_remaining_touches_in_sequence_(false), 357 drop_remaining_touches_in_sequence_(false),
369 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), 358 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor),
370 send_touch_events_async_(false), 359 send_touch_events_async_(false),
371 needs_async_touchmove_for_outer_slop_region_(false),
372 last_sent_touch_timestamp_sec_(0), 360 last_sent_touch_timestamp_sec_(0),
373 touch_scrolling_mode_(config.touch_scrolling_mode) { 361 touch_scrolling_mode_(config.touch_scrolling_mode) {
374 DCHECK(client); 362 DCHECK(client);
375 if (config.touch_ack_timeout_supported) { 363 if (config.touch_ack_timeout_supported) {
376 timeout_handler_.reset( 364 timeout_handler_.reset(
377 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); 365 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
378 } 366 }
379 } 367 }
380 368
381 TouchEventQueue::~TouchEventQueue() { 369 TouchEventQueue::~TouchEventQueue() {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 DCHECK(!dispatching_touch_); 452 DCHECK(!dispatching_touch_);
465 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event(); 453 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
466 454
467 if (send_touch_events_async_ && 455 if (send_touch_events_async_ &&
468 touch.event.type == WebInputEvent::TouchMove) { 456 touch.event.type == WebInputEvent::TouchMove) {
469 // Throttling touchmove's in a continuous touchmove stream while scrolling 457 // Throttling touchmove's in a continuous touchmove stream while scrolling
470 // reduces the risk of jank. However, it's still important that the web 458 // reduces the risk of jank. However, it's still important that the web
471 // application be sent touches at key points in the gesture stream, 459 // application be sent touches at key points in the gesture stream,
472 // e.g., when the application slop region is exceeded or touchmove 460 // e.g., when the application slop region is exceeded or touchmove
473 // coalescing fails because of different modifiers. 461 // coalescing fails because of different modifiers.
474 const bool send_touchmove_now = 462 bool send_touchmove_now = size() > 1;
475 size() > 1 || 463 send_touchmove_now |= pending_async_touchmove_ &&
476 (touch.event.timeStampSeconds >= 464 !pending_async_touchmove_->CanCoalesceWith(touch);
477 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) || 465 send_touchmove_now |=
478 (needs_async_touchmove_for_outer_slop_region_ && 466 touch.event.timeStampSeconds >=
479 OutsideApplicationSlopRegion(touch.event, 467 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec;
480 touch_sequence_start_position_)) ||
481 (pending_async_touchmove_ &&
482 !pending_async_touchmove_->CanCoalesceWith(touch));
483 468
484 if (!send_touchmove_now) { 469 if (!send_touchmove_now) {
485 if (!pending_async_touchmove_) { 470 if (!pending_async_touchmove_) {
486 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch)); 471 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch));
487 } else { 472 } else {
488 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch)); 473 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch));
489 pending_async_touchmove_->CoalesceWith(touch); 474 pending_async_touchmove_->CoalesceWith(touch);
490 } 475 }
491 DCHECK_EQ(1U, size()); 476 DCHECK_EQ(1U, size());
492 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); 477 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 !drop_remaining_touches_in_sequence_ && 531 !drop_remaining_touches_in_sequence_ &&
547 touch_consumer_states_.is_empty()) { 532 touch_consumer_states_.is_empty()) {
548 // If no touch points have a consumer, prevent all subsequent touch events 533 // If no touch points have a consumer, prevent all subsequent touch events
549 // received during the scroll from reaching the renderer. This ensures 534 // received during the scroll from reaching the renderer. This ensures
550 // that the first touchstart the renderer sees in any given sequence can 535 // that the first touchstart the renderer sees in any given sequence can
551 // always be preventDefault'ed (cancelable == true). 536 // always be preventDefault'ed (cancelable == true).
552 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable. 537 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable.
553 drop_remaining_touches_in_sequence_ = true; 538 drop_remaining_touches_in_sequence_ = true;
554 } 539 }
555 540
556 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { 541 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
557 needs_async_touchmove_for_outer_slop_region_ = true;
558 pending_async_touchmove_.reset(); 542 pending_async_touchmove_.reset();
559 }
560 543
561 return; 544 return;
562 } 545 }
563 546
564 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate) 547 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
565 return; 548 return;
566 549
567 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) 550 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
568 send_touch_events_async_ = true; 551 send_touch_events_async_ = true;
569 552
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) 585 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate)
603 return; 586 return;
604 587
605 // Throttle sending touchmove events as long as the scroll events are handled. 588 // Throttle sending touchmove events as long as the scroll events are handled.
606 // Note that there's no guarantee that this ACK is for the most recent 589 // Note that there's no guarantee that this ACK is for the most recent
607 // gesture event (or even part of the current sequence). Worst case, the 590 // gesture event (or even part of the current sequence). Worst case, the
608 // delay in updating the absorption state will result in minor UI glitches. 591 // delay in updating the absorption state will result in minor UI glitches.
609 // A valid |pending_async_touchmove_| will be flushed when the next event is 592 // A valid |pending_async_touchmove_| will be flushed when the next event is
610 // forwarded. 593 // forwarded.
611 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); 594 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
612 if (!send_touch_events_async_)
613 needs_async_touchmove_for_outer_slop_region_ = false;
614 } 595 }
615 596
616 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { 597 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
617 DCHECK(!dispatching_touch_ack_); 598 DCHECK(!dispatching_touch_ack_);
618 DCHECK(!dispatching_touch_); 599 DCHECK(!dispatching_touch_);
619 has_handlers_ = has_handlers; 600 has_handlers_ = has_handlers;
620 } 601 }
621 602
622 bool TouchEventQueue::IsPendingAckTouchStart() const { 603 bool TouchEventQueue::IsPendingAckTouchStart() const {
623 DCHECK(!dispatching_touch_ack_); 604 DCHECK(!dispatching_touch_ack_);
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 668
688 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { 669 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
689 DCHECK(!touch_queue_.empty()); 670 DCHECK(!touch_queue_.empty());
690 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); 671 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front());
691 touch_queue_.pop_front(); 672 touch_queue_.pop_front();
692 return event.Pass(); 673 return event.Pass();
693 } 674 }
694 675
695 void TouchEventQueue::SendTouchEventImmediately( 676 void TouchEventQueue::SendTouchEventImmediately(
696 const TouchEventWithLatencyInfo& touch) { 677 const TouchEventWithLatencyInfo& touch) {
697 if (needs_async_touchmove_for_outer_slop_region_) {
698 // Any event other than a touchmove (e.g., touchcancel or secondary
699 // touchstart) after a scroll has started will interrupt the need to send a
700 // an outer slop-region exceeding touchmove.
701 if (touch.event.type != WebInputEvent::TouchMove ||
702 OutsideApplicationSlopRegion(touch.event,
703 touch_sequence_start_position_))
704 needs_async_touchmove_for_outer_slop_region_ = false;
705 }
706
707 client_->SendTouchEventImmediately(touch); 678 client_->SendTouchEventImmediately(touch);
708 } 679 }
709 680
710 TouchEventQueue::PreFilterResult 681 TouchEventQueue::PreFilterResult
711 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { 682 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
712 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) 683 if (timeout_handler_ && timeout_handler_->FilterEvent(event))
713 return ACK_WITH_NO_CONSUMER_EXISTS; 684 return ACK_WITH_NO_CONSUMER_EXISTS;
714 685
715 if (touchmove_slop_suppressor_->FilterEvent(event)) 686 if (touchmove_slop_suppressor_->FilterEvent(event))
716 return ACK_WITH_NOT_CONSUMED; 687 return ACK_WITH_NOT_CONSUMED;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) 742 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
772 touch_consumer_states_.mark_bit(point.id); 743 touch_consumer_states_.mark_bit(point.id);
773 else 744 else
774 touch_consumer_states_.clear_bit(point.id); 745 touch_consumer_states_.clear_bit(point.id);
775 } 746 }
776 } 747 }
777 } 748 }
778 } 749 }
779 750
780 } // namespace content 751 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698