Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(551)

Side by Side Diff: content/browser/renderer_host/input/touch_event_queue.cc

Issue 997283002: Coalesce async touch move events until the ack back from render (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing unittests Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "content/browser/renderer_host/input/timeout_monitor.h" 10 #include "content/browser/renderer_host/input/timeout_monitor.h"
(...skipping 24 matching lines...) Expand all
35 WebInputEvent::TouchCancel, 35 WebInputEvent::TouchCancel,
36 // TODO(rbyers): Shouldn't we use a fresh timestamp? 36 // TODO(rbyers): Shouldn't we use a fresh timestamp?
37 event.event.timeStampSeconds, 37 event.event.timeStampSeconds,
38 &event.event); 38 &event.event);
39 return event; 39 return event;
40 } 40 }
41 41
42 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) { 42 bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
43 return (event.type == WebInputEvent::TouchStart || 43 return (event.type == WebInputEvent::TouchStart ||
44 event.type == WebInputEvent::TouchMove) && 44 event.type == WebInputEvent::TouchMove) &&
45 !WebInputEventTraits::IgnoresAckDisposition(event); 45 event.cancelable;
46 } 46 }
47 47
48 // Compare all properties of touch points to determine the state. 48 // Compare all properties of touch points to determine the state.
49 bool HasPointChanged(const WebTouchPoint& point_1, 49 bool HasPointChanged(const WebTouchPoint& point_1,
50 const WebTouchPoint& point_2) { 50 const WebTouchPoint& point_2) {
51 DCHECK_EQ(point_1.id, point_2.id); 51 DCHECK_EQ(point_1.id, point_2.id);
52 if (point_1.screenPosition != point_2.screenPosition || 52 if (point_1.screenPosition != point_2.screenPosition ||
53 point_1.position != point_2.position || 53 point_1.position != point_2.position ||
54 point_1.radiusX != point_2.radiusX || 54 point_1.radiusX != point_2.radiusX ||
55 point_1.radiusY != point_2.radiusY || 55 point_1.radiusY != point_2.radiusY ||
(...skipping 19 matching lines...) Expand all
75 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, 75 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
76 base::Unretained(this))), 76 base::Unretained(this))),
77 enabled_(true), 77 enabled_(true),
78 enabled_for_current_sequence_(false) { 78 enabled_for_current_sequence_(false) {
79 DCHECK(timeout_delay != base::TimeDelta()); 79 DCHECK(timeout_delay != base::TimeDelta());
80 } 80 }
81 81
82 ~TouchTimeoutHandler() {} 82 ~TouchTimeoutHandler() {}
83 83
84 void StartIfNecessary(const TouchEventWithLatencyInfo& event) { 84 void StartIfNecessary(const TouchEventWithLatencyInfo& event) {
85 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); 85 if (pending_ack_state_ != PENDING_ACK_NONE)
86 return;
87
86 if (!enabled_) 88 if (!enabled_)
87 return; 89 return;
88 90
89 if (!ShouldTouchTriggerTimeout(event.event)) 91 if (!ShouldTouchTriggerTimeout(event.event))
90 return; 92 return;
91 93
92 if (WebTouchEventTraits::IsTouchSequenceStart(event.event)) 94 if (WebTouchEventTraits::IsTouchSequenceStart(event.event))
93 enabled_for_current_sequence_ = true; 95 enabled_for_current_sequence_ = true;
94 96
95 if (!enabled_for_current_sequence_) 97 if (!enabled_for_current_sequence_)
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 } 382 }
381 } 383 }
382 384
383 TouchEventQueue::~TouchEventQueue() { 385 TouchEventQueue::~TouchEventQueue() {
384 if (!touch_queue_.empty()) 386 if (!touch_queue_.empty())
385 STLDeleteElements(&touch_queue_); 387 STLDeleteElements(&touch_queue_);
386 } 388 }
387 389
388 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { 390 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) {
389 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); 391 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent");
390
391 // If the queueing of |event| was triggered by an ack dispatch, defer 392 // If the queueing of |event| was triggered by an ack dispatch, defer
392 // processing the event until the dispatch has finished. 393 // processing the event until the dispatch has finished.
393 if (touch_queue_.empty() && !dispatching_touch_ack_) { 394 if (touch_queue_.empty() && !dispatching_touch_ack_) {
394 // Optimization of the case without touch handlers. Removing this path 395 // Optimization of the case without touch handlers. Removing this path
395 // yields identical results, but this avoids unnecessary allocations. 396 // yields identical results, but this avoids unnecessary allocations.
396 PreFilterResult filter_result = FilterBeforeForwarding(event.event); 397 PreFilterResult filter_result = FilterBeforeForwarding(event.event);
397 if (filter_result != FORWARD_TO_RENDERER) { 398 if (filter_result != FORWARD_TO_RENDERER) {
398 client_->OnTouchEventAck(event, 399 client_->OnTouchEventAck(event,
399 filter_result == ACK_WITH_NO_CONSUMER_EXISTS 400 filter_result == ACK_WITH_NO_CONSUMER_EXISTS
400 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS 401 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
(...skipping 12 matching lines...) Expand all
413 // also a touch-move, then the events can be coalesced into a single event. 414 // also a touch-move, then the events can be coalesced into a single event.
414 if (touch_queue_.size() > 1) { 415 if (touch_queue_.size() > 1) {
415 CoalescedWebTouchEvent* last_event = touch_queue_.back(); 416 CoalescedWebTouchEvent* last_event = touch_queue_.back();
416 if (last_event->CoalesceEventIfPossible(event)) 417 if (last_event->CoalesceEventIfPossible(event))
417 return; 418 return;
418 } 419 }
419 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); 420 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false));
420 } 421 }
421 422
422 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, 423 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result,
423 const LatencyInfo& latency_info) { 424 const LatencyInfo& latency_info,
425 const uint32 unique_touch_event_id) {
424 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); 426 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck");
425 427
428 // We receive an ack for async touchmove from render.
429 if (!ack_pending_async_touchmove_.empty() &&
430 ack_pending_async_touchmove_.front() == unique_touch_event_id) {
431 // Remove the first touchmove from the ack_pending_async_touchmove queue.
432 ack_pending_async_touchmove_.pop_front();
433 // Send the next pending async touch move once we receive all acks back.
434 if (pending_async_touchmove_ && ack_pending_async_touchmove_.empty()) {
435 DCHECK(touch_queue_.empty());
436
437 // Dispatch the next pending async touch move when time expires.
438 if (pending_async_touchmove_->event.timeStampSeconds >=
439 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) {
440 FlushPendingAsyncTouchmove();
441 }
442 }
443 return;
444 }
445
426 DCHECK(!dispatching_touch_ack_); 446 DCHECK(!dispatching_touch_ack_);
427 dispatching_touch_ = false; 447 dispatching_touch_ = false;
428 448
429 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) 449 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result))
430 return; 450 return;
431 451
432 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); 452 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result);
433 453
434 if (touch_queue_.empty()) 454 if (touch_queue_.empty())
435 return; 455 return;
436 456
457 DCHECK_EQ(touch_queue_.front()->coalesced_event().event.uniqueTouchEventId,
458 unique_touch_event_id);
459
437 PopTouchEventToClient(ack_result, latency_info); 460 PopTouchEventToClient(ack_result, latency_info);
438 TryForwardNextEventToRenderer(); 461 TryForwardNextEventToRenderer();
439 } 462 }
440 463
441 void TouchEventQueue::TryForwardNextEventToRenderer() { 464 void TouchEventQueue::TryForwardNextEventToRenderer() {
442 DCHECK(!dispatching_touch_ack_); 465 DCHECK(!dispatching_touch_ack_);
443 // If there are queued touch events, then try to forward them to the renderer 466 // If there are queued touch events, then try to forward them to the renderer
444 // immediately, or ACK the events back to the client if appropriate. 467 // immediately, or ACK the events back to the client if appropriate.
445 while (!touch_queue_.empty()) { 468 while (!touch_queue_.empty()) {
446 PreFilterResult filter_result = 469 PreFilterResult filter_result =
(...skipping 23 matching lines...) Expand all
470 touch.event.type == WebInputEvent::TouchMove) { 493 touch.event.type == WebInputEvent::TouchMove) {
471 // Throttling touchmove's in a continuous touchmove stream while scrolling 494 // Throttling touchmove's in a continuous touchmove stream while scrolling
472 // reduces the risk of jank. However, it's still important that the web 495 // reduces the risk of jank. However, it's still important that the web
473 // application be sent touches at key points in the gesture stream, 496 // application be sent touches at key points in the gesture stream,
474 // e.g., when the application slop region is exceeded or touchmove 497 // e.g., when the application slop region is exceeded or touchmove
475 // coalescing fails because of different modifiers. 498 // coalescing fails because of different modifiers.
476 bool send_touchmove_now = size() > 1; 499 bool send_touchmove_now = size() > 1;
477 send_touchmove_now |= pending_async_touchmove_ && 500 send_touchmove_now |= pending_async_touchmove_ &&
478 !pending_async_touchmove_->CanCoalesceWith(touch); 501 !pending_async_touchmove_->CanCoalesceWith(touch);
479 send_touchmove_now |= 502 send_touchmove_now |=
480 touch.event.timeStampSeconds >= 503 ack_pending_async_touchmove_.empty() &&
481 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec; 504 (touch.event.timeStampSeconds >=
505 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec);
482 506
483 if (!send_touchmove_now) { 507 if (!send_touchmove_now) {
484 if (!pending_async_touchmove_) { 508 if (!pending_async_touchmove_) {
485 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch)); 509 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch));
486 } else { 510 } else {
487 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch)); 511 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch));
488 pending_async_touchmove_->CoalesceWith(touch); 512 pending_async_touchmove_->CoalesceWith(touch);
489 } 513 }
490 DCHECK_EQ(1U, size()); 514 DCHECK_EQ(1U, size());
491 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); 515 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
(...skipping 11 matching lines...) Expand all
503 // Flush any pending async touch move. If it can be combined with the current 527 // Flush any pending async touch move. If it can be combined with the current
504 // (touchmove) event, great, otherwise send it immediately but separately. Its 528 // (touchmove) event, great, otherwise send it immediately but separately. Its
505 // ack will trigger forwarding of the original |touch| event. 529 // ack will trigger forwarding of the original |touch| event.
506 if (pending_async_touchmove_) { 530 if (pending_async_touchmove_) {
507 if (pending_async_touchmove_->CanCoalesceWith(touch)) { 531 if (pending_async_touchmove_->CanCoalesceWith(touch)) {
508 pending_async_touchmove_->CoalesceWith(touch); 532 pending_async_touchmove_->CoalesceWith(touch);
509 pending_async_touchmove_->event.cancelable = !send_touch_events_async_; 533 pending_async_touchmove_->event.cancelable = !send_touch_events_async_;
510 touch = *pending_async_touchmove_; 534 touch = *pending_async_touchmove_;
511 pending_async_touchmove_.reset(); 535 pending_async_touchmove_.reset();
512 } else { 536 } else {
513 scoped_ptr<TouchEventWithLatencyInfo> async_move = 537 FlushPendingAsyncTouchmove();
514 pending_async_touchmove_.Pass();
515 async_move->event.cancelable = false;
516 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true));
517 SendTouchEventImmediately(async_move.get());
518 return; 538 return;
519 } 539 }
520 } 540 }
521 541
522 // Note: Touchstart events are marked cancelable to allow transitions between 542 // Note: Touchstart events are marked cancelable to allow transitions between
523 // platform scrolling and JS pinching. Touchend events, however, remain 543 // platform scrolling and JS pinching. Touchend events, however, remain
524 // uncancelable, mitigating the risk of jank when transitioning to a fling. 544 // uncancelable, mitigating the risk of jank when transitioning to a fling.
525 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) 545 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart)
526 touch.event.cancelable = false; 546 touch.event.cancelable = false;
527 547
528 // A synchronous ack will reset |dispatching_touch_|, in which case
529 // the touch timeout should not be started.
530 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
531 SendTouchEventImmediately(&touch); 548 SendTouchEventImmediately(&touch);
532 if (dispatching_touch_ && timeout_handler_) 549 }
533 timeout_handler_->StartIfNecessary(touch); 550
551 void TouchEventQueue::FlushPendingAsyncTouchmove() {
552 TouchEventWithLatencyInfo touch = *pending_async_touchmove_;
jdduke (slow) 2015/05/08 21:30:49 Instead of incurring a copy you can do: scoped_pt
lanwei 2015/05/11 19:27:56 Done.
553 touch.event.cancelable = false;
554 pending_async_touchmove_.reset();
555 touch_queue_.push_front(new CoalescedWebTouchEvent(touch, true));
556 SendTouchEventImmediately(&touch);
534 } 557 }
535 558
536 void TouchEventQueue::OnGestureScrollEvent( 559 void TouchEventQueue::OnGestureScrollEvent(
537 const GestureEventWithLatencyInfo& gesture_event) { 560 const GestureEventWithLatencyInfo& gesture_event) {
538 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { 561 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
539 if (has_handler_for_current_sequence_ && 562 if (has_handler_for_current_sequence_ &&
540 !drop_remaining_touches_in_sequence_) { 563 !drop_remaining_touches_in_sequence_) {
541 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves()) 564 DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
542 << "A touch handler should be offered a touchmove before scrolling."; 565 << "A touch handler should be offered a touchmove before scrolling.";
543 } 566 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 break; 686 break;
664 } 687 }
665 } 688 }
666 } 689 }
667 690
668 if (last_sent_touchevent_) 691 if (last_sent_touchevent_)
669 *last_sent_touchevent_ = touch->event; 692 *last_sent_touchevent_ = touch->event;
670 else 693 else
671 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); 694 last_sent_touchevent_.reset(new WebTouchEvent(touch->event));
672 695
696 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
697
673 client_->SendTouchEventImmediately(*touch); 698 client_->SendTouchEventImmediately(*touch);
699
700 // A synchronous ack will reset |dispatching_touch_|, in which case the touch
701 // timeout should not be started and the count also should not be increased.
702 if (dispatching_touch_) {
703 if (touch->event.type == WebInputEvent::TouchMove &&
704 !touch->event.cancelable) {
705 // When we send out a uncancelable touch move, we increase the count and
706 // we do not process input event ack any more, we will just ack to client
707 // and wait for the ack from render. Also we will remove it from the front
708 // of the queue.
709 ack_pending_async_touchmove_.push_back(touch->event.uniqueTouchEventId);
710 dispatching_touch_ = false;
711 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_IGNORED);
712 TryForwardNextEventToRenderer();
713 return;
714 }
715
716 if (timeout_handler_)
717 timeout_handler_->StartIfNecessary(*touch);
718 }
674 } 719 }
675 720
676 TouchEventQueue::PreFilterResult 721 TouchEventQueue::PreFilterResult
677 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { 722 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
678 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { 723 if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
679 has_handler_for_current_sequence_ = false; 724 has_handler_for_current_sequence_ = false;
680 send_touch_events_async_ = false; 725 send_touch_events_async_ = false;
681 pending_async_touchmove_.reset(); 726 pending_async_touchmove_.reset();
682 last_sent_touchevent_.reset(); 727 last_sent_touchevent_.reset();
683 728
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) 795 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
751 send_touch_events_async_ = false; 796 send_touch_events_async_ = false;
752 has_handler_for_current_sequence_ |= 797 has_handler_for_current_sequence_ |=
753 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; 798 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
754 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { 799 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) {
755 has_handler_for_current_sequence_ = false; 800 has_handler_for_current_sequence_ = false;
756 } 801 }
757 } 802 }
758 803
759 } // namespace content 804 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698