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/command_line.h" |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 } | 96 } |
97 | 97 |
98 bool HasTimeoutEvent() const { | 98 bool HasTimeoutEvent() const { |
99 return pending_ack_state_ != PENDING_ACK_NONE; | 99 return pending_ack_state_ != PENDING_ACK_NONE; |
100 } | 100 } |
101 | 101 |
102 bool IsTimeoutTimerRunning() const { | 102 bool IsTimeoutTimerRunning() const { |
103 return timeout_monitor_.IsRunning(); | 103 return timeout_monitor_.IsRunning(); |
104 } | 104 } |
105 | 105 |
| 106 void Reset() { |
| 107 pending_ack_state_ = PENDING_ACK_NONE; |
| 108 timeout_monitor_.Stop(); |
| 109 } |
| 110 |
106 private: | 111 private: |
107 enum PendingAckState { | 112 enum PendingAckState { |
108 PENDING_ACK_NONE, | 113 PENDING_ACK_NONE, |
109 PENDING_ACK_ORIGINAL_EVENT, | 114 PENDING_ACK_ORIGINAL_EVENT, |
110 PENDING_ACK_CANCEL_EVENT, | 115 PENDING_ACK_CANCEL_EVENT, |
111 }; | 116 }; |
112 | 117 |
113 void OnTimeOut() { | 118 void OnTimeOut() { |
114 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT); | 119 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT); |
115 touch_queue_->FlushQueue(); | 120 touch_queue_->FlushQueue(); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 // when the event is acked. | 234 // when the event is acked. |
230 bool ignore_ack_; | 235 bool ignore_ack_; |
231 | 236 |
232 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 237 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
233 }; | 238 }; |
234 | 239 |
235 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 240 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) |
236 : client_(client), | 241 : client_(client), |
237 dispatching_touch_ack_(NULL), | 242 dispatching_touch_ack_(NULL), |
238 dispatching_touch_(false), | 243 dispatching_touch_(false), |
239 no_touch_to_renderer_(false), | 244 has_handlers_(false), |
| 245 scroll_in_progress_(false), |
240 renderer_is_consuming_touch_gesture_(false), | 246 renderer_is_consuming_touch_gesture_(false), |
241 ack_timeout_enabled_(false) { | 247 ack_timeout_enabled_(false) { |
242 DCHECK(client); | 248 DCHECK(client); |
243 } | 249 } |
244 | 250 |
245 TouchEventQueue::~TouchEventQueue() { | 251 TouchEventQueue::~TouchEventQueue() { |
246 if (!touch_queue_.empty()) | 252 if (!touch_queue_.empty()) |
247 STLDeleteElements(&touch_queue_); | 253 STLDeleteElements(&touch_queue_); |
248 } | 254 } |
249 | 255 |
250 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 256 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
| 257 // Optimization of the case without touch handlers. Removing this path |
| 258 // yields identical results, but this avoids unnecessary allocations. |
| 259 if (!has_handlers_) { |
| 260 DCHECK(touch_queue_.empty()); |
| 261 client_->OnTouchEventAck(event, kDefaultNotForwardedAck); |
| 262 return; |
| 263 } |
| 264 |
251 // If the queueing of |event| was triggered by an ack dispatch, defer | 265 // If the queueing of |event| was triggered by an ack dispatch, defer |
252 // processing the event until the dispatch has finished. | 266 // processing the event until the dispatch has finished. |
253 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 267 if (touch_queue_.empty() && !dispatching_touch_ack_) { |
254 // There is no touch event in the queue. Forward it to the renderer | 268 // There is no touch event in the queue. Forward it to the renderer |
255 // immediately. | 269 // immediately. |
256 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 270 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
257 TryForwardNextEventToRenderer(); | 271 TryForwardNextEventToRenderer(); |
258 return; | 272 return; |
259 } | 273 } |
260 | 274 |
(...skipping 28 matching lines...) Expand all Loading... |
289 TryForwardNextEventToRenderer(); | 303 TryForwardNextEventToRenderer(); |
290 } | 304 } |
291 | 305 |
292 void TouchEventQueue::TryForwardNextEventToRenderer() { | 306 void TouchEventQueue::TryForwardNextEventToRenderer() { |
293 DCHECK(!dispatching_touch_ack_); | 307 DCHECK(!dispatching_touch_ack_); |
294 // If there are queued touch events, then try to forward them to the renderer | 308 // If there are queued touch events, then try to forward them to the renderer |
295 // immediately, or ACK the events back to the client if appropriate. | 309 // immediately, or ACK the events back to the client if appropriate. |
296 while (!touch_queue_.empty()) { | 310 while (!touch_queue_.empty()) { |
297 const TouchEventWithLatencyInfo& touch = | 311 const TouchEventWithLatencyInfo& touch = |
298 touch_queue_.front()->coalesced_event(); | 312 touch_queue_.front()->coalesced_event(); |
299 if (IsNewTouchGesture(touch.event)) | 313 if (IsNewTouchGesture(touch.event)) { |
| 314 touch_ack_states_.clear(); |
300 renderer_is_consuming_touch_gesture_ = false; | 315 renderer_is_consuming_touch_gesture_ = false; |
| 316 } |
301 if (ShouldForwardToRenderer(touch.event)) { | 317 if (ShouldForwardToRenderer(touch.event)) { |
302 ForwardToRenderer(touch); | 318 ForwardToRenderer(touch); |
303 break; | 319 break; |
304 } | 320 } |
305 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); | 321 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
306 } | 322 } |
307 } | 323 } |
308 | 324 |
309 void TouchEventQueue::ForwardToRenderer( | 325 void TouchEventQueue::ForwardToRenderer( |
310 const TouchEventWithLatencyInfo& touch) { | 326 const TouchEventWithLatencyInfo& touch) { |
(...skipping 12 matching lines...) Expand all Loading... |
323 } | 339 } |
324 | 340 |
325 void TouchEventQueue::OnGestureScrollEvent( | 341 void TouchEventQueue::OnGestureScrollEvent( |
326 const GestureEventWithLatencyInfo& gesture_event) { | 342 const GestureEventWithLatencyInfo& gesture_event) { |
327 blink::WebInputEvent::Type type = gesture_event.event.type; | 343 blink::WebInputEvent::Type type = gesture_event.event.type; |
328 if (type == blink::WebInputEvent::GestureScrollBegin) { | 344 if (type == blink::WebInputEvent::GestureScrollBegin) { |
329 // We assume the scroll event are generated synchronously from | 345 // We assume the scroll event are generated synchronously from |
330 // dispatching a touch event ack, so that we can fake a cancel | 346 // dispatching a touch event ack, so that we can fake a cancel |
331 // event that has the correct touch ids as the touch event that | 347 // event that has the correct touch ids as the touch event that |
332 // is being acked. If not, we don't do the touch-cancel optimization. | 348 // is being acked. If not, we don't do the touch-cancel optimization. |
333 if (no_touch_to_renderer_ || !dispatching_touch_ack_) | 349 if (scroll_in_progress_ || !dispatching_touch_ack_) |
334 return; | 350 return; |
335 no_touch_to_renderer_ = true; | 351 scroll_in_progress_ = true; |
336 | 352 |
337 // If we have a timeout event, a cancel has already been dispatched | 353 // If we have a timeout event, a cancel has already been dispatched |
338 // for the current touch stream. | 354 // for the current touch stream. |
339 if (HasTimeoutEvent()) | 355 if (HasTimeoutEvent()) |
340 return; | 356 return; |
341 | 357 |
342 // Fake a TouchCancel to cancel the touch points of the touch event | 358 // Fake a TouchCancel to cancel the touch points of the touch event |
343 // that is currently being acked. | 359 // that is currently being acked. |
344 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we | 360 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we |
345 // are in the scope of PopTouchEventToClient() and that no touch event | 361 // are in the scope of PopTouchEventToClient() and that no touch event |
346 // in the queue is waiting for ack from renderer. So we can just insert | 362 // in the queue is waiting for ack from renderer. So we can just insert |
347 // the touch cancel at the beginning of the queue. | 363 // the touch cancel at the beginning of the queue. |
348 touch_queue_.push_front(new CoalescedWebTouchEvent( | 364 touch_queue_.push_front(new CoalescedWebTouchEvent( |
349 ObtainCancelEventForTouchEvent( | 365 ObtainCancelEventForTouchEvent( |
350 dispatching_touch_ack_->coalesced_event()), true)); | 366 dispatching_touch_ack_->coalesced_event()), true)); |
351 } else if (type == blink::WebInputEvent::GestureScrollEnd || | 367 } else if (type == blink::WebInputEvent::GestureScrollEnd || |
352 type == blink::WebInputEvent::GestureFlingStart) { | 368 type == blink::WebInputEvent::GestureFlingStart) { |
353 no_touch_to_renderer_ = false; | 369 scroll_in_progress_ = false; |
354 } | 370 } |
355 } | 371 } |
356 | 372 |
357 void TouchEventQueue::FlushQueue() { | 373 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { |
358 DCHECK(!dispatching_touch_ack_); | 374 DCHECK(!dispatching_touch_ack_); |
359 DCHECK(!dispatching_touch_); | 375 DCHECK(!dispatching_touch_); |
360 while (!touch_queue_.empty()) | 376 if (has_handlers_ == has_handlers) |
361 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); | 377 return; |
| 378 |
| 379 has_handlers_ = has_handlers; |
| 380 |
| 381 if (!has_handlers_) { |
| 382 // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch |
| 383 // state tracking. |
| 384 if (timeout_handler_) |
| 385 timeout_handler_->Reset(); |
| 386 if (!touch_queue_.empty()) |
| 387 ProcessTouchAck(kDefaultNotForwardedAck, ui::LatencyInfo()); |
| 388 // As there is no touch handler, ack'ing the event should flush the queue. |
| 389 DCHECK(touch_queue_.empty()); |
| 390 } else { |
| 391 DCHECK(touch_queue_.empty()); |
| 392 // Prevent a partial sequence from being sent to the renderer. |
| 393 TouchPointAckStates::iterator ack_it = touch_ack_states_.begin(); |
| 394 for (; ack_it != touch_ack_states_.end(); ++ack_it) |
| 395 ack_it->second = kDefaultNotForwardedAck; |
| 396 } |
362 } | 397 } |
363 | 398 |
364 bool TouchEventQueue::IsPendingAckTouchStart() const { | 399 bool TouchEventQueue::IsPendingAckTouchStart() const { |
365 DCHECK(!dispatching_touch_ack_); | 400 DCHECK(!dispatching_touch_ack_); |
366 if (touch_queue_.empty()) | 401 if (touch_queue_.empty()) |
367 return false; | 402 return false; |
368 | 403 |
369 const blink::WebTouchEvent& event = | 404 const blink::WebTouchEvent& event = |
370 touch_queue_.front()->coalesced_event().event; | 405 touch_queue_.front()->coalesced_event().event; |
371 return (event.type == WebInputEvent::TouchStart); | 406 return (event.type == WebInputEvent::TouchStart); |
(...skipping 19 matching lines...) Expand all Loading... |
391 | 426 |
392 bool TouchEventQueue::IsTimeoutRunningForTesting() const { | 427 bool TouchEventQueue::IsTimeoutRunningForTesting() const { |
393 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); | 428 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); |
394 } | 429 } |
395 | 430 |
396 const TouchEventWithLatencyInfo& | 431 const TouchEventWithLatencyInfo& |
397 TouchEventQueue::GetLatestEventForTesting() const { | 432 TouchEventQueue::GetLatestEventForTesting() const { |
398 return touch_queue_.back()->coalesced_event(); | 433 return touch_queue_.back()->coalesced_event(); |
399 } | 434 } |
400 | 435 |
| 436 void TouchEventQueue::FlushQueue() { |
| 437 DCHECK(!dispatching_touch_ack_); |
| 438 DCHECK(!dispatching_touch_); |
| 439 while (!touch_queue_.empty()) |
| 440 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
| 441 } |
| 442 |
401 void TouchEventQueue::PopTouchEventToClient( | 443 void TouchEventQueue::PopTouchEventToClient( |
402 InputEventAckState ack_result, | 444 InputEventAckState ack_result, |
403 const ui::LatencyInfo& renderer_latency_info) { | 445 const ui::LatencyInfo& renderer_latency_info) { |
404 DCHECK(!dispatching_touch_ack_); | 446 DCHECK(!dispatching_touch_ack_); |
405 if (touch_queue_.empty()) | 447 if (touch_queue_.empty()) |
406 return; | 448 return; |
407 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | 449 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); |
408 touch_queue_.pop_front(); | 450 touch_queue_.pop_front(); |
409 | 451 |
410 if (acked_event->ignore_ack()) | 452 if (acked_event->ignore_ack()) |
(...skipping 10 matching lines...) Expand all Loading... |
421 iter->latency.AddNewLatencyFrom(renderer_latency_info); | 463 iter->latency.AddNewLatencyFrom(renderer_latency_info); |
422 client_->OnTouchEventAck((*iter), ack_result); | 464 client_->OnTouchEventAck((*iter), ack_result); |
423 } | 465 } |
424 } | 466 } |
425 | 467 |
426 bool TouchEventQueue::ShouldForwardToRenderer( | 468 bool TouchEventQueue::ShouldForwardToRenderer( |
427 const WebTouchEvent& event) const { | 469 const WebTouchEvent& event) const { |
428 if (HasTimeoutEvent()) | 470 if (HasTimeoutEvent()) |
429 return false; | 471 return false; |
430 | 472 |
431 if (no_touch_to_renderer_ && | 473 if (!has_handlers_) |
| 474 return false; |
| 475 |
| 476 if (scroll_in_progress_ && |
432 event.type != blink::WebInputEvent::TouchCancel) | 477 event.type != blink::WebInputEvent::TouchCancel) |
433 return false; | 478 return false; |
434 | 479 |
435 // Touch press events should always be forwarded to the renderer. | 480 // Touch press events should always be forwarded to the renderer. |
436 if (event.type == WebInputEvent::TouchStart) | 481 if (event.type == WebInputEvent::TouchStart) |
437 return true; | 482 return true; |
438 | 483 |
439 for (unsigned int i = 0; i < event.touchesLength; ++i) { | 484 for (unsigned int i = 0; i < event.touchesLength; ++i) { |
440 const WebTouchPoint& point = event.touches[i]; | 485 const WebTouchPoint& point = event.touches[i]; |
441 // If a point has been stationary, then don't take it into account. | 486 // If a point has been stationary, then don't take it into account. |
(...skipping 29 matching lines...) Expand all Loading... |
471 } else if (event.type == WebInputEvent::TouchStart) { | 516 } else if (event.type == WebInputEvent::TouchStart) { |
472 for (unsigned i = 0; i < event.touchesLength; ++i) { | 517 for (unsigned i = 0; i < event.touchesLength; ++i) { |
473 const WebTouchPoint& point = event.touches[i]; | 518 const WebTouchPoint& point = event.touches[i]; |
474 if (point.state == WebTouchPoint::StatePressed) | 519 if (point.state == WebTouchPoint::StatePressed) |
475 touch_ack_states_[point.id] = ack_result; | 520 touch_ack_states_[point.id] = ack_result; |
476 } | 521 } |
477 } | 522 } |
478 } | 523 } |
479 | 524 |
480 } // namespace content | 525 } // namespace content |
OLD | NEW |