| 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 |