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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |