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 <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 using ui::LatencyInfo; | 21 using ui::LatencyInfo; |
| 22 | 22 |
| 23 namespace content { | 23 namespace content { |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 // Time interval at which touchmove events will be forwarded to the client while | 26 // Time interval at which touchmove events will be forwarded to the client while |
| 27 // scrolling is active and possible. | 27 // scrolling is active and possible. |
| 28 const double kAsyncTouchMoveIntervalSec = .2; | 28 const double kAsyncTouchMoveIntervalSec = .2; |
| 29 | 29 |
| 30 // A sanity check on touches received to ensure that touch movement outside | 30 // A sanity check on touches received to ensure that touch movement outside |
| 31 // the platform slop region will cause scrolling, as indicated by the event's | 31 // the platform slop region will cause scrolling. |
| 32 // |causesScrollingIfUncanceled| bit. | |
| 33 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; | 32 const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.; |
| 34 | 33 |
| 35 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | 34 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( |
| 36 const TouchEventWithLatencyInfo& event_to_cancel) { | 35 const TouchEventWithLatencyInfo& event_to_cancel) { |
| 37 TouchEventWithLatencyInfo event = event_to_cancel; | 36 TouchEventWithLatencyInfo event = event_to_cancel; |
| 38 WebTouchEventTraits::ResetTypeAndTouchStates( | 37 WebTouchEventTraits::ResetTypeAndTouchStates( |
| 39 WebInputEvent::TouchCancel, | 38 WebInputEvent::TouchCancel, |
| 40 // TODO(rbyers): Shouldn't we use a fresh timestamp? | 39 // TODO(rbyers): Shouldn't we use a fresh timestamp? |
| 41 event.event.timeStampSeconds, | 40 event.event.timeStampSeconds, |
| 42 &event.event); | 41 &event.event); |
| (...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 | 452 |
| 454 TouchEventQueue::~TouchEventQueue() { | 453 TouchEventQueue::~TouchEventQueue() { |
| 455 if (!touch_queue_.empty()) | 454 if (!touch_queue_.empty()) |
| 456 STLDeleteElements(&touch_queue_); | 455 STLDeleteElements(&touch_queue_); |
| 457 } | 456 } |
| 458 | 457 |
| 459 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 458 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
| 460 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); | 459 TRACE_EVENT0("input", "TouchEventQueue::QueueEvent"); |
| 461 | 460 |
| 462 // If the queueing of |event| was triggered by an ack dispatch, defer | 461 // If the queueing of |event| was triggered by an ack dispatch, defer |
| 463 // processing the event until the dispatch has finished. | 462 // processing the event until the dispatch has finished. The touch queue is |
| 464 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 463 // non-empty in this case. |
| 464 if (touch_queue_.empty()) { | |
| 465 // Optimization of the case without touch handlers. Removing this path | 465 // Optimization of the case without touch handlers. Removing this path |
| 466 // yields identical results, but this avoids unnecessary allocations. | 466 // yields identical results, but this avoids unnecessary allocations. |
| 467 PreFilterResult filter_result = FilterBeforeForwarding(event.event); | 467 PreFilterResult filter_result = FilterBeforeForwarding(event.event); |
| 468 if (filter_result != FORWARD_TO_RENDERER) { | 468 if (filter_result != FORWARD_TO_RENDERER) { |
| 469 client_->OnFilteringTouchEvent(event.event); | 469 client_->OnFilteringTouchEvent(event.event); |
| 470 client_->OnTouchEventAck(event, | 470 client_->OnTouchEventAck(event, |
| 471 filter_result == ACK_WITH_NO_CONSUMER_EXISTS | 471 filter_result == ACK_WITH_NO_CONSUMER_EXISTS |
| 472 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS | 472 ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS |
| 473 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 473 : INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| 474 return; | 474 return; |
| 475 } | 475 } |
| 476 | 476 |
| 477 // There is no touch event in the queue. Forward it to the renderer | 477 // There is no touch event in the queue. Forward it to the renderer |
| 478 // immediately. | 478 // immediately. |
| 479 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 479 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
| 480 ForwardNextEventToRenderer(); | 480 ForwardNextEventToRenderer(); |
| 481 return; | 481 return; |
| 482 } | 482 } |
| 483 | 483 |
| 484 // If the last queued touch-event was a touch-move, and the current event is | 484 // If the last queued touch-event was a touch-move, and the current event is |
| 485 // also a touch-move, then the events can be coalesced into a single event. | 485 // also a touch-move, then the events can be coalesced into a single event. |
| 486 if (touch_queue_.size() > 1) { | 486 if (touch_queue_.size() > 1) { |
| 487 CoalescedWebTouchEvent* last_event = touch_queue_.back(); | 487 CoalescedWebTouchEvent* last_event = touch_queue_.back(); |
| 488 if (last_event->CoalesceEventIfPossible(event)) | 488 if (last_event->CoalesceEventIfPossible(event)) |
| 489 return; | 489 return; |
| 490 } | 490 } |
| 491 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); | 491 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
| 492 } | 492 } |
| 493 | 493 |
| 494 void TouchEventQueue::PrependTouchScrollNotification() { | |
| 495 TRACE_EVENT0("input", "TouchEventQueue::PrependTouchScrollNotification"); | |
| 496 | |
| 497 TouchEventWithLatencyInfo touch; | |
| 498 touch.event.type = WebInputEvent::TouchScrollStarted; | |
| 499 touch.event.uniqueTouchEventId = 0; | |
| 500 | |
| 501 if (touch_queue_.empty()) { | |
| 502 touch_queue_.push_back(new CoalescedWebTouchEvent(touch, false)); | |
| 503 ForwardNextEventToRenderer(); | |
| 504 } else { | |
| 505 // Leave the head of the queue untouched since it is an in-flight event. | |
| 506 auto it = touch_queue_.begin(); | |
| 507 touch_queue_.insert(++it, new CoalescedWebTouchEvent(touch, false)); | |
| 508 } | |
| 509 } | |
| 510 | |
| 511 | |
| 494 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, | 512 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
| 495 const LatencyInfo& latency_info, | 513 const LatencyInfo& latency_info, |
| 496 const uint32_t unique_touch_event_id) { | 514 const uint32_t unique_touch_event_id) { |
| 497 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); | 515 TRACE_EVENT0("input", "TouchEventQueue::ProcessTouchAck"); |
| 498 | 516 |
| 499 // We receive an ack for async touchmove from render. | 517 // We receive an ack for async touchmove from render. |
| 500 if (!ack_pending_async_touchmove_ids_.empty() && | 518 if (!ack_pending_async_touchmove_ids_.empty() && |
| 501 ack_pending_async_touchmove_ids_.front() == unique_touch_event_id) { | 519 ack_pending_async_touchmove_ids_.front() == unique_touch_event_id) { |
| 502 // Remove the first touchmove from the ack_pending_async_touchmove queue. | 520 // Remove the first touchmove from the ack_pending_async_touchmove queue. |
| 503 ack_pending_async_touchmove_ids_.pop_front(); | 521 ack_pending_async_touchmove_ids_.pop_front(); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 void TouchEventQueue::FlushQueue() { | 730 void TouchEventQueue::FlushQueue() { |
| 713 DCHECK(!dispatching_touch_ack_); | 731 DCHECK(!dispatching_touch_ack_); |
| 714 DCHECK(!dispatching_touch_); | 732 DCHECK(!dispatching_touch_); |
| 715 pending_async_touchmove_.reset(); | 733 pending_async_touchmove_.reset(); |
| 716 drop_remaining_touches_in_sequence_ = true; | 734 drop_remaining_touches_in_sequence_ = true; |
| 717 while (!touch_queue_.empty()) | 735 while (!touch_queue_.empty()) |
| 718 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); | 736 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| 719 } | 737 } |
| 720 | 738 |
| 721 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) { | 739 void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) { |
| 722 AckTouchEventToClient(ack_result, PopTouchEvent(), nullptr); | 740 AckTouchEventToClient(ack_result, nullptr); |
| 723 } | 741 } |
| 724 | 742 |
| 725 void TouchEventQueue::PopTouchEventToClient( | 743 void TouchEventQueue::PopTouchEventToClient( |
| 726 InputEventAckState ack_result, | 744 InputEventAckState ack_result, |
| 727 const LatencyInfo& renderer_latency_info) { | 745 const LatencyInfo& renderer_latency_info) { |
| 728 AckTouchEventToClient(ack_result, PopTouchEvent(), &renderer_latency_info); | 746 AckTouchEventToClient(ack_result, &renderer_latency_info); |
| 729 } | 747 } |
| 730 | 748 |
| 731 void TouchEventQueue::AckTouchEventToClient( | 749 void TouchEventQueue::AckTouchEventToClient( |
| 732 InputEventAckState ack_result, | 750 InputEventAckState ack_result, |
| 733 scoped_ptr<CoalescedWebTouchEvent> acked_event, | |
| 734 const ui::LatencyInfo* optional_latency_info) { | 751 const ui::LatencyInfo* optional_latency_info) { |
| 752 DCHECK(!dispatching_touch_ack_); | |
| 753 DCHECK(!touch_queue_.empty()); | |
| 754 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | |
| 735 DCHECK(acked_event); | 755 DCHECK(acked_event); |
| 736 DCHECK(!dispatching_touch_ack_); | 756 |
| 737 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result); | 757 UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result); |
| 738 | 758 |
| 739 // Note that acking the touch-event may result in multiple gestures being sent | 759 // Note that acking the touch-event may result in multiple gestures being sent |
| 740 // to the renderer, or touch-events being queued. | 760 // to the renderer, or touch-events being queued. |
| 741 base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); | 761 base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); |
| 742 acked_event->DispatchAckToClient(ack_result, optional_latency_info, client_); | |
| 743 } | |
| 744 | 762 |
| 745 scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() { | 763 // Skip ack for TouchScrollStarted since it was synthesized within the queue. |
| 746 DCHECK(!touch_queue_.empty()); | 764 if (acked_event->coalesced_event().event.type != |
| 747 scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front()); | 765 WebInputEvent::TouchScrollStarted) |
|
tdresser
2016/04/01 19:03:20
Multiline bodies require {}
mustaq
2016/04/01 21:49:52
Done.
| |
| 766 acked_event->DispatchAckToClient(ack_result, optional_latency_info, | |
| 767 client_); | |
| 768 | |
| 748 touch_queue_.pop_front(); | 769 touch_queue_.pop_front(); |
| 749 return event; | |
| 750 } | 770 } |
| 751 | 771 |
| 752 void TouchEventQueue::SendTouchEventImmediately( | 772 void TouchEventQueue::SendTouchEventImmediately( |
| 753 TouchEventWithLatencyInfo* touch) { | 773 TouchEventWithLatencyInfo* touch) { |
| 754 // For touchmove events, compare touch points position from current event | 774 // For touchmove events, compare touch points position from current event |
| 755 // to last sent event and update touch points state. | 775 // to last sent event and update touch points state. |
| 756 if (touch->event.type == WebInputEvent::TouchMove) { | 776 if (touch->event.type == WebInputEvent::TouchMove) { |
| 757 CHECK(last_sent_touchevent_); | 777 CHECK(last_sent_touchevent_); |
| 758 for (unsigned int i = 0; i < last_sent_touchevent_->touchesLength; ++i) { | 778 for (unsigned int i = 0; i < last_sent_touchevent_->touchesLength; ++i) { |
| 759 const WebTouchPoint& last_touch_point = | 779 const WebTouchPoint& last_touch_point = |
| 760 last_sent_touchevent_->touches[i]; | 780 last_sent_touchevent_->touches[i]; |
| 761 // Touches with same id may not have same index in Touches array. | 781 // Touches with same id may not have same index in Touches array. |
| 762 for (unsigned int j = 0; j < touch->event.touchesLength; ++j) { | 782 for (unsigned int j = 0; j < touch->event.touchesLength; ++j) { |
| 763 const WebTouchPoint& current_touchmove_point = touch->event.touches[j]; | 783 const WebTouchPoint& current_touchmove_point = touch->event.touches[j]; |
| 764 if (current_touchmove_point.id != last_touch_point.id) | 784 if (current_touchmove_point.id != last_touch_point.id) |
| 765 continue; | 785 continue; |
| 766 | 786 |
| 767 if (!HasPointChanged(last_touch_point, current_touchmove_point)) | 787 if (!HasPointChanged(last_touch_point, current_touchmove_point)) |
| 768 touch->event.touches[j].state = WebTouchPoint::StateStationary; | 788 touch->event.touches[j].state = WebTouchPoint::StateStationary; |
| 769 | 789 |
| 770 break; | 790 break; |
| 771 } | 791 } |
| 772 } | 792 } |
| 773 } | 793 } |
| 774 | 794 |
| 775 if (last_sent_touchevent_) | 795 if (touch->event.type != WebInputEvent::TouchScrollStarted) { |
| 776 *last_sent_touchevent_ = touch->event; | 796 if (last_sent_touchevent_) |
| 777 else | 797 *last_sent_touchevent_ = touch->event; |
| 778 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); | 798 else |
| 799 last_sent_touchevent_.reset(new WebTouchEvent(touch->event)); | |
| 800 } | |
| 779 | 801 |
| 780 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | 802 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
| 781 | 803 |
| 782 client_->SendTouchEventImmediately(*touch); | 804 client_->SendTouchEventImmediately(*touch); |
| 783 | 805 |
| 784 // A synchronous ack will reset |dispatching_touch_|, in which case the touch | 806 // A synchronous ack will reset |dispatching_touch_|, in which case the touch |
| 785 // timeout should not be started and the count also should not be increased. | 807 // timeout should not be started and the count also should not be increased. |
| 786 if (dispatching_touch_) { | 808 if (dispatching_touch_) { |
| 787 if (touch->event.type == WebInputEvent::TouchMove && | 809 if (touch->event.type == WebInputEvent::TouchMove && |
| 788 !touch->event.cancelable) { | 810 !touch->event.cancelable) { |
| 789 // When we send out a uncancelable touch move, we increase the count and | 811 // When we send out a uncancelable touch move, we increase the count and |
| 790 // we do not process input event ack any more, we will just ack to client | 812 // we do not process input event ack any more, we will just ack to client |
| 791 // and wait for the ack from render. Also we will remove it from the front | 813 // and wait for the ack from render. Also we will remove it from the front |
| 792 // of the queue. | 814 // of the queue. |
| 793 ack_pending_async_touchmove_ids_.push_back( | 815 ack_pending_async_touchmove_ids_.push_back( |
| 794 touch->event.uniqueTouchEventId); | 816 touch->event.uniqueTouchEventId); |
| 795 dispatching_touch_ = false; | 817 dispatching_touch_ = false; |
| 796 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_IGNORED); | 818 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_IGNORED); |
| 797 TryForwardNextEventToRenderer(); | 819 TryForwardNextEventToRenderer(); |
| 798 return; | 820 return; |
| 799 } | 821 } |
| 800 | 822 |
| 801 if (timeout_handler_) | 823 if (timeout_handler_) |
| 802 timeout_handler_->StartIfNecessary(*touch); | 824 timeout_handler_->StartIfNecessary(*touch); |
| 803 } | 825 } |
| 804 } | 826 } |
| 805 | 827 |
| 806 TouchEventQueue::PreFilterResult | 828 TouchEventQueue::PreFilterResult |
| 807 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { | 829 TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) { |
| 830 if (event.type == WebInputEvent::TouchScrollStarted) | |
| 831 return FORWARD_TO_RENDERER; | |
| 832 | |
| 808 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { | 833 if (WebTouchEventTraits::IsTouchSequenceStart(event)) { |
| 809 has_handler_for_current_sequence_ = false; | 834 has_handler_for_current_sequence_ = false; |
| 810 send_touch_events_async_ = false; | 835 send_touch_events_async_ = false; |
| 811 pending_async_touchmove_.reset(); | 836 pending_async_touchmove_.reset(); |
| 812 last_sent_touchevent_.reset(); | 837 last_sent_touchevent_.reset(); |
| 813 | 838 |
| 814 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position); | 839 touch_sequence_start_position_ = gfx::PointF(event.touches[0].position); |
| 815 drop_remaining_touches_in_sequence_ = false; | 840 drop_remaining_touches_in_sequence_ = false; |
| 816 if (!has_handlers_) { | 841 if (!has_handlers_) { |
| 817 drop_remaining_touches_in_sequence_ = true; | 842 drop_remaining_touches_in_sequence_ = true; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 880 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) | 905 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
| 881 send_touch_events_async_ = false; | 906 send_touch_events_async_ = false; |
| 882 has_handler_for_current_sequence_ |= | 907 has_handler_for_current_sequence_ |= |
| 883 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | 908 ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; |
| 884 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { | 909 } else if (WebTouchEventTraits::IsTouchSequenceEnd(event)) { |
| 885 has_handler_for_current_sequence_ = false; | 910 has_handler_for_current_sequence_ = false; |
| 886 } | 911 } |
| 887 } | 912 } |
| 888 | 913 |
| 889 } // namespace content | 914 } // namespace content |
| OLD | NEW |