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

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: Rebase Created 6 years, 2 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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT), 366 touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
338 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)), 367 touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
339 touch_ack_timeout_supported(false) { 368 touch_ack_timeout_supported(false) {
340 } 369 }
341 370
342 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, 371 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
343 const Config& config) 372 const Config& config)
344 : client_(client), 373 : client_(client),
345 dispatching_touch_ack_(NULL), 374 dispatching_touch_ack_(NULL),
346 dispatching_touch_(false), 375 dispatching_touch_(false),
347 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), 376 has_handlers_(true),
348 ack_timeout_enabled_(config.touch_ack_timeout_supported),
349 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor( 377 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
350 config.touchmove_slop_suppression_length_dips)), 378 config.touchmove_slop_suppression_length_dips)),
351 send_touch_events_async_(false), 379 send_touch_events_async_(false),
352 needs_async_touchmove_for_outer_slop_region_(false), 380 needs_async_touchmove_for_outer_slop_region_(false),
353 last_sent_touch_timestamp_sec_(0), 381 last_sent_touch_timestamp_sec_(0),
354 touch_scrolling_mode_(config.touch_scrolling_mode) { 382 touch_scrolling_mode_(config.touch_scrolling_mode) {
355 DCHECK(client); 383 DCHECK(client);
356 if (ack_timeout_enabled_) { 384 if (config.touch_ack_timeout_supported) {
357 timeout_handler_.reset( 385 timeout_handler_.reset(
358 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); 386 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
359 } 387 }
360 } 388 }
361 389
362 TouchEventQueue::~TouchEventQueue() { 390 TouchEventQueue::~TouchEventQueue() {
363 if (!touch_queue_.empty()) 391 if (!touch_queue_.empty())
364 STLDeleteElements(&touch_queue_); 392 STLDeleteElements(&touch_queue_);
365 } 393 }
366 394
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 dispatching_touch_ = false; 434 dispatching_touch_ = false;
407 435
408 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) 436 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result))
409 return; 437 return;
410 438
411 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); 439 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result);
412 440
413 if (touch_queue_.empty()) 441 if (touch_queue_.empty())
414 return; 442 return;
415 443
416 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED &&
417 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) {
418 touch_filtering_state_ = FORWARD_ALL_TOUCHES;
419 }
420
421 PopTouchEventToClient(ack_result, latency_info); 444 PopTouchEventToClient(ack_result, latency_info);
422 TryForwardNextEventToRenderer(); 445 TryForwardNextEventToRenderer();
423 } 446 }
424 447
425 void TouchEventQueue::TryForwardNextEventToRenderer() { 448 void TouchEventQueue::TryForwardNextEventToRenderer() {
426 DCHECK(!dispatching_touch_ack_); 449 DCHECK(!dispatching_touch_ack_);
427 // If there are queued touch events, then try to forward them to the renderer 450 // If there are queued touch events, then try to forward them to the renderer
428 // immediately, or ACK the events back to the client if appropriate. 451 // immediately, or ACK the events back to the client if appropriate.
429 while (!touch_queue_.empty()) { 452 while (!touch_queue_.empty()) {
430 PreFilterResult filter_result = 453 PreFilterResult filter_result =
(...skipping 10 matching lines...) Expand all
441 return; 464 return;
442 } 465 }
443 } 466 }
444 } 467 }
445 468
446 void TouchEventQueue::ForwardNextEventToRenderer() { 469 void TouchEventQueue::ForwardNextEventToRenderer() {
447 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer"); 470 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer");
448 471
449 DCHECK(!empty()); 472 DCHECK(!empty());
450 DCHECK(!dispatching_touch_); 473 DCHECK(!dispatching_touch_);
451 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES);
452 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event(); 474 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
453 475
454 if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) {
455 touch_filtering_state_ =
456 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT
457 : FORWARD_ALL_TOUCHES;
458 touch_ack_states_.clear();
459 send_touch_events_async_ = false;
460 pending_async_touchmove_.reset();
461 touch_sequence_start_position_ =
462 gfx::PointF(touch.event.touches[0].position);
463 }
464
465 if (send_touch_events_async_ && 476 if (send_touch_events_async_ &&
466 touch.event.type == WebInputEvent::TouchMove) { 477 touch.event.type == WebInputEvent::TouchMove) {
467 // Throttling touchmove's in a continuous touchmove stream while scrolling 478 // Throttling touchmove's in a continuous touchmove stream while scrolling
468 // reduces the risk of jank. However, it's still important that the web 479 // reduces the risk of jank. However, it's still important that the web
469 // application be sent touches at key points in the gesture stream, 480 // application be sent touches at key points in the gesture stream,
470 // e.g., when the application slop region is exceeded or touchmove 481 // e.g., when the application slop region is exceeded or touchmove
471 // coalescing fails because of different modifiers. 482 // coalescing fails because of different modifiers.
472 const bool send_touchmove_now = 483 const bool send_touchmove_now =
473 size() > 1 || 484 size() > 1 ||
474 (touch.event.timeStampSeconds >= 485 (touch.event.timeStampSeconds >=
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 // Note: Marking touchstart events as not-cancelable prevents them from 531 // Note: Marking touchstart events as not-cancelable prevents them from
521 // blocking subsequent gestures, but it may not be the best long term solution 532 // blocking subsequent gestures, but it may not be the best long term solution
522 // for tracking touch point dispatch. 533 // for tracking touch point dispatch.
523 if (send_touch_events_async_) 534 if (send_touch_events_async_)
524 touch.event.cancelable = false; 535 touch.event.cancelable = false;
525 536
526 // A synchronous ack will reset |dispatching_touch_|, in which case 537 // A synchronous ack will reset |dispatching_touch_|, in which case
527 // the touch timeout should not be started. 538 // the touch timeout should not be started.
528 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); 539 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
529 SendTouchEventImmediately(touch); 540 SendTouchEventImmediately(touch);
530 if (dispatching_touch_ && 541 if (dispatching_touch_ && timeout_handler_)
531 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && 542 timeout_handler_->StartIfNecessary(touch);
532 ShouldTouchTriggerTimeout(touch.event)) {
533 DCHECK(timeout_handler_);
534 timeout_handler_->Start(touch);
535 }
536 } 543 }
537 544
538 void TouchEventQueue::OnGestureScrollEvent( 545 void TouchEventQueue::OnGestureScrollEvent(
539 const GestureEventWithLatencyInfo& gesture_event) { 546 const GestureEventWithLatencyInfo& gesture_event) {
540 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { 547 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
541 if (touch_filtering_state_ != DROP_ALL_TOUCHES && 548 if (!touch_consumer_states_.is_empty() &&
542 touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) { 549 !drop_remaining_touches_in_sequence_) {
543 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) 550 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
544 << "The renderer should be offered a touchmove before scrolling " 551 << "A touch handler should be offered a touchmove before scrolling.";
545 "begins";
546 } 552 }
547
548 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE && 553 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
549 touch_filtering_state_ != DROP_ALL_TOUCHES && 554 !drop_remaining_touches_in_sequence_ &&
550 touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE && 555 touch_consumer_states_.is_empty()) {
551 (touch_ack_states_.empty() ||
552 AllTouchAckStatesHaveState(
553 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))) {
554 // If no touch points have a consumer, prevent all subsequent touch events 556 // If no touch points have a consumer, prevent all subsequent touch events
555 // received during the scroll from reaching the renderer. This ensures 557 // received during the scroll from reaching the renderer. This ensures
556 // that the first touchstart the renderer sees in any given sequence can 558 // that the first touchstart the renderer sees in any given sequence can
557 // always be preventDefault'ed (cancelable == true). 559 // always be preventDefault'ed (cancelable == true).
558 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable. 560 // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable.
559 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 561 drop_remaining_touches_in_sequence_ = true;
560 } 562 }
561 563
562 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { 564 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
563 needs_async_touchmove_for_outer_slop_region_ = true; 565 needs_async_touchmove_for_outer_slop_region_ = true;
564 pending_async_touchmove_.reset(); 566 pending_async_touchmove_.reset();
565 } 567 }
566 568
567 return; 569 return;
568 } 570 }
569 571
570 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate) 572 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
571 return; 573 return;
572 574
573 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) 575 if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
574 send_touch_events_async_ = true; 576 send_touch_events_async_ = true;
575 577
576 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) 578 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
577 return; 579 return;
578 580
579 // We assume that scroll events are generated synchronously from 581 // We assume that scroll events are generated synchronously from
580 // dispatching a touch event ack. This allows us to generate a synthetic 582 // dispatching a touch event ack. This allows us to generate a synthetic
581 // cancel event that has the same touch ids as the touch event that 583 // cancel event that has the same touch ids as the touch event that
582 // is being acked. Otherwise, we don't perform the touch-cancel optimization. 584 // is being acked. Otherwise, we don't perform the touch-cancel optimization.
583 if (!dispatching_touch_ack_) 585 if (!dispatching_touch_ack_)
584 return; 586 return;
585 587
586 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) 588 if (drop_remaining_touches_in_sequence_)
587 return; 589 return;
588 590
589 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; 591 drop_remaining_touches_in_sequence_ = true;
590 592
591 // Fake a TouchCancel to cancel the touch points of the touch event 593 // Fake a TouchCancel to cancel the touch points of the touch event
592 // that is currently being acked. 594 // that is currently being acked.
593 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we 595 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we
594 // are in the scope of PopTouchEventToClient() and that no touch event 596 // are in the scope of PopTouchEventToClient() and that no touch event
595 // in the queue is waiting for ack from renderer. So we can just insert 597 // in the queue is waiting for ack from renderer. So we can just insert
596 // the touch cancel at the beginning of the queue. 598 // the touch cancel at the beginning of the queue.
597 touch_queue_.push_front(new CoalescedWebTouchEvent( 599 touch_queue_.push_front(new CoalescedWebTouchEvent(
598 ObtainCancelEventForTouchEvent( 600 ObtainCancelEventForTouchEvent(
599 dispatching_touch_ack_->coalesced_event()), true)); 601 dispatching_touch_ack_->coalesced_event()), true));
(...skipping 15 matching lines...) Expand all
615 // A valid |pending_async_touchmove_| will be flushed when the next event is 617 // A valid |pending_async_touchmove_| will be flushed when the next event is
616 // forwarded. 618 // forwarded.
617 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); 619 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
618 if (!send_touch_events_async_) 620 if (!send_touch_events_async_)
619 needs_async_touchmove_for_outer_slop_region_ = false; 621 needs_async_touchmove_for_outer_slop_region_ = false;
620 } 622 }
621 623
622 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { 624 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
623 DCHECK(!dispatching_touch_ack_); 625 DCHECK(!dispatching_touch_ack_);
624 DCHECK(!dispatching_touch_); 626 DCHECK(!dispatching_touch_);
625 627 has_handlers_ = has_handlers;
626 if (has_handlers) {
627 if (touch_filtering_state_ == DROP_ALL_TOUCHES) {
628 // If no touch handler was previously registered, ensure that we don't
629 // send a partial touch sequence to the renderer.
630 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
631 }
632 } else {
633 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
634 // state tracking and/or touch-action filtering (e.g., if the touch handler
635 // was removed mid-sequence), crbug.com/375940.
636 touch_filtering_state_ = DROP_ALL_TOUCHES;
637 pending_async_touchmove_.reset();
638 if (timeout_handler_)
639 timeout_handler_->Reset();
640 }
641 } 628 }
642 629
643 bool TouchEventQueue::IsPendingAckTouchStart() const { 630 bool TouchEventQueue::IsPendingAckTouchStart() const {
644 DCHECK(!dispatching_touch_ack_); 631 DCHECK(!dispatching_touch_ack_);
645 if (touch_queue_.empty()) 632 if (touch_queue_.empty())
646 return false; 633 return false;
647 634
648 const blink::WebTouchEvent& event = 635 const blink::WebTouchEvent& event =
649 touch_queue_.front()->coalesced_event().event; 636 touch_queue_.front()->coalesced_event().event;
650 return (event.type == WebInputEvent::TouchStart); 637 return (event.type == WebInputEvent::TouchStart);
651 } 638 }
652 639
653 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) { 640 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) {
654 // The timeout handler is valid only if explicitly supported in the config. 641 if (timeout_handler_)
655 if (!timeout_handler_) 642 timeout_handler_->SetEnabled(enabled);
656 return; 643 }
657 644
658 if (ack_timeout_enabled_ == enabled) 645 bool TouchEventQueue::IsAckTimeoutEnabled() const {
659 return; 646 return timeout_handler_ && timeout_handler_->enabled();
660
661 ack_timeout_enabled_ = enabled;
662
663 if (enabled)
664 return;
665
666 if (touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT)
667 touch_filtering_state_ = FORWARD_ALL_TOUCHES;
668 // Only reset the |timeout_handler_| if the timer is running and has not yet
669 // timed out. This ensures that an already timed out sequence is properly
670 // flushed by the handler.
671 if (timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning())
672 timeout_handler_->Reset();
673 } 647 }
674 648
675 bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const { 649 bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
676 return pending_async_touchmove_; 650 return pending_async_touchmove_;
677 } 651 }
678 652
679 bool TouchEventQueue::IsTimeoutRunningForTesting() const { 653 bool TouchEventQueue::IsTimeoutRunningForTesting() const {
680 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); 654 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning();
681 } 655 }
682 656
683 const TouchEventWithLatencyInfo& 657 const TouchEventWithLatencyInfo&
684 TouchEventQueue::GetLatestEventForTesting() const { 658 TouchEventQueue::GetLatestEventForTesting() const {
685 return touch_queue_.back()->coalesced_event(); 659 return touch_queue_.back()->coalesced_event();
686 } 660 }
687 661
688 void TouchEventQueue::FlushQueue() { 662 void TouchEventQueue::FlushQueue() {
689 DCHECK(!dispatching_touch_ack_); 663 DCHECK(!dispatching_touch_ack_);
690 DCHECK(!dispatching_touch_); 664 DCHECK(!dispatching_touch_);
691 pending_async_touchmove_.reset(); 665 pending_async_touchmove_.reset();
692 if (touch_filtering_state_ != DROP_ALL_TOUCHES) 666 drop_remaining_touches_in_sequence_ = true;
693 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
694 while (!touch_queue_.empty()) 667 while (!touch_queue_.empty())
695 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); 668 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
696 } 669 }
697 670
698 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) { 671 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
699 AckTouchEventToClient(ack_result, PopTouchEvent(), NULL); 672 AckTouchEventToClient(ack_result, PopTouchEvent(), NULL);
700 } 673 }
701 674
702 void TouchEventQueue::PopTouchEventToClient( 675 void TouchEventQueue::PopTouchEventToClient(
703 InputEventAckState ack_result, 676 InputEventAckState ack_result,
704 const LatencyInfo& renderer_latency_info) { 677 const LatencyInfo& renderer_latency_info) {
705 AckTouchEventToClient(ack_result, PopTouchEvent(), &renderer_latency_info); 678 AckTouchEventToClient(ack_result, PopTouchEvent(), &renderer_latency_info);
706 } 679 }
707 680
708 void TouchEventQueue::AckTouchEventToClient( 681 void TouchEventQueue::AckTouchEventToClient(
709 InputEventAckState ack_result, 682 InputEventAckState ack_result,
710 scoped_ptr<CoalescedWebTouchEvent> acked_event, 683 scoped_ptr<CoalescedWebTouchEvent> acked_event,
711 const ui::LatencyInfo* optional_latency_info) { 684 const ui::LatencyInfo* optional_latency_info) {
712 DCHECK(acked_event); 685 DCHECK(acked_event);
713 DCHECK(!dispatching_touch_ack_); 686 DCHECK(!dispatching_touch_ack_);
714 UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result); 687 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result);
715 688
716 // Note that acking the touch-event may result in multiple gestures being sent 689 // Note that acking the touch-event may result in multiple gestures being sent
717 // to the renderer, or touch-events being queued. 690 // to the renderer, or touch-events being queued.
718 base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack( 691 base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack(
719 &dispatching_touch_ack_, acked_event.get()); 692 &dispatching_touch_ack_, acked_event.get());
720 acked_event->DispatchAckToClient(ack_result, optional_latency_info, client_); 693 acked_event->DispatchAckToClient(ack_result, optional_latency_info, client_);
721 } 694 }
722 695
723 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { 696 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
724 DCHECK(!touch_queue_.empty()); 697 DCHECK(!touch_queue_.empty());
(...skipping 18 matching lines...) Expand all
743 } 716 }
744 717
745 TouchEventQueue::PreFilterResult 718 TouchEventQueue::PreFilterResult
746 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { 719 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
747 if (timeout_handler_ && timeout_handler_->FilterEvent(event)) 720 if (timeout_handler_ && timeout_handler_->FilterEvent(event))
748 return ACK_WITH_NO_CONSUMER_EXISTS; 721 return ACK_WITH_NO_CONSUMER_EXISTS;
749 722
750 if (touchmove_slop_suppressor_->FilterEvent(event)) 723 if (touchmove_slop_suppressor_->FilterEvent(event))
751 return ACK_WITH_NOT_CONSUMED; 724 return ACK_WITH_NOT_CONSUMED;
752 725
753 if (touch_filtering_state_ == DROP_ALL_TOUCHES) 726 if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
754 return ACK_WITH_NO_CONSUMER_EXISTS; 727 touch_consumer_states_.clear();
728 send_touch_events_async_ = false;
729 pending_async_touchmove_.reset();
730 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
731 drop_remaining_touches_in_sequence_ = false;
732 if (!has_handlers_) {
733 drop_remaining_touches_in_sequence_ = true;
734 return ACK_WITH_NO_CONSUMER_EXISTS;
735 }
736 }
755 737
756 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && 738 if (drop_remaining_touches_in_sequence_ &&
757 event.type != WebInputEvent::TouchCancel) { 739 event.type != WebInputEvent::TouchCancel) {
758 if (WebTouchEventTraits::IsTouchSequenceStart(event))
759 return FORWARD_TO_RENDERER;
760 return ACK_WITH_NO_CONSUMER_EXISTS; 740 return ACK_WITH_NO_CONSUMER_EXISTS;
761 } 741 }
762 742
763 // Touch press events should always be forwarded to the renderer.
764 if (event.type == WebInputEvent::TouchStart) 743 if (event.type == WebInputEvent::TouchStart)
765 return FORWARD_TO_RENDERER; 744 return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS;
766 745
767 for (unsigned int i = 0; i < event.touchesLength; ++i) { 746 for (unsigned int i = 0; i < event.touchesLength; ++i) {
768 const WebTouchPoint& point = event.touches[i]; 747 const WebTouchPoint& point = event.touches[i];
769 // If a point has been stationary, then don't take it into account. 748 // If a point has been stationary, then don't take it into account.
770 if (point.state == WebTouchPoint::StateStationary) 749 if (point.state == WebTouchPoint::StateStationary)
771 continue; 750 continue;
772 751
773 if (touch_ack_states_.count(point.id) > 0) { 752 if (touch_consumer_states_.has_bit(point.id))
774 if (touch_ack_states_.find(point.id)->second !=
775 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
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; 753 return FORWARD_TO_RENDERER;
781 }
782 } 754 }
783 755
784 return ACK_WITH_NO_CONSUMER_EXISTS; 756 return ACK_WITH_NO_CONSUMER_EXISTS;
785 } 757 }
786 758
787 void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event, 759 void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event,
788 InputEventAckState ack_result) { 760 InputEventAckState ack_result) {
789 // Update the ACK status for each touch point in the ACKed event. 761 // Update the ACK status for each touch point in the ACKed event.
790 if (event.type == WebInputEvent::TouchEnd || 762 if (event.type == WebInputEvent::TouchEnd ||
791 event.type == WebInputEvent::TouchCancel) { 763 event.type == WebInputEvent::TouchCancel) {
792 // The points have been released. Erase the ACK states. 764 // The points have been released. Erase the ACK states.
793 for (unsigned i = 0; i < event.touchesLength; ++i) { 765 for (unsigned i = 0; i < event.touchesLength; ++i) {
794 const WebTouchPoint& point = event.touches[i]; 766 const WebTouchPoint& point = event.touches[i];
795 if (point.state == WebTouchPoint::StateReleased || 767 if (point.state == WebTouchPoint::StateReleased ||
796 point.state == WebTouchPoint::StateCancelled) 768 point.state == WebTouchPoint::StateCancelled)
797 touch_ack_states_.erase(point.id); 769 touch_consumer_states_.clear_bit(point.id);
798 } 770 }
799 } else if (event.type == WebInputEvent::TouchStart) { 771 } else if (event.type == WebInputEvent::TouchStart) {
800 for (unsigned i = 0; i < event.touchesLength; ++i) { 772 for (unsigned i = 0; i < event.touchesLength; ++i) {
801 const WebTouchPoint& point = event.touches[i]; 773 const WebTouchPoint& point = event.touches[i];
802 if (point.state == WebTouchPoint::StatePressed) 774 if (point.state == WebTouchPoint::StatePressed) {
803 touch_ack_states_[point.id] = ack_result; 775 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
776 touch_consumer_states_.mark_bit(point.id);
777 else
778 touch_consumer_states_.clear_bit(point.id);
779 }
804 } 780 }
805 } 781 }
806 } 782 }
807 783
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 784 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698