| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "content/browser/renderer_host/input/timeout_monitor.h" |
| #include "content/browser/renderer_host/input/touch_event_queue.h" |
| #include "content/common/input/synthetic_web_input_event_builders.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/web/WebInputEvent.h" |
| |
| using blink::WebGestureEvent; |
| using blink::WebInputEvent; |
| using blink::WebTouchEvent; |
| using blink::WebTouchPoint; |
| |
| namespace content { |
| namespace { |
| const size_t kDefaultTouchTimeoutDelayMs = 10; |
| } |
| |
| class TouchEventQueueTest : public testing::Test, |
| public TouchEventQueueClient { |
| public: |
| TouchEventQueueTest() |
| : sent_event_count_(0), |
| acked_event_count_(0), |
| last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {} |
| |
| virtual ~TouchEventQueueTest() {} |
| |
| // testing::Test |
| virtual void SetUp() OVERRIDE { |
| queue_.reset(new TouchEventQueue(this)); |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| queue_.reset(); |
| } |
| |
| // TouchEventQueueClient |
| virtual void SendTouchEventImmediately( |
| const TouchEventWithLatencyInfo& event) OVERRIDE { |
| ++sent_event_count_; |
| last_sent_event_ = event.event; |
| if (sync_ack_result_) |
| SendTouchEventACK(*sync_ack_result_.Pass()); |
| } |
| |
| virtual void OnTouchEventAck( |
| const TouchEventWithLatencyInfo& event, |
| InputEventAckState ack_result) OVERRIDE { |
| ++acked_event_count_; |
| last_acked_event_ = event.event; |
| last_acked_event_state_ = ack_result; |
| if (followup_touch_event_) { |
| scoped_ptr<WebTouchEvent> followup_touch_event = |
| followup_touch_event_.Pass(); |
| SendTouchEvent(*followup_touch_event); |
| } |
| if (followup_gesture_event_) { |
| scoped_ptr<WebGestureEvent> followup_gesture_event = |
| followup_gesture_event_.Pass(); |
| queue_->OnGestureScrollEvent( |
| GestureEventWithLatencyInfo(*followup_gesture_event, |
| ui::LatencyInfo())); |
| } |
| } |
| |
| protected: |
| |
| void SetUpForTimeoutTesting(size_t timeout_delay_ms) { |
| queue_->SetAckTimeoutEnabled(true, timeout_delay_ms); |
| } |
| |
| void SendTouchEvent(const WebTouchEvent& event) { |
| queue_->QueueEvent(TouchEventWithLatencyInfo(event, ui::LatencyInfo())); |
| } |
| |
| void SendGestureEvent(WebInputEvent::Type type) { |
| WebGestureEvent event; |
| event.type = type; |
| queue_->OnGestureScrollEvent( |
| GestureEventWithLatencyInfo(event, ui::LatencyInfo())); |
| } |
| |
| void SendTouchEventACK(InputEventAckState ack_result) { |
| queue_->ProcessTouchAck(ack_result, ui::LatencyInfo()); |
| } |
| |
| void SetFollowupEvent(const WebTouchEvent& event) { |
| followup_touch_event_.reset(new WebTouchEvent(event)); |
| } |
| |
| void SetFollowupEvent(const WebGestureEvent& event) { |
| followup_gesture_event_.reset(new WebGestureEvent(event)); |
| } |
| |
| void SetSyncAckResult(InputEventAckState sync_ack_result) { |
| sync_ack_result_.reset(new InputEventAckState(sync_ack_result)); |
| } |
| |
| void PressTouchPoint(int x, int y) { |
| touch_event_.PressPoint(x, y); |
| SendTouchEvent(); |
| } |
| |
| void MoveTouchPoint(int index, int x, int y) { |
| touch_event_.MovePoint(index, x, y); |
| SendTouchEvent(); |
| } |
| |
| void MoveTouchPoints(int index0, int x0, int y0, int index1, int x1, int y1) { |
| touch_event_.MovePoint(index0, x0, y0); |
| touch_event_.MovePoint(index1, x1, y1); |
| SendTouchEvent(); |
| } |
| |
| void ReleaseTouchPoint(int index) { |
| touch_event_.ReleasePoint(index); |
| SendTouchEvent(); |
| } |
| |
| void CancelTouchPoint(int index) { |
| touch_event_.CancelPoint(index); |
| SendTouchEvent(); |
| } |
| |
| size_t GetAndResetAckedEventCount() { |
| size_t count = acked_event_count_; |
| acked_event_count_ = 0; |
| return count; |
| } |
| |
| size_t GetAndResetSentEventCount() { |
| size_t count = sent_event_count_; |
| sent_event_count_ = 0; |
| return count; |
| } |
| |
| bool IsPendingAckTouchStart() const { |
| return queue_->IsPendingAckTouchStart(); |
| } |
| |
| void Flush() { |
| queue_->FlushQueue(); |
| } |
| |
| void SetEnableTouchForwarding(bool enabled) { |
| queue_->no_touch_to_renderer_ = !enabled; |
| } |
| |
| bool WillForwardTouchEvents() { |
| return !queue_->no_touch_to_renderer_ && !queue_->HasTimeoutEvent(); |
| } |
| |
| bool IsTimeoutRunning() { |
| return queue_->IsTimeoutRunningForTesting(); |
| } |
| |
| size_t queued_event_count() const { |
| return queue_->size(); |
| } |
| |
| const WebTouchEvent& latest_event() const { |
| return queue_->GetLatestEventForTesting().event; |
| } |
| |
| const WebTouchEvent& acked_event() const { |
| return last_acked_event_; |
| } |
| |
| const WebTouchEvent& sent_event() const { |
| return last_sent_event_; |
| } |
| |
| InputEventAckState acked_event_state() const { |
| return last_acked_event_state_; |
| } |
| |
| void set_no_touch_to_renderer(bool no_touch) { |
| queue_->no_touch_to_renderer_ = no_touch; |
| } |
| |
| bool no_touch_to_renderer() const { |
| return queue_->no_touch_to_renderer_; |
| } |
| |
| private: |
| void SendTouchEvent() { |
| SendTouchEvent(touch_event_); |
| touch_event_.ResetPoints(); |
| } |
| |
| scoped_ptr<TouchEventQueue> queue_; |
| size_t sent_event_count_; |
| size_t acked_event_count_; |
| WebTouchEvent last_sent_event_; |
| WebTouchEvent last_acked_event_; |
| InputEventAckState last_acked_event_state_; |
| SyntheticWebTouchEvent touch_event_; |
| scoped_ptr<WebTouchEvent> followup_touch_event_; |
| scoped_ptr<WebGestureEvent> followup_gesture_event_; |
| scoped_ptr<InputEventAckState> sync_ack_result_; |
| base::MessageLoopForUI message_loop_; |
| }; |
| |
| |
| // Tests that touch-events are queued properly. |
| TEST_F(TouchEventQueueTest, Basic) { |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // The second touch should not be sent since one is already in queue. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| // Receive an ACK for the first touch-event. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| |
| // Receive an ACK for the second touch-event. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| } |
| |
| // Tests that the touch-queue is emptied if a page stops listening for touch |
| // events. |
| TEST_F(TouchEventQueueTest, Flush) { |
| Flush(); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| // Send a touch-press event. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| ReleaseTouchPoint(0); |
| |
| // Events will be queued until the first sent event is ack'ed. |
| for (int i = 5; i < 15; ++i) { |
| PressTouchPoint(1, 1); |
| MoveTouchPoint(0, i, i); |
| ReleaseTouchPoint(0); |
| } |
| EXPECT_EQ(32U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| // Receive an ACK for the first touch-event. One of the queued touch-event |
| // should be forwarded. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(31U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| |
| // Flush the queue. The touch-event queue should now be emptied, but none of |
| // the queued touch-events should be sent to the renderer. |
| Flush(); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(31U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that touch-events are coalesced properly in the queue. |
| TEST_F(TouchEventQueueTest, Coalesce) { |
| // Send a touch-press event. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // Send a few touch-move events, followed by a touch-release event. All the |
| // touch-move events should be coalesced into a single event. |
| for (int i = 5; i < 15; ++i) |
| MoveTouchPoint(0, i, i); |
| |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(3U, queued_event_count()); |
| |
| // ACK the press. Coalesced touch-move events should be sent. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state()); |
| |
| // ACK the moves. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(10U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| |
| // ACK the release. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchEnd, acked_event().type); |
| } |
| |
| // Tests that an event that has already been sent but hasn't been ack'ed yet |
| // doesn't get coalesced with newer events. |
| TEST_F(TouchEventQueueTest, SentTouchEventDoesNotCoalesce) { |
| // Send a touch-press event. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // Send a few touch-move events, followed by a touch-release event. All the |
| // touch-move events should be coalesced into a single event. |
| for (int i = 5; i < 15; ++i) |
| MoveTouchPoint(0, i, i); |
| |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| // The coalesced touch-move event has been sent to the renderer. Any new |
| // touch-move event should not be coalesced with the sent event. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| MoveTouchPoint(0, 7, 7); |
| EXPECT_EQ(2U, queued_event_count()); |
| } |
| |
| // Tests that coalescing works correctly for multi-touch events. |
| TEST_F(TouchEventQueueTest, MultiTouch) { |
| // Press the first finger. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // Move the finger. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| // Now press a second finger. |
| PressTouchPoint(2, 2); |
| EXPECT_EQ(3U, queued_event_count()); |
| |
| // Move both fingers. |
| MoveTouchPoints(0, 10, 10, 1, 20, 20); |
| MoveTouchPoint(1, 20, 20); |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| // Move only one finger now. |
| MoveTouchPoint(0, 15, 15); |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| // Move the other finger. |
| MoveTouchPoint(1, 25, 25); |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| // Make sure both fingers are marked as having been moved in the coalesced |
| // event. |
| const WebTouchEvent& event = latest_event(); |
| EXPECT_EQ(WebTouchPoint::StateMoved, event.touches[0].state); |
| EXPECT_EQ(WebTouchPoint::StateMoved, event.touches[1].state); |
| } |
| |
| // Tests that if a touch-event queue is destroyed in response to a touch-event |
| // in the renderer, then there is no crash when the ACK for that touch-event |
| // comes back. |
| TEST_F(TouchEventQueueTest, AckAfterQueueFlushed) { |
| // Send some touch-events to the renderer. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| MoveTouchPoint(0, 10, 10); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| // Receive an ACK for the press. This should cause the queued touch-move to |
| // be sent to the renderer. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| Flush(); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| |
| // Now receive an ACK for the move. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| } |
| |
| // Tests that touch-move events are not sent to the renderer if the preceding |
| // touch-press event did not have a consumer (and consequently, did not hit the |
| // main thread in the renderer). Also tests that all queued/coalesced touch |
| // events are flushed immediately when the ACK for the touch-press comes back |
| // with NO_CONSUMER status. |
| TEST_F(TouchEventQueueTest, NoConsumer) { |
| // The first touch-press should reach the renderer. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // The second touch should not be sent since one is already in queue. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| // Receive an ACK for the first touch-event. This should release the queued |
| // touch-event, but it should not be sent to the renderer. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| EXPECT_EQ(2U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| // Send a release event. This should not reach the renderer. |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchEnd, acked_event().type); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Send a press-event, followed by move and release events, and another press |
| // event, before the ACK for the first press event comes back. All of the |
| // events should be queued first. After the NO_CONSUMER ack for the first |
| // touch-press, all events upto the second touch-press should be flushed. |
| PressTouchPoint(10, 10); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| MoveTouchPoint(0, 5, 5); |
| MoveTouchPoint(0, 6, 5); |
| ReleaseTouchPoint(0); |
| |
| PressTouchPoint(6, 5); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| // The queue should hold the first sent touch-press event, the coalesced |
| // touch-move event, the touch-end event and the second touch-press event. |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchEnd, acked_event().type); |
| EXPECT_EQ(4U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| // ACK the second press event as NO_CONSUMER too. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| |
| // Send a second press event. Even though the first touch had NO_CONSUMER, |
| // this press event should reach the renderer. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| } |
| |
| TEST_F(TouchEventQueueTest, ConsumerIgnoreMultiFinger) { |
| // Press two touch points and move them around a bit. The renderer consumes |
| // the events for the first touch point, but returns NO_CONSUMER_EXISTS for |
| // the second touch point. |
| |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| MoveTouchPoint(0, 5, 5); |
| |
| PressTouchPoint(10, 10); |
| |
| MoveTouchPoint(0, 2, 2); |
| |
| MoveTouchPoint(1, 4, 10); |
| |
| MoveTouchPoints(0, 10, 10, 1, 20, 20); |
| |
| // Since the first touch-press is still pending ACK, no other event should |
| // have been sent to the renderer. |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| // The queue includes the two presses, the first touch-move of the first |
| // point, and a coalesced touch-move of both points. |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| // ACK the first press as CONSUMED. This should cause the first touch-move of |
| // the first touch-point to be dispatched. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(3U, queued_event_count()); |
| |
| // ACK the first move as CONSUMED. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| // ACK the second press as NO_CONSUMER_EXISTS. This will dequeue the coalesced |
| // touch-move event (which contains both touch points). Although the second |
| // touch-point does not need to be sent to the renderer, the first touch-point |
| // did move, and so the coalesced touch-event will be sent to the renderer. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| // ACK the coalesced move as NOT_CONSUMED. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| |
| // Move just the second touch point. Because the first touch point did not |
| // move, this event should not reach the renderer. |
| MoveTouchPoint(1, 30, 30); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| |
| // Move just the first touch point. This should reach the renderer. |
| MoveTouchPoint(0, 10, 10); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| // Move both fingers. This event should reach the renderer (after the ACK of |
| // the previous move event is received), because the first touch point did |
| // move. |
| MoveTouchPoints(0, 15, 15, 1, 25, 25); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| |
| // Release the first finger. Then move the second finger around some, then |
| // press another finger. Once the release event is ACKed, the move events of |
| // the second finger should be immediately released to the view, and the |
| // touch-press event should be dispatched to the renderer. |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, queued_event_count()); |
| |
| MoveTouchPoint(1, 40, 40); |
| |
| MoveTouchPoint(1, 50, 50); |
| |
| PressTouchPoint(1, 1); |
| |
| MoveTouchPoint(1, 30, 30); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(4U, queued_event_count()); |
| |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| |
| // ACK the press with NO_CONSUMED_EXISTS. This should release the queued |
| // touch-move events to the view. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| |
| ReleaseTouchPoint(2); |
| ReleaseTouchPoint(1); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, queued_event_count()); |
| } |
| |
| // Tests that touch-event's enqueued via a touch ack are properly handled. |
| TEST_F(TouchEventQueueTest, AckWithFollowupEvents) { |
| // Queue a touch down. |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| |
| // Create a touch event that will be queued synchronously by a touch ack. |
| // Note, this will be triggered by all subsequent touch acks. |
| WebTouchEvent followup_event; |
| followup_event.type = WebInputEvent::TouchStart; |
| followup_event.touchesLength = 1; |
| followup_event.touches[0].id = 1; |
| followup_event.touches[0].state = WebTouchPoint::StatePressed; |
| SetFollowupEvent(followup_event); |
| |
| // Receive an ACK for the press. This should cause the followup touch-move to |
| // be sent to the renderer. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| |
| // Queue another event. |
| MoveTouchPoint(0, 2, 2); |
| EXPECT_EQ(2U, queued_event_count()); |
| |
| // Receive an ACK for the touch-move followup event. This should cause the |
| // subsequent touch move event be sent to the renderer. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that touch-events can be synchronously ack'ed. |
| TEST_F(TouchEventQueueTest, SynchronousAcks) { |
| // TouchStart |
| SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchMove |
| SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
| MoveTouchPoint(0, 2, 2); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchEnd |
| SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchCancel (first inserting a TouchStart so the TouchCancel will be sent) |
| PressTouchPoint(1, 1); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
| CancelTouchPoint(0); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that followup events triggered by an immediate ack from |
| // TouchEventQueue::QueueEvent() are properly handled. |
| TEST_F(TouchEventQueueTest, ImmediateAckWithFollowupEvents) { |
| // Create a touch event that will be queued synchronously by a touch ack. |
| WebTouchEvent followup_event; |
| followup_event.type = WebInputEvent::TouchStart; |
| followup_event.touchesLength = 1; |
| followup_event.touches[0].id = 1; |
| followup_event.touches[0].state = WebTouchPoint::StatePressed; |
| SetFollowupEvent(followup_event); |
| |
| // Now, enqueue a stationary touch that will not be forwarded. This should be |
| // immediately ack'ed with "NO_CONSUMER_EXISTS". The followup event should |
| // then be enqueued and immediately sent to the renderer. |
| WebTouchEvent stationary_event; |
| stationary_event.touchesLength = 1; |
| stationary_event.type = WebInputEvent::TouchMove; |
| stationary_event.touches[0].id = 1; |
| stationary_event.touches[0].state = WebTouchPoint::StateStationary; |
| SendTouchEvent(stationary_event); |
| |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); |
| EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type); |
| } |
| |
| // Tests basic TouchEvent forwarding suppression. |
| TEST_F(TouchEventQueueTest, NoTouchBasic) { |
| // Disable TouchEvent forwarding. |
| SetEnableTouchForwarding(false); |
| MoveTouchPoint(0, 30, 5); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchMove should not be sent to renderer. |
| MoveTouchPoint(0, 65, 10); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchEnd should not be sent to renderer. |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // TouchStart should not be sent to renderer. |
| PressTouchPoint(5, 5); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Enable TouchEvent forwarding. |
| SetEnableTouchForwarding(true); |
| |
| PressTouchPoint(80, 10); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| MoveTouchPoint(0, 80, 20); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that no TouchEvents are sent to renderer during scrolling. |
| TEST_F(TouchEventQueueTest, NoTouchOnScroll) { |
| // Queue a TouchStart. |
| PressTouchPoint(0, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| MoveTouchPoint(0, 20, 5); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // Queue another TouchStart. |
| PressTouchPoint(20, 20); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type); |
| |
| // GestureScrollBegin inserts a synthetic TouchCancel before the TouchStart. |
| WebGestureEvent followup_scroll; |
| followup_scroll.type = WebInputEvent::GestureScrollBegin; |
| SetFollowupEvent(followup_scroll); |
| ASSERT_TRUE(WillForwardTouchEvents()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_EQ(WebInputEvent::TouchCancel, sent_event().type); |
| EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type); |
| |
| // Acking the TouchCancel will result in dispatch of the next TouchStart. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| // The synthetic TouchCancel should not reach client, only the TouchStart. |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type); |
| |
| // TouchMove should not be sent to the renderer. |
| MoveTouchPoint(0, 30, 5); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); |
| |
| // GestureScrollUpdates should not change affect touch forwarding. |
| SendGestureEvent(WebInputEvent::GestureScrollUpdate); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| |
| // TouchEnd should not be sent to the renderer. |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); |
| |
| // GestureScrollEnd will resume the sending of TouchEvents to renderer. |
| SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| |
| // Now TouchEvents should be forwarded normally. |
| PressTouchPoint(80, 10); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| MoveTouchPoint(0, 80, 20); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| ReleaseTouchPoint(0); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that IsTouchStartPendingAck works correctly. |
| TEST_F(TouchEventQueueTest, PendingStart) { |
| |
| EXPECT_FALSE(IsPendingAckTouchStart()); |
| |
| // Send the touchstart for one point (#1). |
| PressTouchPoint(1, 1); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_TRUE(IsPendingAckTouchStart()); |
| |
| // Send a touchmove for that point (#2). |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_TRUE(IsPendingAckTouchStart()); |
| |
| // Ack the touchstart (#1). |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_FALSE(IsPendingAckTouchStart()); |
| |
| // Send a touchstart for another point (#3). |
| PressTouchPoint(10, 10); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_FALSE(IsPendingAckTouchStart()); |
| |
| // Ack the touchmove (#2). |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_TRUE(IsPendingAckTouchStart()); |
| |
| // Send a touchstart for a third point (#4). |
| PressTouchPoint(15, 15); |
| EXPECT_EQ(2U, queued_event_count()); |
| EXPECT_TRUE(IsPendingAckTouchStart()); |
| |
| // Ack the touchstart for the second point (#3). |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(1U, queued_event_count()); |
| EXPECT_TRUE(IsPendingAckTouchStart()); |
| |
| // Ack the touchstart for the third point (#4). |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(0U, queued_event_count()); |
| EXPECT_FALSE(IsPendingAckTouchStart()); |
| } |
| |
| // Tests that the touch timeout is started when sending certain touch types. |
| TEST_F(TouchEventQueueTest, TouchTimeoutTypes) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Sending a TouchStart will start the timeout. |
| PressTouchPoint(0, 1); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| |
| // A TouchMove should start the timeout. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| |
| // A TouchEnd should not start the timeout. |
| ReleaseTouchPoint(0); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| |
| // A TouchCancel should not start the timeout. |
| PressTouchPoint(0, 1); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| ASSERT_FALSE(IsTimeoutRunning()); |
| CancelTouchPoint(0); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| } |
| |
| // Tests that a delayed TouchEvent ack will trigger a TouchCancel timeout, |
| // disabling touch forwarding until the next TouchStart is received after |
| // the timeout events are ack'ed. |
| TEST_F(TouchEventQueueTest, TouchTimeoutBasic) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| GetAndResetSentEventCount(); |
| GetAndResetAckedEventCount(); |
| PressTouchPoint(0, 1); |
| ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| ASSERT_EQ(0U, GetAndResetAckedEventCount()); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| |
| // Delay the ack. |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::MessageLoop::QuitClosure(), |
| base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
| base::MessageLoop::current()->Run(); |
| |
| // The timeout should have fired, synthetically ack'ing the timed-out event. |
| // TouchEvent forwarding is disabled until the ack is received for the |
| // timed-out event and the future cancel event. |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Ack'ing the original event should trigger a cancel event. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // Touch events should not be forwarded until we receive the cancel acks. |
| PressTouchPoint(0, 1); |
| ASSERT_EQ(0U, GetAndResetSentEventCount()); |
| ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // The synthetic TouchCancel ack should not reach the client, but should |
| // resume touch forwarding. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| |
| // Subsequent events should be handled normally. |
| PressTouchPoint(0, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that the timeout is never started if the renderer consumes |
| // a TouchEvent from the current touch sequence. |
| TEST_F(TouchEventQueueTest, NoTouchTimeoutIfRendererIsConsumingGesture) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| PressTouchPoint(0, 1); |
| ASSERT_TRUE(IsTimeoutRunning()); |
| |
| // Mark the event as consumed. This should prevent the timeout from |
| // being activated on subsequent TouchEvents in this gesture. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| |
| // A TouchMove should not start the timeout. |
| MoveTouchPoint(0, 5, 5); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| |
| // A secondary TouchStart should not start the timeout. |
| PressTouchPoint(1, 0); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| |
| // A TouchEnd should not start the timeout. |
| ReleaseTouchPoint(1); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| |
| // A TouchCancel should not start the timeout. |
| CancelTouchPoint(0); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| } |
| |
| // Tests that the timeout is never started if the ack is synchronous. |
| TEST_F(TouchEventQueueTest, NoTouchTimeoutIfAckIsSynchronous) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| SetSyncAckResult(INPUT_EVENT_ACK_STATE_CONSUMED); |
| ASSERT_FALSE(IsTimeoutRunning()); |
| PressTouchPoint(0, 1); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| } |
| |
| // Tests that a TouchCancel timeout plays nice when the timed out touch stream |
| // turns into a scroll gesture sequence. |
| TEST_F(TouchEventQueueTest, TouchTimeoutWithFollowupGesture) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| PressTouchPoint(0, 1); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // The cancelled sequence may turn into a scroll gesture. |
| WebGestureEvent followup_scroll; |
| followup_scroll.type = WebInputEvent::GestureScrollBegin; |
| SetFollowupEvent(followup_scroll); |
| |
| // Delay the ack. |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::MessageLoop::QuitClosure(), |
| base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
| base::MessageLoop::current()->Run(); |
| |
| // The timeout should have fired, disabling touch forwarding until both acks |
| // are received, acking the timed out event. |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Ack the original event, triggering a TouchCancel. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| |
| // Ack the cancel event. Normally, this would resume touch forwarding, |
| // but we're still within a scroll gesture so it remains disabled. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| |
| // Try to forward a touch event. |
| GetAndResetSentEventCount(); |
| GetAndResetAckedEventCount(); |
| PressTouchPoint(0, 1); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Now end the scroll sequence, resuming touch handling. |
| SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| PressTouchPoint(0, 1); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| } |
| |
| // Tests that a TouchCancel timeout plays nice when the timed out touch stream |
| // turns into a scroll gesture sequence, but the original event acks are |
| // significantly delayed. |
| TEST_F(TouchEventQueueTest, TouchTimeoutWithFollowupGestureAndDelayedAck) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| PressTouchPoint(0, 1); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| |
| // The cancelled sequence may turn into a scroll gesture. |
| WebGestureEvent followup_scroll; |
| followup_scroll.type = WebInputEvent::GestureScrollBegin; |
| SetFollowupEvent(followup_scroll); |
| |
| // Delay the ack. |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::MessageLoop::QuitClosure(), |
| base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
| base::MessageLoop::current()->Run(); |
| |
| // The timeout should have fired, disabling touch forwarding until both acks |
| // are received and acking the timed out event. |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Try to forward a touch event. |
| GetAndResetSentEventCount(); |
| GetAndResetAckedEventCount(); |
| PressTouchPoint(0, 1); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Now end the scroll sequence. Events will not be forwarded until the two |
| // outstanding touch acks are received. |
| SendGestureEvent(blink::WebInputEvent::GestureScrollEnd); |
| PressTouchPoint(0, 1); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Ack the original event, triggering a cancel. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| |
| // Ack the cancel event, resuming touch forwarding. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| |
| PressTouchPoint(0, 1); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| } |
| |
| // Tests that a delayed TouchEvent ack will not trigger a TouchCancel timeout if |
| // the timed-out event had no consumer. |
| TEST_F(TouchEventQueueTest, NoCancelOnTouchTimeoutWithoutConsumer) { |
| SetUpForTimeoutTesting(kDefaultTouchTimeoutDelayMs); |
| |
| // Queue a TouchStart. |
| PressTouchPoint(0, 1); |
| ASSERT_EQ(1U, GetAndResetSentEventCount()); |
| ASSERT_EQ(0U, GetAndResetAckedEventCount()); |
| EXPECT_TRUE(IsTimeoutRunning()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| |
| // Delay the ack. |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::MessageLoop::QuitClosure(), |
| base::TimeDelta::FromMilliseconds(kDefaultTouchTimeoutDelayMs * 2)); |
| base::MessageLoop::current()->Run(); |
| |
| // The timeout should have fired, synthetically ack'ing the timed out event. |
| // TouchEvent forwarding is disabled until the original ack is received. |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_FALSE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| EXPECT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Touch events should not be forwarded until we receive the original ack. |
| PressTouchPoint(0, 1); |
| ASSERT_EQ(0U, GetAndResetSentEventCount()); |
| ASSERT_EQ(1U, GetAndResetAckedEventCount()); |
| |
| // Ack'ing the original event should not trigger a cancel event, as the |
| // TouchStart had no consumer. However, it should re-enable touch forwarding. |
| SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); |
| EXPECT_FALSE(IsTimeoutRunning()); |
| EXPECT_TRUE(WillForwardTouchEvents()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| EXPECT_EQ(0U, GetAndResetSentEventCount()); |
| |
| // Subsequent events should be handled normally. |
| PressTouchPoint(0, 1); |
| EXPECT_EQ(1U, GetAndResetSentEventCount()); |
| EXPECT_EQ(0U, GetAndResetAckedEventCount()); |
| } |
| } // namespace content |