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/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 | 22 |
23 // Time interval at which touchmove events will be forwarded to the client while | 23 // Time interval at which touchmove events will be forwarded to the client while |
24 // scrolling is active and possible. | 24 // scrolling is active and possible. |
25 const double kAsyncTouchMoveIntervalSec = .2; | 25 const double kAsyncTouchMoveIntervalSec = .2; |
26 | 26 |
27 // A sanity check on touches received to ensure that touch movement outside | 27 // A sanity check on touches received to ensure that touch movement outside |
28 // the platform slop region will cause scrolling, as indicated by the event's | 28 // the platform slop region will cause scrolling, as indicated by the event's |
29 // |causesScrollingIfUncanceled| bit. | 29 // |causesScrollingIfUncanceled| bit. |
30 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; | 30 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; |
31 | 31 |
| 32 // These values should be synchronized with those in histograms.xml. |
| 33 enum TouchSequenceHandlerType { |
| 34 HAS_HANDLER, |
| 35 HAS_HANDLER_BUT_NO_MOVE_HANDLERS_FOR_PAGE, |
| 36 NO_HANDLERS_FOR_PAGE, |
| 37 NO_HANDLER_FOR_SEQUENCE, |
| 38 UNKNOWN_BECAUSE_TIMEOUT, |
| 39 TOUCH_SEQUENCE_HANDLER_TYPE_COUNT |
| 40 }; |
| 41 |
| 42 void LogSequenceHandlerType(TouchSequenceHandlerType type) { |
| 43 UMA_HISTOGRAM_ENUMERATION("Event.TouchSequence.HandlerType", type, |
| 44 TOUCH_SEQUENCE_HANDLER_TYPE_COUNT); |
| 45 } |
| 46 |
32 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | 47 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
33 const TouchEventWithLatencyInfo& event_to_cancel) { | 48 const TouchEventWithLatencyInfo& event_to_cancel) { |
34 TouchEventWithLatencyInfo event = event_to_cancel; | 49 TouchEventWithLatencyInfo event = event_to_cancel; |
35 WebTouchEventTraits::ResetTypeAndTouchStates( | 50 WebTouchEventTraits::ResetTypeAndTouchStates( |
36 WebInputEvent::TouchCancel, | 51 WebInputEvent::TouchCancel, |
37 // TODO(rbyers): Shouldn't we use a fresh timestamp? | 52 // TODO(rbyers): Shouldn't we use a fresh timestamp? |
38 event.event.timeStampSeconds, | 53 event.event.timeStampSeconds, |
39 &event.event); | 54 &event.event); |
40 return event; | 55 return event; |
41 } | 56 } |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 timeout_monitor_.Stop(); | 139 timeout_monitor_.Stop(); |
125 return false; | 140 return false; |
126 case PENDING_ACK_ORIGINAL_EVENT: | 141 case PENDING_ACK_ORIGINAL_EVENT: |
127 if (AckedTimeoutEventRequiresCancel(ack_result)) { | 142 if (AckedTimeoutEventRequiresCancel(ack_result)) { |
128 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); | 143 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); |
129 TouchEventWithLatencyInfo cancel_event = | 144 TouchEventWithLatencyInfo cancel_event = |
130 ObtainCancelEventForTouchEvent(timeout_event_); | 145 ObtainCancelEventForTouchEvent(timeout_event_); |
131 touch_queue_->SendTouchEventImmediately(&cancel_event); | 146 touch_queue_->SendTouchEventImmediately(&cancel_event); |
132 } else { | 147 } else { |
133 SetPendingAckState(PENDING_ACK_NONE); | 148 SetPendingAckState(PENDING_ACK_NONE); |
134 touch_queue_->UpdateTouchConsumerStates(timeout_event_.event, | |
135 ack_result); | |
136 } | 149 } |
137 return true; | 150 return true; |
138 case PENDING_ACK_CANCEL_EVENT: | 151 case PENDING_ACK_CANCEL_EVENT: |
139 SetPendingAckState(PENDING_ACK_NONE); | 152 SetPendingAckState(PENDING_ACK_NONE); |
140 return true; | 153 return true; |
141 } | 154 } |
142 return false; | 155 return false; |
143 } | 156 } |
144 | 157 |
145 bool FilterEvent(const WebTouchEvent& event) { | 158 bool FilterEvent(const WebTouchEvent& event) { |
(...skipping 28 matching lines...) Expand all Loading... |
174 timeout_monitor_.Stop(); | 187 timeout_monitor_.Stop(); |
175 } | 188 } |
176 } | 189 } |
177 | 190 |
178 void SetUseMobileTimeout(bool use_mobile_timeout) { | 191 void SetUseMobileTimeout(bool use_mobile_timeout) { |
179 use_mobile_timeout_ = use_mobile_timeout; | 192 use_mobile_timeout_ = use_mobile_timeout; |
180 } | 193 } |
181 | 194 |
182 bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); } | 195 bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); } |
183 | 196 |
| 197 bool HasTimeoutEvent() const { |
| 198 return pending_ack_state_ != PENDING_ACK_NONE; |
| 199 } |
| 200 |
184 bool IsEnabled() const { | 201 bool IsEnabled() const { |
185 return enabled_ && !GetTimeoutDelay().is_zero(); | 202 return enabled_ && !GetTimeoutDelay().is_zero(); |
186 } | 203 } |
187 | 204 |
188 private: | 205 private: |
189 enum PendingAckState { | 206 enum PendingAckState { |
190 PENDING_ACK_NONE, | 207 PENDING_ACK_NONE, |
191 PENDING_ACK_ORIGINAL_EVENT, | 208 PENDING_ACK_ORIGINAL_EVENT, |
192 PENDING_ACK_CANCEL_EVENT, | 209 PENDING_ACK_CANCEL_EVENT, |
193 }; | 210 }; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnMobileSite", timed_out); | 264 UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnMobileSite", timed_out); |
248 } else { | 265 } else { |
249 UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnDesktopSite", timed_out); | 266 UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnDesktopSite", timed_out); |
250 } | 267 } |
251 } | 268 } |
252 | 269 |
253 base::TimeDelta GetTimeoutDelay() const { | 270 base::TimeDelta GetTimeoutDelay() const { |
254 return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_; | 271 return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_; |
255 } | 272 } |
256 | 273 |
257 bool HasTimeoutEvent() const { | |
258 return pending_ack_state_ != PENDING_ACK_NONE; | |
259 } | |
260 | |
261 | 274 |
262 TouchEventQueue* touch_queue_; | 275 TouchEventQueue* touch_queue_; |
263 | 276 |
264 // How long to wait on a touch ack before cancelling the touch sequence. | 277 // How long to wait on a touch ack before cancelling the touch sequence. |
265 const base::TimeDelta desktop_timeout_delay_; | 278 const base::TimeDelta desktop_timeout_delay_; |
266 const base::TimeDelta mobile_timeout_delay_; | 279 const base::TimeDelta mobile_timeout_delay_; |
267 bool use_mobile_timeout_; | 280 bool use_mobile_timeout_; |
268 | 281 |
269 // The touch event source for which we expect the next ack. | 282 // The touch event source for which we expect the next ack. |
270 PendingAckState pending_ack_state_; | 283 PendingAckState pending_ack_state_; |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 mobile_touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(1000)), | 439 mobile_touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(1000)), |
427 touch_ack_timeout_supported(false) { | 440 touch_ack_timeout_supported(false) { |
428 } | 441 } |
429 | 442 |
430 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, | 443 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, |
431 const Config& config) | 444 const Config& config) |
432 : client_(client), | 445 : client_(client), |
433 dispatching_touch_ack_(false), | 446 dispatching_touch_ack_(false), |
434 dispatching_touch_(false), | 447 dispatching_touch_(false), |
435 has_handlers_(true), | 448 has_handlers_(true), |
| 449 has_move_handlers_(true), |
436 has_handler_for_current_sequence_(false), | 450 has_handler_for_current_sequence_(false), |
437 drop_remaining_touches_in_sequence_(false), | 451 drop_remaining_touches_in_sequence_(false), |
438 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), | 452 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), |
439 send_touch_events_async_(false), | 453 send_touch_events_async_(false), |
440 last_sent_touch_timestamp_sec_(0) { | 454 last_sent_touch_timestamp_sec_(0) { |
441 DCHECK(client); | 455 DCHECK(client); |
442 if (config.touch_ack_timeout_supported) { | 456 if (config.touch_ack_timeout_supported) { |
443 timeout_handler_.reset( | 457 timeout_handler_.reset( |
444 new TouchTimeoutHandler(this, | 458 new TouchTimeoutHandler(this, |
445 config.desktop_touch_ack_timeout_delay, | 459 config.desktop_touch_ack_timeout_delay, |
446 config.mobile_touch_ack_timeout_delay)); | 460 config.mobile_touch_ack_timeout_delay)); |
447 } | 461 } |
448 } | 462 } |
449 | 463 |
450 TouchEventQueue::~TouchEventQueue() { | 464 TouchEventQueue::~TouchEventQueue() { |
451 if (!touch_queue_.empty()) | 465 if (!touch_queue_.empty()) |
452 STLDeleteElements(&touch_queue_); | 466 STLDeleteElements(&touch_queue_); |
453 } | 467 } |
454 | 468 |
455 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 469 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
456 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); | 470 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); |
457 | 471 |
458 // If the queueing of |event| was triggered by an ack dispatch, defer | 472 // If the queueing of |event| was triggered by an ack dispatch, defer |
459 // processing the event until the dispatch has finished. | 473 // processing the event until the dispatch has finished. |
460 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 474 if (touch_queue_.empty() && !dispatching_touch_ack_) { |
461 // Optimization of the case without touch handlers. Removing this path | 475 // Optimization of the case without touch handlers. Removing this path |
462 // yields identical results, but this avoids unnecessary allocations. | 476 // yields identical results, but this avoids unnecessary allocations. |
463 PreFilterResult filter_result = FilterBeforeForwarding(event.event); | 477 PreFilterResult filter_result = FilterBeforeForwarding(event.event); |
464 if (filter_result != FORWARD_TO_RENDERER) { | 478 if (filter_result != FORWARD_TO_RENDERER) { |
465 client_->OnTouchEventAck(event, | 479 InputEventAckState ack_result = |
466 filter_result == ACK_WITH_NO_CONSUMER_EXISTS | 480 filter_result == ACK_WITH_NO_CONSUMER_EXISTS |
467 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS | 481 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS |
468 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 482 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED; |
| 483 UpdateTouchConsumerStates(event.event, ack_result); |
| 484 client_->OnTouchEventAck(event, ack_result); |
469 return; | 485 return; |
470 } | 486 } |
471 | 487 |
472 // There is no touch event in the queue. Forward it to the renderer | 488 // There is no touch event in the queue. Forward it to the renderer |
473 // immediately. | 489 // immediately. |
474 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 490 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
475 ForwardNextEventToRenderer(); | 491 ForwardNextEventToRenderer(); |
476 return; | 492 return; |
477 } | 493 } |
478 | 494 |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 if (event.event.type == blink::WebInputEvent::GestureScrollUpdate) | 668 if (event.event.type == blink::WebInputEvent::GestureScrollUpdate) |
653 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); | 669 send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); |
654 } | 670 } |
655 | 671 |
656 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { | 672 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { |
657 DCHECK(!dispatching_touch_ack_); | 673 DCHECK(!dispatching_touch_ack_); |
658 DCHECK(!dispatching_touch_); | 674 DCHECK(!dispatching_touch_); |
659 has_handlers_ = has_handlers; | 675 has_handlers_ = has_handlers; |
660 } | 676 } |
661 | 677 |
| 678 void TouchEventQueue::OnHasTouchMoveEventHandlers(bool has_handlers) { |
| 679 DCHECK(!dispatching_touch_ack_); |
| 680 DCHECK(!dispatching_touch_); |
| 681 has_move_handlers_ = has_handlers; |
| 682 } |
| 683 |
662 bool TouchEventQueue::IsPendingAckTouchStart() const { | 684 bool TouchEventQueue::IsPendingAckTouchStart() const { |
663 DCHECK(!dispatching_touch_ack_); | 685 DCHECK(!dispatching_touch_ack_); |
664 if (touch_queue_.empty()) | 686 if (touch_queue_.empty()) |
665 return false; | 687 return false; |
666 | 688 |
667 const blink::WebTouchEvent& event = | 689 const blink::WebTouchEvent& event = |
668 touch_queue_.front()->coalesced_event().event; | 690 touch_queue_.front()->coalesced_event().event; |
669 return (event.type == WebInputEvent::TouchStart); | 691 return (event.type == WebInputEvent::TouchStart); |
670 } | 692 } |
671 | 693 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
816 event.type != WebInputEvent::TouchCancel) { | 838 event.type != WebInputEvent::TouchCancel) { |
817 return ACK_WITH_NO_CONSUMER_EXISTS; | 839 return ACK_WITH_NO_CONSUMER_EXISTS; |
818 } | 840 } |
819 | 841 |
820 if (event.type == WebInputEvent::TouchStart) { | 842 if (event.type == WebInputEvent::TouchStart) { |
821 return (has_handlers_ || has_handler_for_current_sequence_) | 843 return (has_handlers_ || has_handler_for_current_sequence_) |
822 ? FORWARD_TO_RENDERER | 844 ? FORWARD_TO_RENDERER |
823 : ACK_WITH_NO_CONSUMER_EXISTS; | 845 : ACK_WITH_NO_CONSUMER_EXISTS; |
824 } | 846 } |
825 | 847 |
| 848 if (event.type == WebInputEvent::TouchMove && !has_move_handlers_) |
| 849 return ACK_WITH_NO_CONSUMER_EXISTS; |
| 850 |
826 if (has_handler_for_current_sequence_) { | 851 if (has_handler_for_current_sequence_) { |
827 // Only forward a touch if it has a non-stationary pointer that is active | 852 // Only forward a touch if it has a non-stationary pointer that is active |
828 // in the current touch sequence. | 853 // in the current touch sequence. |
829 for (size_t i = 0; i < event.touchesLength; ++i) { | 854 for (size_t i = 0; i < event.touchesLength; ++i) { |
830 const WebTouchPoint& point = event.touches[i]; | 855 const WebTouchPoint& point = event.touches[i]; |
831 if (point.state == WebTouchPoint::StateStationary) | 856 if (point.state == WebTouchPoint::StateStationary) |
832 continue; | 857 continue; |
833 | 858 |
834 // |last_sent_touchevent_| will be non-null as long as there is an | 859 // |last_sent_touchevent_| will be non-null as long as there is an |
835 // active touch sequence being forwarded to the renderer. | 860 // active touch sequence being forwarded to the renderer. |
(...skipping 25 matching lines...) Expand all Loading... |
861 return ACK_WITH_NO_CONSUMER_EXISTS; | 886 return ACK_WITH_NO_CONSUMER_EXISTS; |
862 } | 887 } |
863 | 888 |
864 void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event, | 889 void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event, |
865 InputEventAckState ack_result) { | 890 InputEventAckState ack_result) { |
866 if (event.type == WebInputEvent::TouchStart) { | 891 if (event.type == WebInputEvent::TouchStart) { |
867 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 892 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
868 send_touch_events_async_ = false; | 893 send_touch_events_async_ = false; |
869 has_handler_for_current_sequence_ |= | 894 has_handler_for_current_sequence_ |= |
870 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | 895 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
| 896 |
| 897 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { |
| 898 if (timeout_handler_ && timeout_handler_->HasTimeoutEvent()) |
| 899 LogSequenceHandlerType(UNKNOWN_BECAUSE_TIMEOUT); |
| 900 else if (!has_handlers_) |
| 901 LogSequenceHandlerType(NO_HANDLERS_FOR_PAGE); |
| 902 else if (!has_handler_for_current_sequence_) |
| 903 LogSequenceHandlerType(NO_HANDLER_FOR_SEQUENCE); |
| 904 else if (!has_move_handlers_) |
| 905 LogSequenceHandlerType(HAS_HANDLER_BUT_NO_MOVE_HANDLERS_FOR_PAGE); |
| 906 else |
| 907 LogSequenceHandlerType(HAS_HANDLER); |
| 908 } |
871 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { | 909 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { |
872 has_handler_for_current_sequence_ = false; | 910 has_handler_for_current_sequence_ = false; |
873 } | 911 } |
874 } | 912 } |
875 | 913 |
876 } // namespace content | 914 } // namespace content |
OLD | NEW |