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/command_line.h" |
8 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
9 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "content/browser/renderer_host/input/timeout_monitor.h" |
| 12 #include "content/common/input/web_input_event_traits.h" |
| 13 #include "content/public/common/content_switches.h" |
| 14 |
| 15 using blink::WebInputEvent; |
| 16 using blink::WebTouchEvent; |
| 17 using blink::WebTouchPoint; |
10 | 18 |
11 namespace content { | 19 namespace content { |
| 20 namespace { |
| 21 |
| 22 const InputEventAckState kDefaultNotForwardedAck = |
| 23 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
12 | 24 |
13 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; | 25 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; |
14 | 26 |
| 27 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
| 28 const TouchEventWithLatencyInfo& event_to_cancel) { |
| 29 TouchEventWithLatencyInfo event = event_to_cancel; |
| 30 event.event.type = WebInputEvent::TouchCancel; |
| 31 for (size_t i = 0; i < event.event.touchesLength; i++) |
| 32 event.event.touches[i].state = WebTouchPoint::StateCancelled; |
| 33 return event; |
| 34 } |
| 35 |
| 36 bool IsNewTouchGesture(const WebTouchEvent& event) { |
| 37 if (event.type != WebInputEvent::TouchStart) |
| 38 return false; |
| 39 if (!event.touchesLength) |
| 40 return false; |
| 41 for (size_t i = 0; i < event.touchesLength; i++) { |
| 42 if (event.touches[i].state != WebTouchPoint::StatePressed) |
| 43 return false; |
| 44 } |
| 45 return true; |
| 46 } |
| 47 |
| 48 bool ShouldTouchTypeTriggerTimeout(WebInputEvent::Type type) { |
| 49 return type == WebInputEvent::TouchStart || |
| 50 type == WebInputEvent::TouchMove; |
| 51 } |
| 52 |
| 53 } // namespace |
| 54 |
| 55 class TouchEventQueue::TouchTimeoutHandler { |
| 56 public: |
| 57 TouchTimeoutHandler(TouchEventQueue* touch_queue, size_t timeout_delay_ms) |
| 58 : touch_queue_(touch_queue), |
| 59 timeout_delay_(base::TimeDelta::FromMilliseconds(timeout_delay_ms)), |
| 60 pending_ack_state_(PENDING_ACK_NONE), |
| 61 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, |
| 62 base::Unretained(this))) {} |
| 63 |
| 64 ~TouchTimeoutHandler() {} |
| 65 |
| 66 void Start(const TouchEventWithLatencyInfo& event) { |
| 67 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); |
| 68 DCHECK(ShouldTouchTypeTriggerTimeout(event.event.type)); |
| 69 timeout_event_ = event; |
| 70 timeout_monitor_.Restart(timeout_delay_); |
| 71 } |
| 72 |
| 73 bool ConfirmTouchEvent(InputEventAckState ack_result) { |
| 74 switch (pending_ack_state_) { |
| 75 case PENDING_ACK_NONE: |
| 76 timeout_monitor_.Stop(); |
| 77 return false; |
| 78 case PENDING_ACK_ORIGINAL_EVENT: |
| 79 if (AckedTimeoutEventRequiresCancel(ack_result)) { |
| 80 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); |
| 81 TouchEventWithLatencyInfo cancel_event = |
| 82 ObtainCancelEventForTouchEvent(timeout_event_); |
| 83 touch_queue_->UpdateTouchAckStates( |
| 84 cancel_event.event, kDefaultNotForwardedAck); |
| 85 touch_queue_->client_->SendTouchEventImmediately(cancel_event); |
| 86 } else { |
| 87 SetPendingAckState(PENDING_ACK_NONE); |
| 88 touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result); |
| 89 } |
| 90 return true; |
| 91 case PENDING_ACK_CANCEL_EVENT: |
| 92 SetPendingAckState(PENDING_ACK_NONE); |
| 93 return true; |
| 94 } |
| 95 return false; |
| 96 } |
| 97 |
| 98 bool HasTimeoutEvent() const { |
| 99 return pending_ack_state_ != PENDING_ACK_NONE; |
| 100 } |
| 101 |
| 102 bool IsTimeoutTimerRunning() const { |
| 103 return timeout_monitor_.IsRunning(); |
| 104 } |
| 105 |
| 106 private: |
| 107 enum PendingAckState { |
| 108 PENDING_ACK_NONE, |
| 109 PENDING_ACK_ORIGINAL_EVENT, |
| 110 PENDING_ACK_CANCEL_EVENT, |
| 111 }; |
| 112 |
| 113 void OnTimeOut() { |
| 114 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT); |
| 115 touch_queue_->FlushQueue(); |
| 116 } |
| 117 |
| 118 // Skip a cancel event if the timed-out event had no consumer and was the |
| 119 // initial event in the gesture. |
| 120 bool AckedTimeoutEventRequiresCancel(InputEventAckState ack_result) const { |
| 121 DCHECK(HasTimeoutEvent()); |
| 122 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |
| 123 return true; |
| 124 return !IsNewTouchGesture(timeout_event_.event); |
| 125 } |
| 126 |
| 127 void SetPendingAckState(PendingAckState new_pending_ack_state) { |
| 128 DCHECK_NE(pending_ack_state_, new_pending_ack_state); |
| 129 switch (new_pending_ack_state) { |
| 130 case PENDING_ACK_ORIGINAL_EVENT: |
| 131 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); |
| 132 TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventTimeout", this); |
| 133 break; |
| 134 case PENDING_ACK_CANCEL_EVENT: |
| 135 DCHECK_EQ(pending_ack_state_, PENDING_ACK_ORIGINAL_EVENT); |
| 136 DCHECK(!timeout_monitor_.IsRunning()); |
| 137 DCHECK(touch_queue_->empty()); |
| 138 TRACE_EVENT_ASYNC_STEP_INTO0( |
| 139 "input", "TouchEventTimeout", this, "CancelEvent"); |
| 140 break; |
| 141 case PENDING_ACK_NONE: |
| 142 DCHECK(!timeout_monitor_.IsRunning()); |
| 143 DCHECK(touch_queue_->empty()); |
| 144 TRACE_EVENT_ASYNC_END0("input", "TouchEventTimeout", this); |
| 145 break; |
| 146 } |
| 147 pending_ack_state_ = new_pending_ack_state; |
| 148 } |
| 149 |
| 150 |
| 151 TouchEventQueue* touch_queue_; |
| 152 |
| 153 // How long to wait on a touch ack before cancelling the touch sequence. |
| 154 base::TimeDelta timeout_delay_; |
| 155 |
| 156 // The touch event source for which we expect the next ack. |
| 157 PendingAckState pending_ack_state_; |
| 158 |
| 159 // The event for which the ack timeout is triggered. |
| 160 TouchEventWithLatencyInfo timeout_event_; |
| 161 |
| 162 // Provides timeout-based callback behavior. |
| 163 TimeoutMonitor timeout_monitor_; |
| 164 }; |
| 165 |
| 166 |
15 // This class represents a single coalesced touch event. However, it also keeps | 167 // This class represents a single coalesced touch event. However, it also keeps |
16 // track of all the original touch-events that were coalesced into a single | 168 // track of all the original touch-events that were coalesced into a single |
17 // event. The coalesced event is forwarded to the renderer, while the original | 169 // event. The coalesced event is forwarded to the renderer, while the original |
18 // touch-events are sent to the Client (on ACK for the coalesced event) so that | 170 // touch-events are sent to the Client (on ACK for the coalesced event) so that |
19 // the Client receives the event with their original timestamp. | 171 // the Client receives the event with their original timestamp. |
20 class CoalescedWebTouchEvent { | 172 class CoalescedWebTouchEvent { |
21 public: | 173 public: |
22 explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event) | 174 CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, |
| 175 bool ignore_ack) |
23 : coalesced_event_(event), | 176 : coalesced_event_(event), |
24 ignore_ack_(false) { | 177 ignore_ack_(ignore_ack) { |
25 events_.push_back(event); | 178 events_.push_back(event); |
26 TRACE_EVENT_ASYNC_BEGIN0( | 179 TRACE_EVENT_ASYNC_BEGIN0( |
27 "input", "TouchEventQueue::QueueEvent", this); | 180 "input", "TouchEventQueue::QueueEvent", this); |
28 } | 181 } |
29 | 182 |
30 ~CoalescedWebTouchEvent() { | 183 ~CoalescedWebTouchEvent() { |
31 TRACE_EVENT_ASYNC_END0( | 184 TRACE_EVENT_ASYNC_END0( |
32 "input", "TouchEventQueue::QueueEvent", this); | 185 "input", "TouchEventQueue::QueueEvent", this); |
33 } | 186 } |
34 | 187 |
(...skipping 22 matching lines...) Expand all Loading... |
57 return events_.begin(); | 210 return events_.begin(); |
58 } | 211 } |
59 | 212 |
60 WebTouchEventWithLatencyList::iterator end() { | 213 WebTouchEventWithLatencyList::iterator end() { |
61 return events_.end(); | 214 return events_.end(); |
62 } | 215 } |
63 | 216 |
64 size_t size() const { return events_.size(); } | 217 size_t size() const { return events_.size(); } |
65 | 218 |
66 bool ignore_ack() const { return ignore_ack_; } | 219 bool ignore_ack() const { return ignore_ack_; } |
67 void set_ignore_ack(bool value) { ignore_ack_ = value; } | |
68 | 220 |
69 private: | 221 private: |
70 // This is the event that is forwarded to the renderer. | 222 // This is the event that is forwarded to the renderer. |
71 TouchEventWithLatencyInfo coalesced_event_; | 223 TouchEventWithLatencyInfo coalesced_event_; |
72 | 224 |
73 // This is the list of the original events that were coalesced. | 225 // This is the list of the original events that were coalesced. |
74 WebTouchEventWithLatencyList events_; | 226 WebTouchEventWithLatencyList events_; |
75 | 227 |
76 // If |ignore_ack_| is true, don't send this touch event to client | 228 // If |ignore_ack_| is true, don't send this touch event to client |
77 // when the event is acked. | 229 // when the event is acked. |
78 bool ignore_ack_; | 230 bool ignore_ack_; |
79 | 231 |
80 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 232 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
81 }; | 233 }; |
82 | 234 |
83 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 235 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) |
84 : client_(client), | 236 : client_(client), |
85 dispatching_touch_ack_(NULL), | 237 dispatching_touch_ack_(NULL), |
86 no_touch_to_renderer_(false) { | 238 dispatching_touch_(false), |
| 239 no_touch_to_renderer_(false), |
| 240 renderer_is_consuming_touch_gesture_(false), |
| 241 ack_timeout_enabled_(false) { |
87 DCHECK(client); | 242 DCHECK(client); |
88 } | 243 } |
89 | 244 |
90 TouchEventQueue::~TouchEventQueue() { | 245 TouchEventQueue::~TouchEventQueue() { |
91 if (!touch_queue_.empty()) | 246 if (!touch_queue_.empty()) |
92 STLDeleteElements(&touch_queue_); | 247 STLDeleteElements(&touch_queue_); |
93 } | 248 } |
94 | 249 |
95 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 250 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
96 // If the queueing of |event| was triggered by an ack dispatch, defer | 251 // If the queueing of |event| was triggered by an ack dispatch, defer |
97 // processing the event until the dispatch has finished. | 252 // processing the event until the dispatch has finished. |
98 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 253 if (touch_queue_.empty() && !dispatching_touch_ack_) { |
99 // There is no touch event in the queue. Forward it to the renderer | 254 // There is no touch event in the queue. Forward it to the renderer |
100 // immediately. | 255 // immediately. |
101 touch_queue_.push_back(new CoalescedWebTouchEvent(event)); | 256 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
102 TryForwardNextEventToRenderer(); | 257 TryForwardNextEventToRenderer(); |
103 return; | 258 return; |
104 } | 259 } |
105 | 260 |
106 // If the last queued touch-event was a touch-move, and the current event is | 261 // If the last queued touch-event was a touch-move, and the current event is |
107 // also a touch-move, then the events can be coalesced into a single event. | 262 // also a touch-move, then the events can be coalesced into a single event. |
108 if (touch_queue_.size() > 1) { | 263 if (touch_queue_.size() > 1) { |
109 CoalescedWebTouchEvent* last_event = touch_queue_.back(); | 264 CoalescedWebTouchEvent* last_event = touch_queue_.back(); |
110 if (last_event->CoalesceEventIfPossible(event)) | 265 if (last_event->CoalesceEventIfPossible(event)) |
111 return; | 266 return; |
112 } | 267 } |
113 touch_queue_.push_back(new CoalescedWebTouchEvent(event)); | 268 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
114 } | 269 } |
115 | 270 |
116 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, | 271 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
117 const ui::LatencyInfo& latency_info) { | 272 const ui::LatencyInfo& latency_info) { |
118 DCHECK(!dispatching_touch_ack_); | 273 DCHECK(!dispatching_touch_ack_); |
| 274 dispatching_touch_ = false; |
| 275 |
| 276 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) |
| 277 return; |
| 278 |
119 if (touch_queue_.empty()) | 279 if (touch_queue_.empty()) |
120 return; | 280 return; |
121 | 281 |
122 // Update the ACK status for each touch point in the ACKed event. | 282 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
123 const blink::WebTouchEvent& event = | 283 renderer_is_consuming_touch_gesture_ = true; |
| 284 |
| 285 const WebTouchEvent& acked_event = |
124 touch_queue_.front()->coalesced_event().event; | 286 touch_queue_.front()->coalesced_event().event; |
125 if (event.type == blink::WebInputEvent::TouchEnd || | 287 UpdateTouchAckStates(acked_event, ack_result); |
126 event.type == blink::WebInputEvent::TouchCancel) { | |
127 // The points have been released. Erase the ACK states. | |
128 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
129 const blink::WebTouchPoint& point = event.touches[i]; | |
130 if (point.state == blink::WebTouchPoint::StateReleased || | |
131 point.state == blink::WebTouchPoint::StateCancelled) | |
132 touch_ack_states_.erase(point.id); | |
133 } | |
134 } else if (event.type == blink::WebInputEvent::TouchStart) { | |
135 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
136 const blink::WebTouchPoint& point = event.touches[i]; | |
137 if (point.state == blink::WebTouchPoint::StatePressed) | |
138 touch_ack_states_[point.id] = ack_result; | |
139 } | |
140 } | |
141 | |
142 PopTouchEventToClient(ack_result, latency_info); | 288 PopTouchEventToClient(ack_result, latency_info); |
143 TryForwardNextEventToRenderer(); | 289 TryForwardNextEventToRenderer(); |
144 } | 290 } |
145 | 291 |
146 void TouchEventQueue::TryForwardNextEventToRenderer() { | 292 void TouchEventQueue::TryForwardNextEventToRenderer() { |
147 DCHECK(!dispatching_touch_ack_); | 293 DCHECK(!dispatching_touch_ack_); |
148 // If there are queued touch events, then try to forward them to the renderer | 294 // If there are queued touch events, then try to forward them to the renderer |
149 // immediately, or ACK the events back to the client if appropriate. | 295 // immediately, or ACK the events back to the client if appropriate. |
150 while (!touch_queue_.empty()) { | 296 while (!touch_queue_.empty()) { |
151 const TouchEventWithLatencyInfo& touch = | 297 const TouchEventWithLatencyInfo& touch = |
152 touch_queue_.front()->coalesced_event(); | 298 touch_queue_.front()->coalesced_event(); |
| 299 if (IsNewTouchGesture(touch.event)) |
| 300 renderer_is_consuming_touch_gesture_ = false; |
153 if (ShouldForwardToRenderer(touch.event)) { | 301 if (ShouldForwardToRenderer(touch.event)) { |
154 client_->SendTouchEventImmediately(touch); | 302 ForwardToRenderer(touch); |
155 break; | 303 break; |
156 } | 304 } |
157 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, | 305 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
158 ui::LatencyInfo()); | |
159 } | 306 } |
160 } | 307 } |
161 | 308 |
| 309 void TouchEventQueue::ForwardToRenderer( |
| 310 const TouchEventWithLatencyInfo& touch) { |
| 311 DCHECK(!dispatching_touch_); |
| 312 // A synchronous ack will reset |dispatching_touch_|, in which case |
| 313 // the touch timeout should not be started. |
| 314 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
| 315 client_->SendTouchEventImmediately(touch); |
| 316 if (ack_timeout_enabled_ && |
| 317 dispatching_touch_ && |
| 318 !renderer_is_consuming_touch_gesture_ && |
| 319 ShouldTouchTypeTriggerTimeout(touch.event.type)) { |
| 320 DCHECK(timeout_handler_); |
| 321 timeout_handler_->Start(touch); |
| 322 } |
| 323 } |
| 324 |
162 void TouchEventQueue::OnGestureScrollEvent( | 325 void TouchEventQueue::OnGestureScrollEvent( |
163 const GestureEventWithLatencyInfo& gesture_event) { | 326 const GestureEventWithLatencyInfo& gesture_event) { |
164 blink::WebInputEvent::Type type = gesture_event.event.type; | 327 blink::WebInputEvent::Type type = gesture_event.event.type; |
165 if (type == blink::WebInputEvent::GestureScrollBegin) { | 328 if (type == blink::WebInputEvent::GestureScrollBegin) { |
166 // We assume the scroll event are generated synchronously from | 329 // We assume the scroll event are generated synchronously from |
167 // dispatching a touch event ack, so that we can fake a cancel | 330 // dispatching a touch event ack, so that we can fake a cancel |
168 // event that has the correct touch ids as the touch event that | 331 // event that has the correct touch ids as the touch event that |
169 // is being acked. If not, we don't do the touch-cancel optimization. | 332 // is being acked. If not, we don't do the touch-cancel optimization. |
170 if (no_touch_to_renderer_ || !dispatching_touch_ack_) | 333 if (no_touch_to_renderer_ || !dispatching_touch_ack_) |
171 return; | 334 return; |
172 no_touch_to_renderer_ = true; | 335 no_touch_to_renderer_ = true; |
| 336 |
| 337 // If we have a timeout event, a cancel has already been dispatched |
| 338 // for the current touch stream. |
| 339 if (HasTimeoutEvent()) |
| 340 return; |
| 341 |
173 // Fake a TouchCancel to cancel the touch points of the touch event | 342 // Fake a TouchCancel to cancel the touch points of the touch event |
174 // that is currently being acked. | 343 // that is currently being acked. |
175 TouchEventWithLatencyInfo cancel_event = | 344 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we |
176 dispatching_touch_ack_->coalesced_event(); | |
177 cancel_event.event.type = blink::WebInputEvent::TouchCancel; | |
178 for (size_t i = 0; i < cancel_event.event.touchesLength; i++) | |
179 cancel_event.event.touches[i].state = | |
180 blink::WebTouchPoint::StateCancelled; | |
181 CoalescedWebTouchEvent* coalesced_cancel_event = | |
182 new CoalescedWebTouchEvent(cancel_event); | |
183 // Ignore the ack of the touch cancel so when it is acked, it won't get | |
184 // sent to gesture recognizer. | |
185 coalesced_cancel_event->set_ignore_ack(true); | |
186 // |dispatching_touch_ack_| is non-null when we reach here, meaning we | |
187 // are in the scope of PopTouchEventToClient() and that no touch event | 345 // are in the scope of PopTouchEventToClient() and that no touch event |
188 // in the queue is waiting for ack from renderer. So we can just insert | 346 // in the queue is waiting for ack from renderer. So we can just insert |
189 // the touch cancel at the beginning of the queue. | 347 // the touch cancel at the beginning of the queue. |
190 touch_queue_.push_front(coalesced_cancel_event); | 348 touch_queue_.push_front(new CoalescedWebTouchEvent( |
| 349 ObtainCancelEventForTouchEvent( |
| 350 dispatching_touch_ack_->coalesced_event()), true)); |
191 } else if (type == blink::WebInputEvent::GestureScrollEnd || | 351 } else if (type == blink::WebInputEvent::GestureScrollEnd || |
192 type == blink::WebInputEvent::GestureFlingStart) { | 352 type == blink::WebInputEvent::GestureFlingStart) { |
193 no_touch_to_renderer_ = false; | 353 no_touch_to_renderer_ = false; |
194 } | 354 } |
195 } | 355 } |
196 | 356 |
197 void TouchEventQueue::FlushQueue() { | 357 void TouchEventQueue::FlushQueue() { |
198 DCHECK(!dispatching_touch_ack_); | 358 DCHECK(!dispatching_touch_ack_); |
| 359 DCHECK(!dispatching_touch_); |
199 while (!touch_queue_.empty()) | 360 while (!touch_queue_.empty()) |
200 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 361 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
201 ui::LatencyInfo()); | |
202 } | 362 } |
203 | 363 |
204 bool TouchEventQueue::IsPendingAckTouchStart() const { | 364 bool TouchEventQueue::IsPendingAckTouchStart() const { |
205 DCHECK(!dispatching_touch_ack_); | 365 DCHECK(!dispatching_touch_ack_); |
206 if (touch_queue_.empty()) | 366 if (touch_queue_.empty()) |
207 return false; | 367 return false; |
208 | 368 |
209 const blink::WebTouchEvent& event = | 369 const blink::WebTouchEvent& event = |
210 touch_queue_.front()->coalesced_event().event; | 370 touch_queue_.front()->coalesced_event().event; |
211 return (event.type == blink::WebInputEvent::TouchStart); | 371 return (event.type == WebInputEvent::TouchStart); |
212 } | 372 } |
213 | 373 |
214 size_t TouchEventQueue::GetQueueSize() const { | 374 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled, |
215 return touch_queue_.size(); | 375 size_t ack_timeout_delay_ms) { |
| 376 if (!enabled) { |
| 377 // Avoid resetting |timeout_handler_|, as an outstanding timeout may |
| 378 // be active and must be completed for ack handling consistency. |
| 379 ack_timeout_enabled_ = false; |
| 380 return; |
| 381 } |
| 382 |
| 383 ack_timeout_enabled_ = true; |
| 384 if (!timeout_handler_) |
| 385 timeout_handler_.reset(new TouchTimeoutHandler(this, ack_timeout_delay_ms)); |
216 } | 386 } |
217 | 387 |
218 const TouchEventWithLatencyInfo& TouchEventQueue::GetLatestEvent() const { | 388 bool TouchEventQueue::HasTimeoutEvent() const { |
| 389 return timeout_handler_ && timeout_handler_->HasTimeoutEvent(); |
| 390 } |
| 391 |
| 392 bool TouchEventQueue::IsTimeoutRunningForTesting() const { |
| 393 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); |
| 394 } |
| 395 |
| 396 const TouchEventWithLatencyInfo& |
| 397 TouchEventQueue::GetLatestEventForTesting() const { |
219 return touch_queue_.back()->coalesced_event(); | 398 return touch_queue_.back()->coalesced_event(); |
220 } | 399 } |
221 | 400 |
222 void TouchEventQueue::PopTouchEventToClient( | 401 void TouchEventQueue::PopTouchEventToClient( |
223 InputEventAckState ack_result, | 402 InputEventAckState ack_result, |
224 const ui::LatencyInfo& renderer_latency_info) { | 403 const ui::LatencyInfo& renderer_latency_info) { |
| 404 DCHECK(!dispatching_touch_ack_); |
225 if (touch_queue_.empty()) | 405 if (touch_queue_.empty()) |
226 return; | 406 return; |
227 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | 407 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); |
228 touch_queue_.pop_front(); | 408 touch_queue_.pop_front(); |
229 | 409 |
230 if (acked_event->ignore_ack()) | 410 if (acked_event->ignore_ack()) |
231 return; | 411 return; |
232 | 412 |
233 // Note that acking the touch-event may result in multiple gestures being sent | 413 // Note that acking the touch-event may result in multiple gestures being sent |
234 // to the renderer, or touch-events being queued. | 414 // to the renderer, or touch-events being queued. |
235 base::AutoReset<CoalescedWebTouchEvent*> | 415 base::AutoReset<CoalescedWebTouchEvent*> |
236 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); | 416 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); |
237 | 417 |
238 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), | 418 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), |
239 end = acked_event->end(); | 419 end = acked_event->end(); |
240 iter != end; ++iter) { | 420 iter != end; ++iter) { |
241 iter->latency.AddNewLatencyFrom(renderer_latency_info); | 421 iter->latency.AddNewLatencyFrom(renderer_latency_info); |
242 client_->OnTouchEventAck((*iter), ack_result); | 422 client_->OnTouchEventAck((*iter), ack_result); |
243 } | 423 } |
244 } | 424 } |
245 | 425 |
246 bool TouchEventQueue::ShouldForwardToRenderer( | 426 bool TouchEventQueue::ShouldForwardToRenderer( |
247 const blink::WebTouchEvent& event) const { | 427 const WebTouchEvent& event) const { |
| 428 if (HasTimeoutEvent()) |
| 429 return false; |
| 430 |
248 if (no_touch_to_renderer_ && | 431 if (no_touch_to_renderer_ && |
249 event.type != blink::WebInputEvent::TouchCancel) | 432 event.type != blink::WebInputEvent::TouchCancel) |
250 return false; | 433 return false; |
251 | 434 |
252 // Touch press events should always be forwarded to the renderer. | 435 // Touch press events should always be forwarded to the renderer. |
253 if (event.type == blink::WebInputEvent::TouchStart) | 436 if (event.type == WebInputEvent::TouchStart) |
254 return true; | 437 return true; |
255 | 438 |
256 for (unsigned int i = 0; i < event.touchesLength; ++i) { | 439 for (unsigned int i = 0; i < event.touchesLength; ++i) { |
257 const blink::WebTouchPoint& point = event.touches[i]; | 440 const WebTouchPoint& point = event.touches[i]; |
258 // If a point has been stationary, then don't take it into account. | 441 // If a point has been stationary, then don't take it into account. |
259 if (point.state == blink::WebTouchPoint::StateStationary) | 442 if (point.state == WebTouchPoint::StateStationary) |
260 continue; | 443 continue; |
261 | 444 |
262 if (touch_ack_states_.count(point.id) > 0) { | 445 if (touch_ack_states_.count(point.id) > 0) { |
263 if (touch_ack_states_.find(point.id)->second != | 446 if (touch_ack_states_.find(point.id)->second != |
264 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | 447 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |
265 return true; | 448 return true; |
266 } else { | 449 } else { |
267 // If the ACK status of a point is unknown, then the event should be | 450 // If the ACK status of a point is unknown, then the event should be |
268 // forwarded to the renderer. | 451 // forwarded to the renderer. |
269 return true; | 452 return true; |
270 } | 453 } |
271 } | 454 } |
272 | 455 |
273 return false; | 456 return false; |
274 } | 457 } |
275 | 458 |
| 459 void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event, |
| 460 InputEventAckState ack_result) { |
| 461 // Update the ACK status for each touch point in the ACKed event. |
| 462 if (event.type == WebInputEvent::TouchEnd || |
| 463 event.type == WebInputEvent::TouchCancel) { |
| 464 // The points have been released. Erase the ACK states. |
| 465 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 466 const WebTouchPoint& point = event.touches[i]; |
| 467 if (point.state == WebTouchPoint::StateReleased || |
| 468 point.state == WebTouchPoint::StateCancelled) |
| 469 touch_ack_states_.erase(point.id); |
| 470 } |
| 471 } else if (event.type == WebInputEvent::TouchStart) { |
| 472 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 473 const WebTouchPoint& point = event.touches[i]; |
| 474 if (point.state == WebTouchPoint::StatePressed) |
| 475 touch_ack_states_[point.id] = ack_result; |
| 476 } |
| 477 } |
| 478 } |
| 479 |
276 } // namespace content | 480 } // namespace content |
OLD | NEW |