acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
slop_length_dips_(0),
- slop_includes_boundary_(true),
touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
virtual ~TouchEventQueueTest() {}
TouchEventQueue::Config config;
config.touch_scrolling_mode = touch_scrolling_mode_;
config.touchmove_slop_suppression_length_dips = slop_length_dips_;
- config.touchmove_slop_suppression_region_includes_boundary =
- slop_includes_boundary_;
return config;
}
ResetQueueWithConfig(CreateConfig());
}
- void SetUpForTouchMoveSlopTesting(double slop_length_dips,
- bool slop_includes_boundary) {
+ void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
slop_length_dips_ = slop_length_dips;
- slop_includes_boundary_ = slop_includes_boundary;
ResetQueueWithConfig(CreateConfig());
}
touch_event_.timeStampSeconds += seconds;
}
+ void ResetTouchEvent() {
+ touch_event_ = SyntheticWebTouchEvent();
+ }
+
size_t GetAndResetAckedEventCount() {
size_t count = acked_event_count_;
acked_event_count_ = 0;
void SetAckTimeoutDisabled() { queue_->SetAckTimeoutEnabled(false); }
- bool IsTimeoutEnabled() const { return queue_->ack_timeout_enabled(); }
-
bool IsTimeoutRunning() const { return queue_->IsTimeoutRunningForTesting(); }
bool HasPendingAsyncTouchMove() const {
scoped_ptr<WebGestureEvent> followup_gesture_event_;
scoped_ptr<InputEventAckState> sync_ack_result_;
double slop_length_dips_;
- bool slop_includes_boundary_;
TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
base::MessageLoopForUI message_loop_;
};
EXPECT_TRUE(acked_event().cancelable);
}
-// Tests that the touch-queue is emptied if a page stops listening for touch
-// events.
-TEST_F(TouchEventQueueTest, QueueFlushedWhenHandlersRemoved) {
+// Tests that touch-events with multiple points are queued properly.
+TEST_F(TouchEventQueueTest, BasicMultiTouch) {
+ const size_t kPointerCount = 10;
+ for (size_t i = 0; i < kPointerCount; ++i)
+ PressTouchPoint(i, i);
+
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount, queued_event_count());
+
+ for (size_t i = 0; i < kPointerCount; ++i)
+ MoveTouchPoint(i, 1.f + i, 2.f + i);
+
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ // All moves should coalesce.
+ EXPECT_EQ(kPointerCount + 1, queued_event_count());
+
+ for (size_t i = 0; i < kPointerCount; ++i)
+ ReleaseTouchPoint(kPointerCount - 1 - i);
+
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount * 2 + 1, queued_event_count());
+
+ // Ack all presses.
+ for (size_t i = 0; i < kPointerCount; ++i)
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount, GetAndResetSentEventCount());
+
+ // Ack the coalesced move.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Ack all releases.
+ for (size_t i = 0; i < kPointerCount; ++i)
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount - 1, GetAndResetSentEventCount());
+}
+
+// Tests that the touch-queue continues delivering events for an active pointer
+// after all handlers are removed, but acks new pointers immediately as having
+// no consumer.
+TEST_F(TouchEventQueueTest, NoNewTouchesForwardedAfterHandlersRemoved) {
OnHasTouchEventHandlers(true);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
// Send a touch-press event.
PressTouchPoint(1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
- 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());
+ // Signal that all touch handlers have been removed.
+ OnHasTouchEventHandlers(false);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, queued_event_count());
- // Receive an ACK for the first touch-event. One of the queued touch-event
- // should be forwarded.
+ // Process the ack for the sent touch, ensuring that it is honored (despite
+ // the touch handler having been removed).
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);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
- // Flush the queue. The touch-event queue should now be emptied, but none of
- // the queued touch-events should be sent to the renderer.
- OnHasTouchEventHandlers(false);
+ // Try forwarding a new pointer. It should be rejected immediately.
+ PressTouchPoint(2, 2);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
+
+ // Further events for the pointer without a handler should not be forwarded.
+ MoveTouchPoint(1, 3, 3);
+ ReleaseTouchPoint(1);
+ EXPECT_EQ(2U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
+
+ // Events for the first pointer, that had a handler, should be forwarded, even
+ // if the renderer reports that no handlers exist.
+ MoveTouchPoint(0, 4, 4);
+ ReleaseTouchPoint(0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
+
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(31U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
}
// Tests that addition of a touch handler during a touch sequence will not cause
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, GetAndResetSentEventCount());
- // Touch handle deregistration should flush the queue.
+ // Unregister all touch handlers.
OnHasTouchEventHandlers(false);
- EXPECT_EQ(2U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
- // The ack should be ignored as the touch queue is now empty.
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ // Repeated registration/unregstration of handlers should have no effect as
+ // we're still awaiting the ack arrival.
+ OnHasTouchEventHandlers(true);
EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+ OnHasTouchEventHandlers(false);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+
+ // The ack should be flush the queue.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_EQ(2U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
// Events should be dropped while there is no touch handler.
EXPECT_EQ(1U, GetAndResetSentEventCount());
}
+// Tests that removal/addition of a touch handler without any intervening
+// touch activity has no affect on touch forwarding.
+TEST_F(TouchEventQueueTest,
+ ActiveSequenceUnaffectedByRepeatedHandlerRemovalAndAddition) {
+ // Send a touch-press event.
+ PressTouchPoint(1, 1);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+
+ // Simulate the case where the touchstart handler removes itself, and adds a
+ // touchmove handler.
+ OnHasTouchEventHandlers(false);
+ OnHasTouchEventHandlers(true);
+
+ // Queue a touch-move event.
+ MoveTouchPoint(0, 5, 5);
+ EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ // The ack should trigger forwarding of the touchmove, as if no touch
+ // handler registration changes have occurred.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+}
+
// Tests that touch-events are coalesced properly in the queue.
TEST_F(TouchEventQueueTest, Coalesce) {
// Send a touch-press event.
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.
+// Tests that the touch-event queue is robust to redundant acks.
+TEST_F(TouchEventQueueTest, SpuriousAcksIgnored) {
+ // Trigger a spurious ack.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+
+ // Send and ack a touch press.
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());
-
- OnHasTouchEventHandlers(false);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
- // Now receive an ACK for the move.
+ // Trigger a spurious ack.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
// Tests that touch-move events are not sent to the renderer if the preceding
// 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.type = WebInputEvent::TouchMove;
followup_event.touchesLength = 1;
- followup_event.touches[0].id = 1;
- followup_event.touches[0].state = WebTouchPoint::StatePressed;
+ followup_event.touches[0].id = 0;
+ followup_event.touches[0].state = WebTouchPoint::StateMoved;
SetFollowupEvent(followup_event);
// Receive an ACK for the press. This should cause the followup touch-move to
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
+ MoveTouchPoint(0, 30, 15);
+ EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
// Queue another TouchStart.
PressTouchPoint(20, 20);
- EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(3U, 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);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(2U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
+
+ // GestureScrollUpdate inserts a synthetic TouchCancel before the TouchStart.
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
EXPECT_EQ(WebInputEvent::TouchCancel, sent_event().type);
EXPECT_FALSE(sent_event().cancelable);
EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
// Send the ack immediately. The timeout should not have fired.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(IsTimeoutRunning());
- EXPECT_TRUE(IsTimeoutEnabled());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
// Now explicitly disable the timeout.
SetAckTimeoutDisabled();
EXPECT_FALSE(IsTimeoutRunning());
- EXPECT_FALSE(IsTimeoutEnabled());
// A TouchMove should not start or trigger the timeout.
MoveTouchPoint(0, 5, 5);
EXPECT_FALSE(IsTimeoutRunning());
}
-// Tests that the timeout is disabled if the touch handler disappears.
-TEST_F(TouchEventQueueTest, NoTouchTimeoutIfTouchHandlerRemoved) {
- SetUpForTimeoutTesting(DefaultTouchTimeoutDelay());
-
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- ASSERT_TRUE(IsTimeoutRunning());
-
- // Unload the touch handler.
- OnHasTouchEventHandlers(false);
- EXPECT_FALSE(IsTimeoutRunning());
-}
-
// Tests that the timeout does not fire if explicitly disabled while an event
// is in-flight.
TEST_F(TouchEventQueueTest, NoTouchTimeoutIfDisabledWhileTimerIsActive) {
TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that TouchMove's are dropped if within the boundary-exclusive slop
-// suppression region for an unconsumed TouchStart.
-TEST_F(TouchEventQueueTest, TouchMoveSuppressionExcludingSlopBoundary) {
+// Tests that TouchMove's are not dropped within the slop suppression region if
+// the touchstart was consumed.
+TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = false;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ASSERT_EQ(1U, GetAndResetAckedEventCount());
- // TouchMove's within the region should be suppressed.
+ // TouchMove's within the region should not be suppressed, as a touch was
+ // consumed.
MoveTouchPoint(0, 0, kHalfSlopLengthDips);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
-
- MoveTouchPoint(0, kSlopLengthDips - 0.2f, 0);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
-
- // As soon as a TouchMove reaches the (Euclidean) slop distance, no more
- // TouchMove's should be suppressed.
- MoveTouchPoint(0, kSlopLengthDips, 0);
- EXPECT_EQ(1U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, GetAndResetAckedEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, kHalfSlopLengthDips, 0);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that TouchMove's are not dropped within the slop suppression region if
-// the touchstart was consumed.
-TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
- const double kSlopLengthDips = 10.;
- const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
-
+// Tests that even very small TouchMove's are not suppressed when suppression is
+// disabled.
+TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionIfDisabled) {
// Queue a TouchStart.
PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ASSERT_EQ(1U, GetAndResetAckedEventCount());
- // TouchMove's within the region should not be suppressed, as a touch was
- // consumed.
- MoveTouchPoint(0, 0, kHalfSlopLengthDips);
+ // Small TouchMove's should not be suppressed.
+ MoveTouchPoint(0, 0.001f, 0.001f);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
const float kSlopLengthPixels = 7.f;
const float kDPIScale = 3.f;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale,
- slop_includes_boundary);
+ SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale);
// Queue a TouchStart.
PressTouchPoint(0, 0);
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
const double kSlopLengthDips = 10.;
const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // Now send the first touch move and associated GestureScrollBegin,
- // but don't ACK the gesture event yet.
+ // Now send the first touch move and associated GestureScrollBegin.
MoveTouchPoint(0, 0, 5);
WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin;
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ SendGestureEventAck(WebInputEvent::GestureScrollBegin,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Send the second touch move and associated GestureScrollUpdate, but don't
+ // ACK the gesture event yet.
+ MoveTouchPoint(0, 0, 50);
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
// Now queue a second touchmove and verify it's not (yet) dispatched.
- MoveTouchPoint(0, 0, 10);
+ MoveTouchPoint(0, 0, 100);
+ SetFollowupEvent(followup_scroll);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(HasPendingAsyncTouchMove());
EXPECT_EQ(0U, queued_event_count());
// Queuing the final touchend should flush the pending, async touchmove.
ReleaseTouchPoint(0);
+ followup_scroll.type = WebInputEvent::GestureScrollEnd;
+ SetFollowupEvent(followup_scroll);
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_FALSE(sent_event().cancelable);
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // Now mark the scroll as not consumed (which would cause future
- // touchmoves in the active sequence to be sent if there was one).
- SendGestureEventAck(WebInputEvent::GestureScrollBegin,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ // Now mark the scrolls as not consumed (which would cause future touchmoves
+ // in the active sequence to be sent if there was one).
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
// Start a new touch sequence and verify that throttling has been reset.
// Touch moves after the start of scrolling will again be throttled.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
MoveTouchPoint(0, 0, 5);
+ followup_scroll.type = WebInputEvent::GestureScrollBegin;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ MoveTouchPoint(0, 0, 5);
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
SetFollowupEvent(followup_scroll);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
MoveTouchPoint(0, 0, 10);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(HasPendingAsyncTouchMove());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
+ SendGestureEvent(WebInputEvent::GestureScrollUpdate);
+
// The async touchmove should be ack'ed immediately, but not forwarded.
// However, because the ack triggers a touchcancel, both the pending touch and
// the queued touchcancel should be flushed.
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, GetAndResetSentEventCount());
- // The ack for the asnc touchmove should not reach the client, as it has
+ // The ack for the async touchmove should not reach the client, as it has
// already been ack'ed.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(sent_event().cancelable);
EXPECT_EQ(0U, GetAndResetSentEventCount());
}
+// Ensure that the async touch is fully reset if the touch sequence restarts
+// without properly terminating.
+TEST_F(TouchEventQueueTest, AsyncTouchWithHardTouchStartReset) {
+ SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
+
+ PressTouchPoint(0, 0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Trigger async touchmove dispatch.
+ MoveTouchPoint(0, 1, 1);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ WebGestureEvent followup_scroll;
+ followup_scroll.type = WebInputEvent::GestureScrollBegin;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ SendGestureEvent(WebInputEvent::GestureScrollUpdate);
+
+ // The async touchmove should be immediately ack'ed but delivery is deferred.
+ MoveTouchPoint(0, 2, 2);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type);
+
+ // The queue should be robust to hard touch restarts with a new touch
+ // sequence. In this case, the deferred async touch should not be flushed
+ // by the new touch sequence.
+ SendGestureEvent(WebInputEvent::GestureScrollEnd);
+ ResetTouchEvent();
+
+ PressTouchPoint(0, 0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+}
+
+TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
+ SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
+
+ // Queue a TouchStart.
+ PressTouchPoint(0, 1);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ MoveTouchPoint(0, 20, 5);
+ SendGestureEvent(blink::WebInputEvent::GestureScrollBegin);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+ // Even if the first touchmove event was consumed, subsequent unconsumed
+ // touchmove events should trigger scrolling.
+ MoveTouchPoint(0, 60, 5);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ MoveTouchPoint(0, 20, 5);
+ WebGestureEvent followup_scroll;
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Touch move event is throttled.
+ MoveTouchPoint(0, 60, 5);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+}
+
+TEST_F(TouchEventQueueTest, UnseenTouchPointerIdsNotForwarded) {
+ SyntheticWebTouchEvent event;
+ event.PressPoint(0, 0);
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a previously unseen pointer id; it should not be sent.
+ int press_id = event.touches[0].id;
+ event.MovePoint(0, 1, 1);
+ event.touches[0].id = 7;
+ SendTouchEvent(event);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a valid id; it should be sent.
+ event.touches[0].id = press_id;
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Do the same for release.
+ event.ReleasePoint(0);
+ event.touches[0].id = 11;
+ SendTouchEvent(event);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a valid id; it should be sent.
+ event.touches[0].id = press_id;
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+}
+
} // namespace content