blob: eac532a7ec7d9432e2ba8b57e7a84cc9ec4b0fcd [file] [log] [blame]
// Copyright 2014 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 "content/browser/renderer_host/input/gesture_event_queue.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include <vector>
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
#include "content/common/input/input_event_ack_state.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "ui/events/blink/blink_features.h"
using base::TimeDelta;
using blink::WebGestureDevice;
using blink::WebGestureEvent;
using blink::WebInputEvent;
namespace content {
class GestureEventQueueTest : public testing::Test,
public GestureEventQueueClient,
public TouchpadTapSuppressionControllerClient {
public:
GestureEventQueueTest() : GestureEventQueueTest(false) {}
GestureEventQueueTest(bool enable_compositor_event_queue)
: acked_gesture_event_count_(0), sent_gesture_event_count_(0) {
if (enable_compositor_event_queue)
feature_list_.InitAndEnableFeature(features::kVsyncAlignedInputEvents);
else
feature_list_.InitAndDisableFeature(features::kVsyncAlignedInputEvents);
}
~GestureEventQueueTest() override {}
// testing::Test
void SetUp() override {
queue_.reset(new GestureEventQueue(this, this, DefaultConfig()));
}
void TearDown() override {
// Process all pending tasks to avoid leaks.
RunUntilIdle();
queue_.reset();
}
// GestureEventQueueClient
void SendGestureEventImmediately(
const GestureEventWithLatencyInfo& event) override {
++sent_gesture_event_count_;
if (sync_ack_result_) {
std::unique_ptr<InputEventAckState> ack_result =
std::move(sync_ack_result_);
SendInputEventACK(event.event.GetType(), *ack_result);
}
}
void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) override {
++acked_gesture_event_count_;
last_acked_event_ = event.event;
if (sync_followup_event_) {
auto sync_followup_event = std::move(sync_followup_event_);
SimulateGestureEvent(*sync_followup_event);
}
}
// TouchpadTapSuppressionControllerClient
void SendMouseEventImmediately(
const MouseEventWithLatencyInfo& event) override {}
protected:
static GestureEventQueue::Config DefaultConfig() {
return GestureEventQueue::Config();
}
void SetUpForDebounce(int interval_ms) {
queue()->set_debounce_interval_time_ms_for_testing(interval_ms);
}
void SimulateGestureEvent(const WebGestureEvent& gesture) {
queue()->QueueEvent(GestureEventWithLatencyInfo(gesture));
}
void SimulateGestureEvent(WebInputEvent::Type type,
WebGestureDevice sourceDevice) {
SimulateGestureEvent(
SyntheticWebGestureEventBuilder::Build(type, sourceDevice));
}
void SimulateGestureScrollUpdateEvent(float dX, float dY, int modifiers) {
SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildScrollUpdate(
dX, dY, modifiers, blink::kWebGestureDeviceTouchscreen));
}
void SimulateGesturePinchUpdateEvent(float scale,
float anchorX,
float anchorY,
int modifiers) {
SimulateGestureEvent(SyntheticWebGestureEventBuilder::BuildPinchUpdate(
scale, anchorX, anchorY, modifiers,
blink::kWebGestureDeviceTouchscreen));
}
void SimulateGestureFlingStartEvent(float velocityX,
float velocityY,
WebGestureDevice sourceDevice) {
SimulateGestureEvent(
SyntheticWebGestureEventBuilder::BuildFling(velocityX,
velocityY,
sourceDevice));
}
void SendInputEventACK(WebInputEvent::Type type,
InputEventAckState ack) {
queue()->ProcessGestureAck(ack, type, ui::LatencyInfo());
}
void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
size_t GetAndResetSentGestureEventCount() {
size_t count = sent_gesture_event_count_;
sent_gesture_event_count_ = 0;
return count;
}
size_t GetAndResetAckedGestureEventCount() {
size_t count = acked_gesture_event_count_;
acked_gesture_event_count_ = 0;
return count;
}
const WebGestureEvent& last_acked_event() const {
return last_acked_event_;
}
void set_synchronous_ack(InputEventAckState ack_result) {
sync_ack_result_.reset(new InputEventAckState(ack_result));
}
void set_sync_followup_event(WebInputEvent::Type type,
WebGestureDevice sourceDevice) {
sync_followup_event_.reset(new WebGestureEvent(
SyntheticWebGestureEventBuilder::Build(type, sourceDevice)));
}
unsigned GestureEventQueueSize() {
return queue()->coalesced_gesture_events_.size();
}
WebGestureEvent GestureEventSecondFromLastQueueEvent() {
return queue()->coalesced_gesture_events_.at(
GestureEventQueueSize() - 2).event;
}
WebGestureEvent GestureEventLastQueueEvent() {
return queue()->coalesced_gesture_events_.back().event;
}
unsigned GestureEventDebouncingQueueSize() {
return queue()->debouncing_deferral_queue_.size();
}
WebGestureEvent GestureEventQueueEventAt(int i) {
return queue()->coalesced_gesture_events_.at(i).event;
}
bool ScrollingInProgress() {
return queue()->scrolling_in_progress_;
}
bool FlingInProgress() { return queue()->fling_in_progress_; }
bool WillIgnoreNextACK() {
return queue()->ignore_next_ack_;
}
GestureEventQueue* queue() const {
return queue_.get();
}
private:
std::unique_ptr<GestureEventQueue> queue_;
size_t acked_gesture_event_count_;
size_t sent_gesture_event_count_;
WebGestureEvent last_acked_event_;
std::unique_ptr<InputEventAckState> sync_ack_result_;
std::unique_ptr<WebGestureEvent> sync_followup_event_;
base::MessageLoopForUI message_loop_;
base::test::ScopedFeatureList feature_list_;
};
#if GTEST_HAS_PARAM_TEST
// This is for tests that are to be run for all source devices.
class GestureEventQueueWithSourceTest
: public GestureEventQueueTest,
public testing::WithParamInterface<WebGestureDevice> {};
#endif // GTEST_HAS_PARAM_TEST
class GestureEventQueueWithCompositorEventQueueTest
: public GestureEventQueueTest {
public:
GestureEventQueueWithCompositorEventQueueTest()
: GestureEventQueueTest(true) {}
};
TEST_F(GestureEventQueueTest, CoalescesScrollGestureEvents) {
// Test coalescing of only GestureScrollUpdate events.
// Simulate gesture events.
// Sent.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Enqueued.
SimulateGestureScrollUpdateEvent(8, -5, 0);
// Make sure that the queue contains what we think it should.
WebGestureEvent merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Coalesced.
SimulateGestureScrollUpdateEvent(8, -6, 0);
// Check that coalescing updated the correct values.
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(0, merged_event.GetModifiers());
EXPECT_EQ(16, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-11, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGestureScrollUpdateEvent(8, -7, 1);
// Check that we didn't wrongly coalesce.
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Different.
SimulateGestureEvent(WebInputEvent::kGestureScrollEnd,
blink::kWebGestureDeviceTouchscreen);
// Check that only the first event was sent.
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
// Check that the ACK sends the second message.
SendInputEventACK(WebInputEvent::kGestureScrollBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Ack for queued coalesced event.
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Ack for queued uncoalesced event.
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// After the final ack, the queue should be empty.
SendInputEventACK(WebInputEvent::kGestureScrollEnd,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
}
TEST_F(GestureEventQueueTest,
DoesNotCoalesceScrollGestureEventsFromDifferentDevices) {
// Test that GestureScrollUpdate events from Touchscreen and Touchpad do not
// coalesce.
// Sent.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Enqueued.
SimulateGestureScrollUpdateEvent(8, -5, 0);
// Make sure that the queue contains what we think it should.
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
GestureEventLastQueueEvent().source_device);
// Coalesced.
SimulateGestureScrollUpdateEvent(8, -6, 0);
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
GestureEventLastQueueEvent().source_device);
// Enqueued.
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchpad);
EXPECT_EQ(3U, GestureEventQueueSize());
EXPECT_EQ(blink::kWebGestureDeviceTouchpad,
GestureEventLastQueueEvent().source_device);
// Coalesced.
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchpad);
EXPECT_EQ(3U, GestureEventQueueSize());
EXPECT_EQ(blink::kWebGestureDeviceTouchpad,
GestureEventLastQueueEvent().source_device);
// Enqueued.
SimulateGestureScrollUpdateEvent(8, -7, 0);
EXPECT_EQ(4U, GestureEventQueueSize());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen,
GestureEventLastQueueEvent().source_device);
}
TEST_F(GestureEventQueueTest, CoalescesScrollAndPinchEvents) {
// Test coalescing of only GestureScrollUpdate events.
// Simulate gesture events.
// Sent.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
// Sent.
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
// Enqueued.
SimulateGestureScrollUpdateEvent(8, -4, 1);
// Make sure that the queue contains what we think it should.
WebGestureEvent merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(3U, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
// Coalesced without changing event order. Note anchor at (60, 60). Anchoring
// from a point that is not the origin should still give us the right scroll.
SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(8, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-4, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGestureScrollUpdateEvent(6, -3, 1);
// Check whether coalesced correctly.
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(12, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-6, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGesturePinchUpdateEvent(2, 60, 60, 1);
// Check whether coalesced correctly.
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(3, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(12, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-6, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGesturePinchUpdateEvent(2, 60, 60, 1);
// Check whether coalesced correctly.
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(6, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(12, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-6, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Check that only the first event was sent.
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Check that the ACK sends the second message.
SendInputEventACK(WebInputEvent::kGestureScrollBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Enqueued.
SimulateGestureScrollUpdateEvent(6, -6, 1);
// Check whether coalesced correctly.
EXPECT_EQ(3U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(6, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(13, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-7, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// At this point ACKs shouldn't be getting ignored.
EXPECT_FALSE(WillIgnoreNextACK());
// Check that the ACK sends both scroll and pinch updates.
SendInputEventACK(WebInputEvent::kGesturePinchBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
// The next ACK should be getting ignored.
EXPECT_TRUE(WillIgnoreNextACK());
// Enqueued.
SimulateGestureScrollUpdateEvent(1, -1, 1);
// Check whether coalesced correctly.
EXPECT_EQ(3U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(1, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-1, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(6, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGestureScrollUpdateEvent(2, -2, 1);
// Coalescing scrolls should still work.
EXPECT_EQ(3U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(3, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-3, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(6, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Enqueued.
SimulateGesturePinchUpdateEvent(0.5, 60, 60, 1);
// Check whether coalesced correctly.
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(0.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(3, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-3, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Check that the ACK gets ignored.
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
RunUntilIdle();
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
// The flag should have been flipped back to false.
EXPECT_FALSE(WillIgnoreNextACK());
// Enqueued.
SimulateGestureScrollUpdateEvent(2, -2, 2);
// Shouldn't coalesce with different modifiers.
EXPECT_EQ(4U, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(2, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-2, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(2, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(0.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, merged_event.source_device);
// Check that the ACK sends the next scroll pinch pair.
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
RunUntilIdle();
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
// Check that the ACK sends the second message.
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
RunUntilIdle();
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
// Check that the ACK sends the second event.
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
// Check that the queue is empty after ACK and no events get sent.
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
RunUntilIdle();
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
}
TEST_F(GestureEventQueueTest, CoalescesMultiplePinchEventSequences) {
// Simulate a pinch sequence.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureScrollUpdateEvent(8, -4, 1);
// Make sure that the queue contains what we think it should.
WebGestureEvent merged_event = GestureEventLastQueueEvent();
size_t expected_events_in_queue = 3;
EXPECT_EQ(expected_events_in_queue, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
// Coalesced without changing event order. Note anchor at (60, 60). Anchoring
// from a point that is not the origin should still give us the right scroll.
SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
EXPECT_EQ(++expected_events_in_queue, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(8, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-4, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
// Enqueued.
SimulateGestureScrollUpdateEvent(6, -3, 1);
// Check whether coalesced correctly.
EXPECT_EQ(expected_events_in_queue, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(12, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-6, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
// Now start another sequence before the previous sequence has been ack'ed.
SimulateGestureEvent(WebInputEvent::kGesturePinchEnd,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureEvent(WebInputEvent::kGestureScrollEnd,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
SimulateGestureScrollUpdateEvent(8, -4, 1);
// Make sure that the queue contains what we think it should.
expected_events_in_queue += 5;
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(expected_events_in_queue, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
// Coalesced without changing event order. Note anchor at (60, 60). Anchoring
// from a point that is not the origin should still give us the right scroll.
SimulateGesturePinchUpdateEvent(1.5, 30, 30, 1);
EXPECT_EQ(++expected_events_in_queue, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(8, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-4, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
// Enqueued.
SimulateGestureScrollUpdateEvent(6, -3, 1);
// Check whether coalesced correctly.
EXPECT_EQ(expected_events_in_queue, GestureEventQueueSize());
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, merged_event.GetType());
EXPECT_EQ(1.5, merged_event.data.pinch_update.scale);
EXPECT_EQ(1, merged_event.GetModifiers());
merged_event = GestureEventSecondFromLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
EXPECT_EQ(12, merged_event.data.scroll_update.delta_x);
EXPECT_EQ(-6, merged_event.data.scroll_update.delta_y);
EXPECT_EQ(1, merged_event.GetModifiers());
}
TEST_F(GestureEventQueueTest, CoalescesPinchSequencesWithEarlyAck) {
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
SendInputEventACK(WebInputEvent::kGestureScrollBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
SendInputEventACK(WebInputEvent::kGesturePinchBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
// ScrollBegin and PinchBegin have been sent
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(5, 5, 1);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
GestureEventLastQueueEvent().GetType());
EXPECT_EQ(1U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(2, 60, 60, 1);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
GestureEventLastQueueEvent().GetType());
EXPECT_EQ(2U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(3, 60, 60, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
GestureEventLastQueueEvent().GetType());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(5, 5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
// The coalesced pinch/scroll pair will have been re-arranged, with the
// pinch following the scroll.
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
GestureEventLastQueueEvent().GetType());
EXPECT_EQ(4U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(4, 60, 60, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(4U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(2.f, last_acked_event().data.pinch_update.scale);
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(3.f * 4.f, last_acked_event().data.pinch_update.scale);
EXPECT_EQ(0U, GestureEventQueueSize());
}
TEST_F(GestureEventQueueTest,
DoesNotCoalescePinchGestureEventsWithDifferentModifiers) {
// Insert an event to force queueing of gestures.
SimulateGestureEvent(WebInputEvent::kGestureTapCancel,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(5, 5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(3, 60, 60, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(10, 15, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(4, 60, 60, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
// Using different modifiers should prevent coalescing.
SimulateGesturePinchUpdateEvent(5, 60, 60, 2);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(4U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(6, 60, 60, 3);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(5U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureTapCancel,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(4U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
EXPECT_EQ(3U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(3.f * 4.f, last_acked_event().data.pinch_update.scale);
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(5.f, last_acked_event().data.pinch_update.scale);
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(6.f, last_acked_event().data.pinch_update.scale);
EXPECT_EQ(0U, GestureEventQueueSize());
}
TEST_F(GestureEventQueueTest, CoalescesScrollAndPinchEventsIdentity) {
// Insert an event to force queueing of gestures.
SimulateGestureEvent(WebInputEvent::kGestureTapCancel,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
// Ensure that coalescing yields an identity transform for any pinch/scroll
// pair combined with its inverse.
SimulateGestureScrollUpdateEvent(5, 5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(5, 10, 10, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(.2f, 10, 10, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(-5, -5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureTapCancel,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
EXPECT_EQ(0.f, last_acked_event().data.scroll_update.delta_x);
EXPECT_EQ(0.f, last_acked_event().data.scroll_update.delta_y);
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(1.f, last_acked_event().data.pinch_update.scale);
EXPECT_EQ(0U, GestureEventQueueSize());
// Insert an event to force queueing of gestures.
SimulateGestureEvent(WebInputEvent::kGestureTapCancel,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
// Ensure that coalescing yields an identity transform for any pinch/scroll
// pair combined with its inverse.
SimulateGesturePinchUpdateEvent(2, 10, 10, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(20, 20, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(0.5f, 20, 20, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SimulateGestureScrollUpdateEvent(-5, -5, 1);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureTapCancel,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
EXPECT_EQ(0.f, last_acked_event().data.scroll_update.delta_x);
EXPECT_EQ(0.f, last_acked_event().data.scroll_update.delta_y);
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(1.f, last_acked_event().data.pinch_update.scale);
}
// Tests a single event with an synchronous ack.
TEST_F(GestureEventQueueTest, SimpleSyncAck) {
set_synchronous_ack(INPUT_EVENT_ACK_STATE_CONSUMED);
SimulateGestureEvent(WebInputEvent::kGestureTapDown,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
}
// Tests an event with an synchronous ack which enqueues an additional event.
TEST_F(GestureEventQueueTest, SyncAckQueuesEvent) {
std::unique_ptr<WebGestureEvent> queued_event;
set_synchronous_ack(INPUT_EVENT_ACK_STATE_CONSUMED);
set_sync_followup_event(WebInputEvent::kGestureShowPress,
blink::kWebGestureDeviceTouchscreen);
// This event enqueues the show press event.
SimulateGestureEvent(WebInputEvent::kGestureTapDown,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
SendInputEventACK(WebInputEvent::kGestureShowPress,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
}
// Tests an event with an async ack followed by an event with a sync ack.
TEST_F(GestureEventQueueTest, AsyncThenSyncAck) {
SimulateGestureEvent(WebInputEvent::kGestureTapDown,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(0U, GetAndResetAckedGestureEventCount());
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
set_synchronous_ack(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(0U, GetAndResetAckedGestureEventCount());
SendInputEventACK(WebInputEvent::kGestureTapDown,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
EXPECT_EQ(2U, GetAndResetAckedGestureEventCount());
}
TEST_F(GestureEventQueueTest, CoalescesScrollAndPinchEventWithSyncAck) {
// Simulate a pinch sequence.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
SimulateGestureScrollUpdateEvent(8, -4, 1);
// Make sure that the queue contains what we think it should.
WebGestureEvent merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(3U, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, merged_event.GetType());
// Coalesced without changing event order. Note anchor at (60, 60). Anchoring
// from a point that is not the origin should still give us the right scroll.
SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
EXPECT_EQ(4U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGestureScrollBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
// Ack the PinchBegin, and schedule a synchronous ack for GestureScrollUpdate.
set_synchronous_ack(INPUT_EVENT_ACK_STATE_CONSUMED);
SendInputEventACK(WebInputEvent::kGesturePinchBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
// Both GestureScrollUpdate and GesturePinchUpdate should have been sent.
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
// Ack the final GesturePinchUpdate.
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(0U, GestureEventQueueSize());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
}
#if GTEST_HAS_PARAM_TEST
TEST_P(GestureEventQueueWithSourceTest, GestureFlingCancelsFiltered) {
WebGestureDevice source_device = GetParam();
// GFC without previous GFS is dropped.
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
// GFC after previous GFS is dispatched and acked.
SimulateGestureFlingStartEvent(0, -10, source_device);
EXPECT_TRUE(FlingInProgress());
SendInputEventACK(WebInputEvent::kGestureFlingStart,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
SendInputEventACK(WebInputEvent::kGestureFlingCancel,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
// GFC before previous GFS is acked.
SimulateGestureFlingStartEvent(0, -10, source_device);
EXPECT_TRUE(FlingInProgress());
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
// Advance state realistically.
SendInputEventACK(WebInputEvent::kGestureFlingStart,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SendInputEventACK(WebInputEvent::kGestureFlingCancel,
INPUT_EVENT_ACK_STATE_CONSUMED);
RunUntilIdle();
EXPECT_EQ(2U, GetAndResetAckedGestureEventCount());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(0U, GestureEventQueueSize());
// GFS is added to the queue if another event is pending
SimulateGestureScrollUpdateEvent(8, -7, 0);
SimulateGestureFlingStartEvent(0, -10, source_device);
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
WebGestureEvent merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureFlingStart, merged_event.GetType());
EXPECT_TRUE(FlingInProgress());
EXPECT_EQ(2U, GestureEventQueueSize());
// GFS in queue means that a GFC is added to the queue
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
merged_event =GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(3U, GestureEventQueueSize());
// Adding a second GFC is dropped.
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(3U, GestureEventQueueSize());
// Adding another GFS will add it to the queue.
SimulateGestureFlingStartEvent(0, -10, source_device);
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureFlingStart, merged_event.GetType());
EXPECT_TRUE(FlingInProgress());
EXPECT_EQ(4U, GestureEventQueueSize());
// GFS in queue means that a GFC is added to the queue
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(5U, GestureEventQueueSize());
// Adding another GFC with a GFC already there is dropped.
SimulateGestureEvent(WebInputEvent::kGestureFlingCancel, source_device);
merged_event = GestureEventLastQueueEvent();
EXPECT_EQ(WebInputEvent::kGestureFlingCancel, merged_event.GetType());
EXPECT_FALSE(FlingInProgress());
EXPECT_EQ(5U, GestureEventQueueSize());
}
INSTANTIATE_TEST_CASE_P(AllSources,
GestureEventQueueWithSourceTest,
testing::Values(blink::kWebGestureDeviceTouchscreen,
blink::kWebGestureDeviceTouchpad));
#endif // GTEST_HAS_PARAM_TEST
// Test that a GestureScrollEnd | GestureFlingStart are deferred during the
// debounce interval, that Scrolls are not and that the deferred events are
// sent after that timer fires.
TEST_F(GestureEventQueueTest, DebounceDefersFollowingGestureEvents) {
SetUpForDebounce(3);
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
EXPECT_TRUE(ScrollingInProgress());
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
EXPECT_TRUE(ScrollingInProgress());
SimulateGestureEvent(WebInputEvent::kGestureScrollEnd,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(1U, GestureEventDebouncingQueueSize());
SimulateGestureFlingStartEvent(0, 10, blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(2U, GestureEventDebouncingQueueSize());
SimulateGestureEvent(WebInputEvent::kGestureTapDown,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(3U, GestureEventDebouncingQueueSize());
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
TimeDelta::FromMilliseconds(5));
base::RunLoop().Run();
// The deferred events are correctly queued in coalescing queue.
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(5U, GestureEventQueueSize());
EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
EXPECT_FALSE(ScrollingInProgress());
// Verify that the coalescing queue contains the correct events.
WebInputEvent::Type expected[] = {
WebInputEvent::kGestureScrollUpdate, WebInputEvent::kGestureScrollUpdate,
WebInputEvent::kGestureScrollEnd, WebInputEvent::kGestureFlingStart};
for (unsigned i = 0; i < sizeof(expected) / sizeof(WebInputEvent::Type);
i++) {
WebGestureEvent merged_event = GestureEventQueueEventAt(i);
EXPECT_EQ(expected[i], merged_event.GetType());
}
}
// Test that non-scroll events are deferred while scrolling during the debounce
// interval and are discarded if a GestureScrollUpdate event arrives before the
// interval end.
TEST_F(GestureEventQueueTest, DebounceDropsDeferredEvents) {
SetUpForDebounce(3);
EXPECT_FALSE(ScrollingInProgress());
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
EXPECT_TRUE(ScrollingInProgress());
// This event should get discarded.
SimulateGestureEvent(WebInputEvent::kGestureScrollEnd,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
EXPECT_EQ(1U, GestureEventDebouncingQueueSize());
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(0U, GestureEventDebouncingQueueSize());
EXPECT_TRUE(ScrollingInProgress());
// Verify that the coalescing queue contains the correct events.
WebInputEvent::Type expected[] = {WebInputEvent::kGestureScrollUpdate,
WebInputEvent::kGestureScrollUpdate};
for (unsigned i = 0; i < sizeof(expected) / sizeof(WebInputEvent::Type);
i++) {
WebGestureEvent merged_event = GestureEventQueueEventAt(i);
EXPECT_EQ(expected[i], merged_event.GetType());
}
}
TEST_F(GestureEventQueueTest, CoalescesSyntheticScrollBeginEndEvents) {
// Test coalescing of only GestureScrollBegin/End events.
SimulateGestureEvent(WebInputEvent::kGestureScrollUpdate,
blink::kWebGestureDeviceTouchpad);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
WebGestureEvent synthetic_end = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollEnd, blink::kWebGestureDeviceTouchpad);
synthetic_end.data.scroll_end.synthetic = true;
SimulateGestureEvent(synthetic_end);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(2U, GestureEventQueueSize());
// Synthetic begin will remove the unsent synthetic end.
WebGestureEvent synthetic_begin = SyntheticWebGestureEventBuilder::Build(
WebInputEvent::kGestureScrollBegin, blink::kWebGestureDeviceTouchpad);
synthetic_begin.data.scroll_begin.synthetic = true;
SimulateGestureEvent(synthetic_begin);
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
EXPECT_EQ(1U, GestureEventQueueSize());
}
TEST_F(GestureEventQueueWithCompositorEventQueueTest,
MultipleGesturesInFlight) {
// Simulate a pinch sequence, events should be forwarded immediately.
SimulateGestureEvent(WebInputEvent::kGestureScrollBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SimulateGestureEvent(WebInputEvent::kGesturePinchBegin,
blink::kWebGestureDeviceTouchscreen);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
SimulateGestureScrollUpdateEvent(8, -4, 1);
EXPECT_EQ(1U, GetAndResetSentGestureEventCount());
EXPECT_EQ(3U, GestureEventQueueSize());
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate,
GestureEventLastQueueEvent().GetType());
// Simulate 2 pinch update events.
SimulateGesturePinchUpdateEvent(1.5, 60, 60, 1);
EXPECT_EQ(4U, GestureEventQueueSize());
SimulateGesturePinchUpdateEvent(1.3, 60, 60, 1);
// Events should be forwarded immediately instead of being coalesced.
EXPECT_EQ(5U, GestureEventQueueSize());
EXPECT_EQ(2U, GetAndResetSentGestureEventCount());
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate,
GestureEventLastQueueEvent().GetType());
SendInputEventACK(WebInputEvent::kGestureScrollBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(4U, GestureEventQueueSize());
SendInputEventACK(WebInputEvent::kGesturePinchBegin,
INPUT_EVENT_ACK_STATE_CONSUMED);
SendInputEventACK(WebInputEvent::kGestureScrollUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
// Both GestureScrollUpdate and GesturePinchUpdate should have been sent.
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, last_acked_event().GetType());
EXPECT_EQ(2U, GestureEventQueueSize());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
// Ack the last 2 GesturePinchUpdate events.
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
SendInputEventACK(WebInputEvent::kGesturePinchUpdate,
INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(WebInputEvent::kGesturePinchUpdate, last_acked_event().GetType());
EXPECT_EQ(0U, GestureEventQueueSize());
EXPECT_EQ(0U, GetAndResetSentGestureEventCount());
}
} // namespace content