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/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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |