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

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

Issue 586553002: Allow repeated handler removal/addition with the TouchEventQueue (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment Created 6 years, 3 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/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "content/browser/renderer_host/input/timeout_monitor.h" 10 #include "content/browser/renderer_host/input/timeout_monitor.h"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 // Cancels a touch sequence if a touchstart or touchmove ack response is 62 // Cancels a touch sequence if a touchstart or touchmove ack response is
63 // sufficiently delayed. 63 // sufficiently delayed.
64 class TouchEventQueue::TouchTimeoutHandler { 64 class TouchEventQueue::TouchTimeoutHandler {
65 public: 65 public:
66 TouchTimeoutHandler(TouchEventQueue* touch_queue, 66 TouchTimeoutHandler(TouchEventQueue* touch_queue,
67 base::TimeDelta timeout_delay) 67 base::TimeDelta timeout_delay)
68 : touch_queue_(touch_queue), 68 : touch_queue_(touch_queue),
69 timeout_delay_(timeout_delay), 69 timeout_delay_(timeout_delay),
70 pending_ack_state_(PENDING_ACK_NONE), 70 pending_ack_state_(PENDING_ACK_NONE),
71 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, 71 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
72 base::Unretained(this))) { 72 base::Unretained(this))),
73 enabled_(true),
74 enabled_for_current_sequence_(false) {
73 DCHECK(timeout_delay != base::TimeDelta()); 75 DCHECK(timeout_delay != base::TimeDelta());
74 } 76 }
75 77
76 ~TouchTimeoutHandler() {} 78 ~TouchTimeoutHandler() {}
77 79
78 void Start(const TouchEventWithLatencyInfo& event) { 80 void StartIfNecessary(const TouchEventWithLatencyInfo& event) {
79 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); 81 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
80 DCHECK(ShouldTouchTriggerTimeout(event.event)); 82 if (!enabled_)
83 return;
84
85 if (!ShouldTouchTriggerTimeout(event.event))
86 return;
87
88 if (WebTouchEventTraits::IsTouchSequenceStart(event.event))
89 enabled_for_current_sequence_ = true;
90
91 if (!enabled_for_current_sequence_)
92 return;
93
81 timeout_event_ = event; 94 timeout_event_ = event;
82 timeout_monitor_.Restart(timeout_delay_); 95 timeout_monitor_.Restart(timeout_delay_);
83 } 96 }
84 97
85 bool ConfirmTouchEvent(InputEventAckState ack_result) { 98 bool ConfirmTouchEvent(InputEventAckState ack_result) {
86 switch (pending_ack_state_) { 99 switch (pending_ack_state_) {
87 case PENDING_ACK_NONE: 100 case PENDING_ACK_NONE:
101 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
102 enabled_for_current_sequence_ = false;
88 timeout_monitor_.Stop(); 103 timeout_monitor_.Stop();
89 return false; 104 return false;
90 case PENDING_ACK_ORIGINAL_EVENT: 105 case PENDING_ACK_ORIGINAL_EVENT:
91 if (AckedTimeoutEventRequiresCancel(ack_result)) { 106 if (AckedTimeoutEventRequiresCancel(ack_result)) {
92 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); 107 SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
93 TouchEventWithLatencyInfo cancel_event = 108 TouchEventWithLatencyInfo cancel_event =
94 ObtainCancelEventForTouchEvent(timeout_event_); 109 ObtainCancelEventForTouchEvent(timeout_event_);
95 touch_queue_->SendTouchEventImmediately(cancel_event); 110 touch_queue_->SendTouchEventImmediately(cancel_event);
96 } else { 111 } else {
97 SetPendingAckState(PENDING_ACK_NONE); 112 SetPendingAckState(PENDING_ACK_NONE);
98 touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result); 113 touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
114 ack_result);
99 } 115 }
100 return true; 116 return true;
101 case PENDING_ACK_CANCEL_EVENT: 117 case PENDING_ACK_CANCEL_EVENT:
102 SetPendingAckState(PENDING_ACK_NONE); 118 SetPendingAckState(PENDING_ACK_NONE);
103 return true; 119 return true;
104 } 120 }
105 return false; 121 return false;
106 } 122 }
107 123
108 bool FilterEvent(const WebTouchEvent& event) { 124 bool FilterEvent(const WebTouchEvent& event) {
109 return HasTimeoutEvent(); 125 return HasTimeoutEvent();
110 } 126 }
111 127
112 bool IsTimeoutTimerRunning() const { 128 void SetEnabled(bool enabled) {
113 return timeout_monitor_.IsRunning(); 129 if (enabled_ == enabled)
130 return;
131
132 enabled_ = enabled;
133
134 if (enabled_)
135 return;
136
137 enabled_for_current_sequence_ = false;
138 // Only reset the |timeout_handler_| if the timer is running and has not
139 // yet timed out. This ensures that an already timed out sequence is
140 // properly flushed by the handler.
141 if (IsTimeoutTimerRunning()) {
142 pending_ack_state_ = PENDING_ACK_NONE;
143 timeout_monitor_.Stop();
144 }
114 } 145 }
115 146
116 void Reset() { 147 bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); }
117 pending_ack_state_ = PENDING_ACK_NONE;
118 timeout_monitor_.Stop();
119 }
120 148
121 void set_timeout_delay(base::TimeDelta timeout_delay) { 149 bool enabled() const { return enabled_; }
122 timeout_delay_ = timeout_delay;
123 }
124 150
125 private: 151 private:
126 enum PendingAckState { 152 enum PendingAckState {
127 PENDING_ACK_NONE, 153 PENDING_ACK_NONE,
128 PENDING_ACK_ORIGINAL_EVENT, 154 PENDING_ACK_ORIGINAL_EVENT,
129 PENDING_ACK_CANCEL_EVENT, 155 PENDING_ACK_CANCEL_EVENT,
130 }; 156 };
131 157
132 void OnTimeOut() { 158 void OnTimeOut() {
133 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT); 159 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 base::TimeDelta timeout_delay_; 203 base::TimeDelta timeout_delay_;
178 204
179 // The touch event source for which we expect the next ack. 205 // The touch event source for which we expect the next ack.
180 PendingAckState pending_ack_state_; 206 PendingAckState pending_ack_state_;
181 207
182 // The event for which the ack timeout is triggered. 208 // The event for which the ack timeout is triggered.
183 TouchEventWithLatencyInfo timeout_event_; 209 TouchEventWithLatencyInfo timeout_event_;
184 210
185 // Provides timeout-based callback behavior. 211 // Provides timeout-based callback behavior.
186 TimeoutMonitor timeout_monitor_; 212 TimeoutMonitor timeout_monitor_;
213
214 bool enabled_;
215 bool enabled_for_current_sequence_;
187 }; 216 };
188 217
189 // Provides touchmove slop suppression for a single touch that remains within 218 // Provides touchmove slop suppression for a single touch that remains within
190 // a given slop region, unless the touchstart is preventDefault'ed. 219 // a given slop region, unless the touchstart is preventDefault'ed.
191 // TODO(jdduke): Use a flag bundled with each TouchEvent declaring whether it 220 // TODO(jdduke): Use a flag bundled with each TouchEvent declaring whether it
192 // has exceeded the slop region, removing duplicated slop determination logic. 221 // has exceeded the slop region, removing duplicated slop determination logic.
193 class TouchEventQueue::TouchMoveSlopSuppressor { 222 class TouchEventQueue::TouchMoveSlopSuppressor {
194 public: 223 public:
195 TouchMoveSlopSuppressor(double slop_suppression_length_dips) 224 TouchMoveSlopSuppressor(double slop_suppression_length_dips)
196 : slop_suppression_length_dips_squared_(0), 225 : slop_suppression_length_dips_squared_(0),
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT), 365 touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
337 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)), 366 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
338 touch_ack_timeout_supported(false) { 367 touch_ack_timeout_supported(false) {
339 } 368 }
340 369
341 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, 370 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
342 const Config& config) 371 const Config& config)
343 : client_(client), 372 : client_(client),
344 dispatching_touch_ack_(NULL), 373 dispatching_touch_ack_(NULL),
345 dispatching_touch_(false), 374 dispatching_touch_(false),
346 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), 375 has_handlers_(true),
347 ack_timeout_enabled_(config.touch_ack_timeout_supported),
348 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( 376 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
349 config.touchmove_slop_suppression_length_dips)), 377 config.touchmove_slop_suppression_length_dips)),
350 send_touch_events_async_(false), 378 send_touch_events_async_(false),
351 needs_async_touchmove_for_outer_slop_region_(false), 379 needs_async_touchmove_for_outer_slop_region_(false),
352 last_sent_touch_timestamp_sec_(0), 380 last_sent_touch_timestamp_sec_(0),
353 touch_scrolling_mode_(config.touch_scrolling_mode) { 381 touch_scrolling_mode_(config.touch_scrolling_mode) {
354 DCHECK(client); 382 DCHECK(client);
355 if (ack_timeout_enabled_) { 383 if (config.touch_ack_timeout_supported) {
356 timeout_handler_.reset( 384 timeout_handler_.reset(
357 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); 385 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
358 } 386 }
359 } 387 }
360 388
361 TouchEventQueue::~TouchEventQueue() { 389 TouchEventQueue::~TouchEventQueue() {
362 if (!touch_queue_.empty()) 390 if (!touch_queue_.empty())
363 STLDeleteElements(&touch_queue_); 391 STLDeleteElements(&touch_queue_);
364 } 392 }
365 393
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 dispatching_touch_ = false; 433 dispatching_touch_ = false;
406 434
407 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) 435 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result))
408 return; 436 return;
409 437
410 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); 438 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result);
411 439
412 if (touch_queue_.empty()) 440 if (touch_queue_.empty())
413 return; 441 return;
414 442
415 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED &&
416 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) {
417 touch_filtering_state_ = FORWARD_ALL_TOUCHES;
418 }
419
420 PopTouchEventToClient(ack_result, latency_info); 443 PopTouchEventToClient(ack_result, latency_info);
421 TryForwardNextEventToRenderer(); 444 TryForwardNextEventToRenderer();
422 } 445 }
423 446
424 void TouchEventQueue::TryForwardNextEventToRenderer() { 447 void TouchEventQueue::TryForwardNextEventToRenderer() {
425 DCHECK(!dispatching_touch_ack_); 448 DCHECK(!dispatching_touch_ack_);
426 // If there are queued touch events, then try to forward them to the renderer 449 // If there are queued touch events, then try to forward them to the renderer
427 // immediately, or ACK the events back to the client if appropriate. 450 // immediately, or ACK the events back to the client if appropriate.
428 while (!touch_queue_.empty()) { 451 while (!touch_queue_.empty()) {
429 PreFilterResult filter_result = 452 PreFilterResult filter_result =
(...skipping 10 matching lines...) Expand all
440 return; 463 return;
441 } 464 }
442 } 465 }
443 } 466 }
444 467
445 void TouchEventQueue::ForwardNextEventToRenderer() { 468 void TouchEventQueue::ForwardNextEventToRenderer() {
446 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer"); 469 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer");
447 470
448 DCHECK(!empty()); 471 DCHECK(!empty());
449 DCHECK(!dispatching_touch_); 472 DCHECK(!dispatching_touch_);
450 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES);
451 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event(); 473 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
452 474
453 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) {
454 touch_filtering_state_ =
455 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT
456 : FORWARD_ALL_TOUCHES;
457 touch_ack_states_.clear();
458 send_touch_events_async_ = false;
459 pending_async_touchmove_.reset();
460 touch_sequence_start_position_ =
461 gfx::PointF(touch.event.touches[0].position);
462 }
463
464 if (send_touch_events_async_ && 475 if (send_touch_events_async_ &&
465 touch.event.type == WebInputEvent::TouchMove) { 476 touch.event.type == WebInputEvent::TouchMove) {
466 // Throttling touchmove's in a continuous touchmove stream while scrolling 477 // Throttling touchmove's in a continuous touchmove stream while scrolling
467 // reduces the risk of jank. However, it's still important that the web 478 // reduces the risk of jank. However, it's still important that the web
468 // application be sent touches at key points in the gesture stream, 479 // application be sent touches at key points in the gesture stream,
469 // e.g., when the application slop region is exceeded or touchmove 480 // e.g., when the application slop region is exceeded or touchmove
470 // coalescing fails because of different modifiers. 481 // coalescing fails because of different modifiers.
471 const bool send_touchmove_now = 482 const bool send_touchmove_now =
472 size() > 1 || 483 size() > 1 ||
473 (touch.event.timeStampSeconds >= 484 (touch.event.timeStampSeconds >=
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 // Note: Marking touchstart events as not-cancelable prevents them from 530 // Note: Marking touchstart events as not-cancelable prevents them from
520 // blocking subsequent gestures, but it may not be the best long term solution 531 // blocking subsequent gestures, but it may not be the best long term solution
521 // for tracking touch point dispatch. 532 // for tracking touch point dispatch.
522 if (send_touch_events_async_) 533 if (send_touch_events_async_)
523 touch.event.cancelable = false; 534 touch.event.cancelable = false;
524 535
525 // A synchronous ack will reset |dispatching_touch_|, in which case 536 // A synchronous ack will reset |dispatching_touch_|, in which case
526 // the touch timeout should not be started. 537 // the touch timeout should not be started.
527 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); 538 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
528 SendTouchEventImmediately(touch); 539 SendTouchEventImmediately(touch);
529 if (dispatching_touch_ && 540 if (dispatching_touch_ && timeout_handler_)
530 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && 541 timeout_handler_->StartIfNecessary(touch);
531 ShouldTouchTriggerTimeout(touch.event)) {
532 DCHECK(timeout_handler_);
533 timeout_handler_->Start(touch);
534 }
535 } 542 }
536 543
537 void TouchEventQueue::OnGestureScrollEvent( 544 void TouchEventQueue::OnGestureScrollEvent(
538 const GestureEventWithLatencyInfo& gesture_event) { 545 const GestureEventWithLatencyInfo& gesture_event) {
539 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { 546 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
540 if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
541 touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
542 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
Rick Byers 2014/09/19 17:54:06 We added this DCHECK because we had at least one n
jdduke (slow) 2014/09/22 16:30:14 Hmm, you're right, I thought it would be tricky bu
543 << "The renderer should be offered a touchmove before scrolling "
544 "begins";
545 }
546
547 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE && 547 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
548 touch_filtering_state_ != DROP_ALL_TOUCHES && 548 !drop_remaining_touches_in_sequence_ &&
549 touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE && 549 touch_consumer_states_.is_empty()) {
550 (touch_ack_states_.empty() ||
551 AllTouchAckStatesHaveState(
552 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))) {
553 // If no touch points have a consumer, prevent all subsequent touch events 550 // If no touch points have a consumer, prevent all subsequent touch events
554 // received during the scroll from reaching the renderer. This ensures 551 // received during the scroll from reaching the renderer. This ensures
555 // that the first touchstart the renderer sees in any given sequence can 552 // that the first touchstart the renderer sees in any given sequence can
556 // always be preventDefault'ed (cancelable == true). 553 // always be preventDefault'ed (cancelable == true).
557 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable. 554 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable.
558 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 555 drop_remaining_touches_in_sequence_ = true;
559 } 556 }
560 557
561 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { 558 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
562 needs_async_touchmove_for_outer_slop_region_ = true; 559 needs_async_touchmove_for_outer_slop_region_ = true;
563 pending_async_touchmove_.reset(); 560 pending_async_touchmove_.reset();
564 } 561 }
565 562
566 return; 563 return;
567 } 564 }
568 565
569 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate) 566 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
570 return; 567 return;
571 568
572 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) 569 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
573 send_touch_events_async_ = true; 570 send_touch_events_async_ = true;
574 571
575 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) 572 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
576 return; 573 return;
577 574
578 // We assume that scroll events are generated synchronously from 575 // We assume that scroll events are generated synchronously from
579 // dispatching a touch event ack. This allows us to generate a synthetic 576 // dispatching a touch event ack. This allows us to generate a synthetic
580 // cancel event that has the same touch ids as the touch event that 577 // cancel event that has the same touch ids as the touch event that
581 // is being acked. Otherwise, we don't perform the touch-cancel optimization. 578 // is being acked. Otherwise, we don't perform the touch-cancel optimization.
582 if (!dispatching_touch_ack_) 579 if (!dispatching_touch_ack_)
583 return; 580 return;
584 581
585 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) 582 if (drop_remaining_touches_in_sequence_)
586 return; 583 return;
587 584
588 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 585 drop_remaining_touches_in_sequence_ = true;
589 586
590 // Fake a TouchCancel to cancel the touch points of the touch event 587 // Fake a TouchCancel to cancel the touch points of the touch event
591 // that is currently being acked. 588 // that is currently being acked.
592 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we 589 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we
593 // are in the scope of PopTouchEventToClient() and that no touch event 590 // are in the scope of PopTouchEventToClient() and that no touch event
594 // in the queue is waiting for ack from renderer. So we can just insert 591 // in the queue is waiting for ack from renderer. So we can just insert
595 // the touch cancel at the beginning of the queue. 592 // the touch cancel at the beginning of the queue.
596 touch_queue_.push_front(new CoalescedWebTouchEvent( 593 touch_queue_.push_front(new CoalescedWebTouchEvent(
597 ObtainCancelEventForTouchEvent( 594 ObtainCancelEventForTouchEvent(
598 dispatching_touch_ack_->coalesced_event()), true)); 595 dispatching_touch_ack_->coalesced_event()), true));
(...skipping 15 matching lines...) Expand all
614 // A valid |pending_async_touchmove_| will be flushed when the next event is 611 // A valid |pending_async_touchmove_| will be flushed when the next event is
615 // forwarded. 612 // forwarded.
616 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); 613 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
617 if (!send_touch_events_async_) 614 if (!send_touch_events_async_)
618 needs_async_touchmove_for_outer_slop_region_ = false; 615 needs_async_touchmove_for_outer_slop_region_ = false;
619 } 616 }
620 617
621 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { 618 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
622 DCHECK(!dispatching_touch_ack_); 619 DCHECK(!dispatching_touch_ack_);
623 DCHECK(!dispatching_touch_); 620 DCHECK(!dispatching_touch_);
624 621 has_handlers_ = has_handlers;
625 if (has_handlers) {
626 if (touch_filtering_state_ == DROP_ALL_TOUCHES) {
627 // If no touch handler was previously registered, ensure that we don't
628 // send a partial touch sequence to the renderer.
629 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
630 }
631 } else {
632 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
633 // state tracking and/or touch-action filtering (e.g., if the touch handler
634 // was removed mid-sequence), crbug.com/375940.
635 touch_filtering_state_ = DROP_ALL_TOUCHES;
636 pending_async_touchmove_.reset();
637 if (timeout_handler_)
638 timeout_handler_->Reset();
639 }
640 } 622 }
641 623
642 bool TouchEventQueue::IsPendingAckTouchStart() const { 624 bool TouchEventQueue::IsPendingAckTouchStart() const {
643 DCHECK(!dispatching_touch_ack_); 625 DCHECK(!dispatching_touch_ack_);
644 if (touch_queue_.empty()) 626 if (touch_queue_.empty())
645 return false; 627 return false;
646 628
647 const blink::WebTouchEvent& event = 629 const blink::WebTouchEvent& event =
648 touch_queue_.front()->coalesced_event().event; 630 touch_queue_.front()->coalesced_event().event;
649 return (event.type == WebInputEvent::TouchStart); 631 return (event.type == WebInputEvent::TouchStart);
650 } 632 }
651 633
652 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) { 634 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) {
653 // The timeout handler is valid only if explicitly supported in the config. 635 if (timeout_handler_)
654 if (!timeout_handler_) 636 timeout_handler_->SetEnabled(enabled);
655 return; 637 }
656 638
657 if (ack_timeout_enabled_ == enabled) 639 bool TouchEventQueue::IsAckTimeoutEnabled() const {
658 return; 640 return timeout_handler_ && timeout_handler_->enabled();
659
660 ack_timeout_enabled_ = enabled;
661
662 if (enabled)
663 return;
664
665 if (touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT)
666 touch_filtering_state_ = FORWARD_ALL_TOUCHES;
667 // Only reset the |timeout_handler_| if the timer is running and has not yet
668 // timed out. This ensures that an already timed out sequence is properly
669 // flushed by the handler.
670 if (timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning())
671 timeout_handler_->Reset();
672 } 641 }
673 642
674 bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const { 643 bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
675 return pending_async_touchmove_; 644 return pending_async_touchmove_;
676 } 645 }
677 646
678 bool TouchEventQueue::IsTimeoutRunningForTesting() const { 647 bool TouchEventQueue::IsTimeoutRunningForTesting() const {
679 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); 648 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning();
680 } 649 }
681 650
682 const TouchEventWithLatencyInfo& 651 const TouchEventWithLatencyInfo&
683 TouchEventQueue::GetLatestEventForTesting() const { 652 TouchEventQueue::GetLatestEventForTesting() const {
684 return touch_queue_.back()->coalesced_event(); 653 return touch_queue_.back()->coalesced_event();
685 } 654 }
686 655
687 void TouchEventQueue::FlushQueue() { 656 void TouchEventQueue::FlushQueue() {
688 DCHECK(!dispatching_touch_ack_); 657 DCHECK(!dispatching_touch_ack_);
689 DCHECK(!dispatching_touch_); 658 DCHECK(!dispatching_touch_);
690 pending_async_touchmove_.reset(); 659 pending_async_touchmove_.reset();
691 if (touch_filtering_state_ != DROP_ALL_TOUCHES) 660 drop_remaining_touches_in_sequence_ = true;
692 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
693 while (!touch_queue_.empty()) 661 while (!touch_queue_.empty())
694 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); 662 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
695 } 663 }
696 664
697 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) { 665 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
698 AckTouchEventToClient(ack_result, PopTouchEvent()); 666 AckTouchEventToClient(ack_result, PopTouchEvent());
699 } 667 }
700 668
701 void TouchEventQueue::PopTouchEventToClient( 669 void TouchEventQueue::PopTouchEventToClient(
702 InputEventAckState ack_result, 670 InputEventAckState ack_result,
703 const LatencyInfo& renderer_latency_info) { 671 const LatencyInfo& renderer_latency_info) {
704 scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent(); 672 scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent();
705 acked_event->UpdateLatencyInfoForAck(renderer_latency_info); 673 acked_event->UpdateLatencyInfoForAck(renderer_latency_info);
706 AckTouchEventToClient(ack_result, acked_event.Pass()); 674 AckTouchEventToClient(ack_result, acked_event.Pass());
707 } 675 }
708 676
709 void TouchEventQueue::AckTouchEventToClient( 677 void TouchEventQueue::AckTouchEventToClient(
710 InputEventAckState ack_result, 678 InputEventAckState ack_result,
711 scoped_ptr<CoalescedWebTouchEvent> acked_event) { 679 scoped_ptr<CoalescedWebTouchEvent> acked_event) {
712 DCHECK(acked_event); 680 DCHECK(acked_event);
713 DCHECK(!dispatching_touch_ack_); 681 DCHECK(!dispatching_touch_ack_);
714 UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result); 682 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result);
715 683
716 // Note that acking the touch-event may result in multiple gestures being sent 684 // Note that acking the touch-event may result in multiple gestures being sent
717 // to the renderer, or touch-events being queued. 685 // to the renderer, or touch-events being queued.
718 base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack( 686 base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack(
719 &dispatching_touch_ack_, acked_event.get()); 687 &dispatching_touch_ack_, acked_event.get());
720 acked_event->DispatchAckToClient(ack_result, client_); 688 acked_event->DispatchAckToClient(ack_result, client_);
721 } 689 }
722 690
723 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { 691 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
724 DCHECK(!touch_queue_.empty()); 692 DCHECK(!touch_queue_.empty());
(...skipping 18 matching lines...) Expand all
743 } 711 }
744 712
745 TouchEventQueue::PreFilterResult 713 TouchEventQueue::PreFilterResult
746 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { 714 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
747 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) 715 if (timeout_handler_ && timeout_handler_->FilterEvent(event))
748 return ACK_WITH_NO_CONSUMER_EXISTS; 716 return ACK_WITH_NO_CONSUMER_EXISTS;
749 717
750 if (touchmove_slop_suppressor_->FilterEvent(event)) 718 if (touchmove_slop_suppressor_->FilterEvent(event))
751 return ACK_WITH_NOT_CONSUMED; 719 return ACK_WITH_NOT_CONSUMED;
752 720
753 if (touch_filtering_state_ == DROP_ALL_TOUCHES) 721 if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
754 return ACK_WITH_NO_CONSUMER_EXISTS; 722 touch_consumer_states_.clear();
723 send_touch_events_async_ = false;
724 pending_async_touchmove_.reset();
725 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
726 drop_remaining_touches_in_sequence_ = false;
727 if (!has_handlers_) {
728 drop_remaining_touches_in_sequence_ = true;
729 return ACK_WITH_NO_CONSUMER_EXISTS;
730 }
731 }
755 732
756 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && 733 if (drop_remaining_touches_in_sequence_ &&
757 event.type != WebInputEvent::TouchCancel) { 734 event.type != WebInputEvent::TouchCancel) {
758 if (WebTouchEventTraits::IsTouchSequenceStart(event))
759 return FORWARD_TO_RENDERER;
760 return ACK_WITH_NO_CONSUMER_EXISTS; 735 return ACK_WITH_NO_CONSUMER_EXISTS;
761 } 736 }
762 737
763 // Touch press events should always be forwarded to the renderer.
764 if (event.type == WebInputEvent::TouchStart) 738 if (event.type == WebInputEvent::TouchStart)
765 return FORWARD_TO_RENDERER; 739 return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS;
766 740
767 for (unsigned int i = 0; i < event.touchesLength; ++i) { 741 for (unsigned int i = 0; i < event.touchesLength; ++i) {
768 const WebTouchPoint& point = event.touches[i]; 742 const WebTouchPoint& point = event.touches[i];
769 // If a point has been stationary, then don't take it into account. 743 // If a point has been stationary, then don't take it into account.
770 if (point.state == WebTouchPoint::StateStationary) 744 if (point.state == WebTouchPoint::StateStationary)
771 continue; 745 continue;
772 746
773 if (touch_ack_states_.count(point.id) > 0) { 747 DCHECK_GE(point.id, 0);
774 if (touch_ack_states_.find(point.id)->second != 748 DCHECK_LT(point.id, 32);
775 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) 749 if (touch_consumer_states_.has_bit(point.id))
776 return FORWARD_TO_RENDERER;
777 } else {
778 // If the ACK status of a point is unknown, then the event should be
779 // forwarded to the renderer.
780 return FORWARD_TO_RENDERER; 750 return FORWARD_TO_RENDERER;
781 }
782 } 751 }
783 752
784 return ACK_WITH_NO_CONSUMER_EXISTS; 753 return ACK_WITH_NO_CONSUMER_EXISTS;
785 } 754 }
786 755
787 void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event, 756 void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event,
788 InputEventAckState ack_result) { 757 InputEventAckState ack_result) {
789 // Update the ACK status for each touch point in the ACKed event. 758 // Update the ACK status for each touch point in the ACKed event.
790 if (event.type == WebInputEvent::TouchEnd || 759 if (event.type == WebInputEvent::TouchEnd ||
791 event.type == WebInputEvent::TouchCancel) { 760 event.type == WebInputEvent::TouchCancel) {
792 // The points have been released. Erase the ACK states. 761 // The points have been released. Erase the ACK states.
793 for (unsigned i = 0; i < event.touchesLength; ++i) { 762 for (unsigned i = 0; i < event.touchesLength; ++i) {
794 const WebTouchPoint& point = event.touches[i]; 763 const WebTouchPoint& point = event.touches[i];
764 DCHECK_GE(point.id, 0);
Rick Byers 2014/09/19 17:54:06 I'd prefer if the DCHECK_LT was in the bitset impl
jdduke (slow) 2014/09/22 16:30:14 That's much better, thanks.
765 DCHECK_LT(point.id, 32);
795 if (point.state == WebTouchPoint::StateReleased || 766 if (point.state == WebTouchPoint::StateReleased ||
796 point.state == WebTouchPoint::StateCancelled) 767 point.state == WebTouchPoint::StateCancelled)
797 touch_ack_states_.erase(point.id); 768 touch_consumer_states_.clear_bit(point.id);
798 } 769 }
799 } else if (event.type == WebInputEvent::TouchStart) { 770 } else if (event.type == WebInputEvent::TouchStart) {
800 for (unsigned i = 0; i < event.touchesLength; ++i) { 771 for (unsigned i = 0; i < event.touchesLength; ++i) {
801 const WebTouchPoint& point = event.touches[i]; 772 const WebTouchPoint& point = event.touches[i];
802 if (point.state == WebTouchPoint::StatePressed) 773 DCHECK_GE(point.id, 0);
803 touch_ack_states_[point.id] = ack_result; 774 DCHECK_LT(point.id, 32);
775 if (point.state == WebTouchPoint::StatePressed) {
776 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
777 touch_consumer_states_.mark_bit(point.id);
778 else
779 touch_consumer_states_.clear_bit(point.id);
780 }
804 } 781 }
805 } 782 }
806 } 783 }
807 784
808 bool TouchEventQueue::AllTouchAckStatesHaveState(
809 InputEventAckState ack_state) const {
810 if (touch_ack_states_.empty())
811 return false;
812
813 for (TouchPointAckStates::const_iterator iter = touch_ack_states_.begin(),
814 end = touch_ack_states_.end();
815 iter != end;
816 ++iter) {
817 if (iter->second != ack_state)
818 return false;
819 }
820
821 return true;
822 }
823
824 } // namespace content 785 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698