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/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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |