Chromium Code Reviews| 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(); | |
|
tdresser
2014/01/09 21:14:32
Shouldn't these be cleared per finger, not per ges
jdduke (slow)
2014/01/09 22:05:04
I thought about adding a DCHECK(touch_ack_states_.
| |
| 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; |
|
tdresser
2014/01/09 21:14:32
This should be a DCHECK, shouldn't it? (Given the
| |
| 378 | |
| 379 has_handlers_ = has_handlers; | |
| 380 | |
| 381 if (!has_handlers_) { | |
| 382 // TODO(jdduke): Synthesize a TouchCancel if necessary? This would only work | |
| 383 // if we cache the last WebTouchEvent sent to the renderer. | |
|
tdresser
2014/01/09 21:14:32
Can you give me an example of when we'd want a Tou
jdduke (slow)
2014/01/09 22:05:04
I was talking with rbyers@ about this. He seemed t
tdresser
2014/01/09 22:20:41
Perhaps "Synthesize a TouchCancel if necessary to
| |
| 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 |