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

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: Unit tests Created 5 years, 9 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 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client, 365 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
366 const Config& config) 366 const Config& config)
367 : client_(client), 367 : client_(client),
368 dispatching_touch_ack_(false), 368 dispatching_touch_ack_(false),
369 dispatching_touch_(false), 369 dispatching_touch_(false),
370 has_handlers_(true), 370 has_handlers_(true),
371 has_handler_for_current_sequence_(false), 371 has_handler_for_current_sequence_(false),
372 drop_remaining_touches_in_sequence_(false), 372 drop_remaining_touches_in_sequence_(false),
373 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor), 373 touchmove_slop_suppressor_(new TouchMoveSlopSuppressor),
374 send_touch_events_async_(false), 374 send_touch_events_async_(false),
375 pending_uncancelable_event_ack_count_(0),
376 sent_uncancelable_touch_move_count_(0),
375 last_sent_touch_timestamp_sec_(0) { 377 last_sent_touch_timestamp_sec_(0) {
376 DCHECK(client); 378 DCHECK(client);
377 if (config.touch_ack_timeout_supported) { 379 if (config.touch_ack_timeout_supported) {
378 timeout_handler_.reset( 380 timeout_handler_.reset(
379 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay)); 381 new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
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");
tdresser 2015/03/25 14:16:18 Might as well leave that whitespace there.
lanwei 2015/03/26 11:54:38 Done.
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 21 matching lines...) Expand all
422 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, 423 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result,
423 const LatencyInfo& latency_info) { 424 const LatencyInfo& latency_info) {
424 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); 425 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck");
425 426
426 DCHECK(!dispatching_touch_ack_); 427 DCHECK(!dispatching_touch_ack_);
427 dispatching_touch_ = false; 428 dispatching_touch_ = false;
428 429
429 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) 430 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result))
430 return; 431 return;
431 432
432 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result); 433 touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result);
tdresser 2015/03/25 14:16:18 Might as well leave that whitespace there.
lanwei 2015/03/26 11:54:38 Done.
433
434 if (touch_queue_.empty()) 434 if (touch_queue_.empty())
435 return; 435 return;
436 436
437 PopTouchEventToClient(ack_result, latency_info); 437 PopTouchEventToClient(ack_result, latency_info);
438 TryForwardNextEventToRenderer(); 438 TryForwardNextEventToRenderer();
439 } 439 }
440 440
441 void TouchEventQueue::ProcessUncancelableTouchMoveAck() {
442 TRACE_EVENT0("input", "TouchEventQueue::ProcessUncancelableTouchMoveAck");
443
444 DCHECK(!dispatching_touch_ack_);
445 dispatching_touch_ = false;
446
447 // Ignore the acks for uncancelable touchmoves when we have a touch event
448 // rather than uncancelable touchmoves and flush pending async touchmove.
449 if (pending_uncancelable_event_ack_count_ > 0) {
450 --pending_uncancelable_event_ack_count_;
451 return;
452 }
453
454 // Decrease the count once we receive the ack back from render for
455 // uncancelable touchmoves.
456 --sent_uncancelable_touch_move_count_;
457
458 // Send the next pending async touch move once we receive the ack.
459 if (pending_async_touchmove_) {
460 TouchEventWithLatencyInfo touch = *pending_async_touchmove_;
461 touch.event.cancelable = !send_touch_events_async_;
462 pending_async_touchmove_.reset();
463 if (!touch.event.cancelable)
464 ++sent_uncancelable_touch_move_count_;
465 touch_queue_.push_front(new CoalescedWebTouchEvent(touch, true));
466 SendTouchEventImmediately(&touch);
467 }
468 }
469
441 void TouchEventQueue::TryForwardNextEventToRenderer() { 470 void TouchEventQueue::TryForwardNextEventToRenderer() {
442 DCHECK(!dispatching_touch_ack_); 471 DCHECK(!dispatching_touch_ack_);
443 // If there are queued touch events, then try to forward them to the renderer 472 // 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. 473 // immediately, or ACK the events back to the client if appropriate.
445 while (!touch_queue_.empty()) { 474 while (!touch_queue_.empty()) {
446 PreFilterResult filter_result = 475 PreFilterResult filter_result =
447 FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event); 476 FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event);
448 switch (filter_result) { 477 switch (filter_result) {
449 case ACK_WITH_NO_CONSUMER_EXISTS: 478 case ACK_WITH_NO_CONSUMER_EXISTS:
450 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); 479 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
451 break; 480 break;
452 case ACK_WITH_NOT_CONSUMED: 481 case ACK_WITH_NOT_CONSUMED:
453 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); 482 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
454 break; 483 break;
455 case FORWARD_TO_RENDERER: 484 case FORWARD_TO_RENDERER:
456 ForwardNextEventToRenderer(); 485 ForwardNextEventToRenderer();
457 return; 486 return;
458 } 487 }
459 } 488 }
460 } 489 }
461 490
462 void TouchEventQueue::ForwardNextEventToRenderer() { 491 void TouchEventQueue::ForwardNextEventToRenderer() {
463 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer"); 492 TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer");
464 493
465 DCHECK(!empty()); 494 DCHECK(!empty());
466 DCHECK(!dispatching_touch_); 495 DCHECK(!dispatching_touch_);
467 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event(); 496 TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
468
469 if (send_touch_events_async_ && 497 if (send_touch_events_async_ &&
470 touch.event.type == WebInputEvent::TouchMove) { 498 touch.event.type == WebInputEvent::TouchMove) {
471 // Throttling touchmove's in a continuous touchmove stream while scrolling 499 // Throttling touchmove's in a continuous touchmove stream while scrolling
472 // reduces the risk of jank. However, it's still important that the web 500 // 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, 501 // application be sent touches at key points in the gesture stream,
474 // e.g., when the application slop region is exceeded or touchmove 502 // e.g., when the application slop region is exceeded or touchmove
475 // coalescing fails because of different modifiers. 503 // coalescing fails because of different modifiers.
476 bool send_touchmove_now = size() > 1; 504 bool send_touchmove_now = size() > 1;
477 send_touchmove_now |= pending_async_touchmove_ && 505 send_touchmove_now |= pending_async_touchmove_ &&
478 !pending_async_touchmove_->CanCoalesceWith(touch); 506 !pending_async_touchmove_->CanCoalesceWith(touch);
479 send_touchmove_now |= 507 send_touchmove_now |=
480 touch.event.timeStampSeconds >= 508 touch.event.timeStampSeconds >=
481 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec; 509 last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec;
482 510
483 if (!send_touchmove_now) { 511 if (!send_touchmove_now || sent_uncancelable_touch_move_count_ > 0) {
484 if (!pending_async_touchmove_) { 512 if (!pending_async_touchmove_) {
485 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch)); 513 pending_async_touchmove_.reset(new TouchEventWithLatencyInfo(touch));
486 } else { 514 } else {
487 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch)); 515 DCHECK(pending_async_touchmove_->CanCoalesceWith(touch));
488 pending_async_touchmove_->CoalesceWith(touch); 516 pending_async_touchmove_->CoalesceWith(touch);
489 } 517 }
490 DCHECK_EQ(1U, size()); 518 DCHECK_EQ(1U, size());
491 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); 519 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
492 // It's possible (though unlikely) that ack'ing the current touch will 520 // It's possible (though unlikely) that ack'ing the current touch will
493 // trigger the queueing of another touch event (e.g., a touchcancel). As 521 // trigger the queueing of another touch event (e.g., a touchcancel). As
494 // forwarding of the queued event will be deferred while the ack is being 522 // forwarding of the queued event will be deferred while the ack is being
495 // dispatched (see |OnTouchEvent()|), try forwarding it now. 523 // dispatched (see |OnTouchEvent()|), try forwarding it now.
496 TryForwardNextEventToRenderer(); 524 TryForwardNextEventToRenderer();
497 return; 525 return;
498 } 526 }
499 } 527 }
500 528
501 last_sent_touch_timestamp_sec_ = touch.event.timeStampSeconds; 529 last_sent_touch_timestamp_sec_ = touch.event.timeStampSeconds;
502
503 // Flush any pending async touch move. If it can be combined with the current 530 // 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 531 // (touchmove) event, great, otherwise send it immediately but separately. Its
505 // ack will trigger forwarding of the original |touch| event. 532 // ack will trigger forwarding of the original |touch| event.
506 if (pending_async_touchmove_) { 533 if (pending_async_touchmove_) {
507 if (pending_async_touchmove_->CanCoalesceWith(touch)) { 534 if (pending_async_touchmove_->CanCoalesceWith(touch)) {
508 pending_async_touchmove_->CoalesceWith(touch); 535 pending_async_touchmove_->CoalesceWith(touch);
509 pending_async_touchmove_->event.cancelable = !send_touch_events_async_; 536 pending_async_touchmove_->event.cancelable = !send_touch_events_async_;
510 touch = *pending_async_touchmove_; 537 touch = *pending_async_touchmove_;
511 pending_async_touchmove_.reset(); 538 pending_async_touchmove_.reset();
512 } else { 539 } else {
540 // Once we flush the pending async touch move, we ignore all the acks
541 // from the uncancelable touch moves that we sent out and wait for acks
542 // back.
543 ++sent_uncancelable_touch_move_count_;
513 scoped_ptr<TouchEventWithLatencyInfo> async_move = 544 scoped_ptr<TouchEventWithLatencyInfo> async_move =
514 pending_async_touchmove_.Pass(); 545 pending_async_touchmove_.Pass();
515 async_move->event.cancelable = false; 546 async_move->event.cancelable = false;
516 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true)); 547 touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true));
517 SendTouchEventImmediately(async_move.get()); 548 SendTouchEventImmediately(async_move.get());
518 return; 549 return;
519 } 550 }
520 } 551 }
521 552
522 // Note: Touchstart events are marked cancelable to allow transitions between 553 // Note: Touchstart events are marked cancelable to allow transitions between
523 // platform scrolling and JS pinching. Touchend events, however, remain 554 // platform scrolling and JS pinching. Touchend events, however, remain
524 // uncancelable, mitigating the risk of jank when transitioning to a fling. 555 // uncancelable, mitigating the risk of jank when transitioning to a fling.
525 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart) 556 if (send_touch_events_async_ && touch.event.type != WebInputEvent::TouchStart)
526 touch.event.cancelable = false; 557 touch.event.cancelable = false;
527 558
528 // A synchronous ack will reset |dispatching_touch_|, in which case 559 // A synchronous ack will reset |dispatching_touch_|, in which case
529 // the touch timeout should not be started. 560 // the touch timeout should not be started.
530 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); 561 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
562
563 // We increase the count when we send out a uncancelable touch move, and we
564 // use pending_uncancelable_event_ack_count_ to keep track the number of
565 // acks we do not wait any more when we flush pending async touch moves.
566 if (touch.event.type == WebInputEvent::TouchMove && !touch.event.cancelable) {
567 ++sent_uncancelable_touch_move_count_;
568 } else {
569 pending_uncancelable_event_ack_count_ +=
570 sent_uncancelable_touch_move_count_;
571 sent_uncancelable_touch_move_count_ = 0;
572 }
531 SendTouchEventImmediately(&touch); 573 SendTouchEventImmediately(&touch);
532 if (dispatching_touch_ && timeout_handler_) 574 if (dispatching_touch_ && timeout_handler_)
533 timeout_handler_->StartIfNecessary(touch); 575 timeout_handler_->StartIfNecessary(touch);
534 } 576 }
535 577
536 void TouchEventQueue::OnGestureScrollEvent( 578 void TouchEventQueue::OnGestureScrollEvent(
537 const GestureEventWithLatencyInfo& gesture_event) { 579 const GestureEventWithLatencyInfo& gesture_event) {
538 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) { 580 if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
539 if (has_handler_for_current_sequence_ && 581 if (has_handler_for_current_sequence_ &&
540 !drop_remaining_touches_in_sequence_) { 582 !drop_remaining_touches_in_sequence_) {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) 792 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
751 send_touch_events_async_ = false; 793 send_touch_events_async_ = false;
752 has_handler_for_current_sequence_ |= 794 has_handler_for_current_sequence_ |=
753 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; 795 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
754 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { 796 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) {
755 has_handler_for_current_sequence_ = false; 797 has_handler_for_current_sequence_ = false;
756 } 798 }
757 } 799 }
758 800
759 } // namespace content 801 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698