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 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 // This is the list of the original events that were coalesced. | 228 // This is the list of the original events that were coalesced. |
229 WebTouchEventWithLatencyList events_; | 229 WebTouchEventWithLatencyList events_; |
230 | 230 |
231 // If |ignore_ack_| is true, don't send this touch event to client | 231 // If |ignore_ack_| is true, don't send this touch event to client |
232 // when the event is acked. | 232 // when the event is acked. |
233 bool ignore_ack_; | 233 bool ignore_ack_; |
234 | 234 |
235 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 235 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
236 }; | 236 }; |
237 | 237 |
238 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 238 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, |
| 239 TouchScrollingMode mode) |
239 : client_(client), | 240 : client_(client), |
240 dispatching_touch_ack_(NULL), | 241 dispatching_touch_ack_(NULL), |
241 dispatching_touch_(false), | 242 dispatching_touch_(false), |
242 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), | 243 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), |
243 ack_timeout_enabled_(false) { | 244 ack_timeout_enabled_(false), |
| 245 touch_scrolling_mode_(mode), |
| 246 absorbing_touch_moves_(false) { |
244 DCHECK(client); | 247 DCHECK(client); |
245 } | 248 } |
246 | 249 |
247 TouchEventQueue::~TouchEventQueue() { | 250 TouchEventQueue::~TouchEventQueue() { |
248 if (!touch_queue_.empty()) | 251 if (!touch_queue_.empty()) |
249 STLDeleteElements(&touch_queue_); | 252 STLDeleteElements(&touch_queue_); |
250 } | 253 } |
251 | 254 |
252 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 255 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
253 // If the queueing of |event| was triggered by an ack dispatch, defer | 256 // If the queueing of |event| was triggered by an ack dispatch, defer |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 void TouchEventQueue::ForwardToRenderer( | 322 void TouchEventQueue::ForwardToRenderer( |
320 const TouchEventWithLatencyInfo& touch) { | 323 const TouchEventWithLatencyInfo& touch) { |
321 DCHECK(!dispatching_touch_); | 324 DCHECK(!dispatching_touch_); |
322 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); | 325 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); |
323 | 326 |
324 if (IsNewTouchSequence(touch.event)) { | 327 if (IsNewTouchSequence(touch.event)) { |
325 touch_filtering_state_ = | 328 touch_filtering_state_ = |
326 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT | 329 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT |
327 : FORWARD_ALL_TOUCHES; | 330 : FORWARD_ALL_TOUCHES; |
328 touch_ack_states_.clear(); | 331 touch_ack_states_.clear(); |
| 332 absorbing_touch_moves_ = false; |
329 } | 333 } |
330 | 334 |
331 // A synchronous ack will reset |dispatching_touch_|, in which case | 335 // A synchronous ack will reset |dispatching_touch_|, in which case |
332 // the touch timeout should not be started. | 336 // the touch timeout should not be started. |
333 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | 337 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
334 client_->SendTouchEventImmediately(touch); | 338 client_->SendTouchEventImmediately(touch); |
335 if (dispatching_touch_ && | 339 if (dispatching_touch_ && |
336 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && | 340 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && |
337 ShouldTouchTypeTriggerTimeout(touch.event.type)) { | 341 ShouldTouchTypeTriggerTimeout(touch.event.type)) { |
338 DCHECK(timeout_handler_); | 342 DCHECK(timeout_handler_); |
339 timeout_handler_->Start(touch); | 343 timeout_handler_->Start(touch); |
340 } | 344 } |
341 } | 345 } |
342 | 346 |
343 void TouchEventQueue::OnGestureScrollEvent( | 347 void TouchEventQueue::OnGestureScrollEvent( |
344 const GestureEventWithLatencyInfo& gesture_event) { | 348 const GestureEventWithLatencyInfo& gesture_event) { |
345 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) | 349 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) |
346 return; | 350 return; |
347 | 351 |
| 352 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) |
| 353 return; |
| 354 |
348 // We assume that scroll events are generated synchronously from | 355 // We assume that scroll events are generated synchronously from |
349 // dispatching a touch event ack. This allows us to generate a synthetic | 356 // dispatching a touch event ack. This allows us to generate a synthetic |
350 // cancel event that has the same touch ids as the touch event that | 357 // cancel event that has the same touch ids as the touch event that |
351 // is being acked. Otherwise, we don't perform the touch-cancel optimization. | 358 // is being acked. Otherwise, we don't perform the touch-cancel optimization. |
352 if (!dispatching_touch_ack_) | 359 if (!dispatching_touch_ack_) |
353 return; | 360 return; |
354 | 361 |
355 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) | 362 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) |
356 return; | 363 return; |
357 | 364 |
358 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 365 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
359 | 366 |
360 // Fake a TouchCancel to cancel the touch points of the touch event | 367 // Fake a TouchCancel to cancel the touch points of the touch event |
361 // that is currently being acked. | 368 // that is currently being acked. |
362 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we | 369 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we |
363 // are in the scope of PopTouchEventToClient() and that no touch event | 370 // are in the scope of PopTouchEventToClient() and that no touch event |
364 // in the queue is waiting for ack from renderer. So we can just insert | 371 // in the queue is waiting for ack from renderer. So we can just insert |
365 // the touch cancel at the beginning of the queue. | 372 // the touch cancel at the beginning of the queue. |
366 touch_queue_.push_front(new CoalescedWebTouchEvent( | 373 touch_queue_.push_front(new CoalescedWebTouchEvent( |
367 ObtainCancelEventForTouchEvent( | 374 ObtainCancelEventForTouchEvent( |
368 dispatching_touch_ack_->coalesced_event()), true)); | 375 dispatching_touch_ack_->coalesced_event()), true)); |
369 } | 376 } |
370 | 377 |
| 378 void TouchEventQueue::OnGestureEventAck( |
| 379 const GestureEventWithLatencyInfo& event, |
| 380 InputEventAckState ack_result) { |
| 381 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) |
| 382 return; |
| 383 |
| 384 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) |
| 385 return; |
| 386 |
| 387 // Suspend sending touchmove events as long as the scroll events are handled. |
| 388 // Note that there's no guarantee that this ACK is for the most recent |
| 389 // gesture event (or even part of the current sequence). Worse case, the |
| 390 // delay in updating the absorption state should onl result in minor UI |
| 391 // glitches. |
| 392 // TODO(rbyers): Define precise timing requirements and potentially implement |
| 393 // mitigations for races. |
| 394 absorbing_touch_moves_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); |
| 395 } |
| 396 |
371 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { | 397 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { |
372 DCHECK(!dispatching_touch_ack_); | 398 DCHECK(!dispatching_touch_ack_); |
373 DCHECK(!dispatching_touch_); | 399 DCHECK(!dispatching_touch_); |
374 | 400 |
375 if (has_handlers) { | 401 if (has_handlers) { |
376 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { | 402 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { |
377 // If no touch handler was previously registered, ensure that we don't | 403 // If no touch handler was previously registered, ensure that we don't |
378 // send a partial touch sequence to the renderer. | 404 // send a partial touch sequence to the renderer. |
379 DCHECK(touch_queue_.empty()); | 405 DCHECK(touch_queue_.empty()); |
380 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 406 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 if (touch_filtering_state_ == DROP_ALL_TOUCHES) | 497 if (touch_filtering_state_ == DROP_ALL_TOUCHES) |
472 return false; | 498 return false; |
473 | 499 |
474 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && | 500 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && |
475 event.type != WebInputEvent::TouchCancel) { | 501 event.type != WebInputEvent::TouchCancel) { |
476 if (IsNewTouchSequence(event)) | 502 if (IsNewTouchSequence(event)) |
477 return true; | 503 return true; |
478 return false; | 504 return false; |
479 } | 505 } |
480 | 506 |
| 507 if (absorbing_touch_moves_ && event.type == WebInputEvent::TouchMove) |
| 508 return false; |
| 509 |
481 // Touch press events should always be forwarded to the renderer. | 510 // Touch press events should always be forwarded to the renderer. |
482 if (event.type == WebInputEvent::TouchStart) | 511 if (event.type == WebInputEvent::TouchStart) |
483 return true; | 512 return true; |
484 | 513 |
485 for (unsigned int i = 0; i < event.touchesLength; ++i) { | 514 for (unsigned int i = 0; i < event.touchesLength; ++i) { |
486 const WebTouchPoint& point = event.touches[i]; | 515 const WebTouchPoint& point = event.touches[i]; |
487 // If a point has been stationary, then don't take it into account. | 516 // If a point has been stationary, then don't take it into account. |
488 if (point.state == WebTouchPoint::StateStationary) | 517 if (point.state == WebTouchPoint::StateStationary) |
489 continue; | 518 continue; |
490 | 519 |
(...skipping 26 matching lines...) Expand all Loading... |
517 } else if (event.type == WebInputEvent::TouchStart) { | 546 } else if (event.type == WebInputEvent::TouchStart) { |
518 for (unsigned i = 0; i < event.touchesLength; ++i) { | 547 for (unsigned i = 0; i < event.touchesLength; ++i) { |
519 const WebTouchPoint& point = event.touches[i]; | 548 const WebTouchPoint& point = event.touches[i]; |
520 if (point.state == WebTouchPoint::StatePressed) | 549 if (point.state == WebTouchPoint::StatePressed) |
521 touch_ack_states_[point.id] = ack_result; | 550 touch_ack_states_[point.id] = ack_result; |
522 } | 551 } |
523 } | 552 } |
524 } | 553 } |
525 | 554 |
526 } // namespace content | 555 } // namespace content |
OLD | NEW |