blob: 9d88e2a28ef8a139a32d445d7cdeeb0e4cb51005 [file] [log] [blame]
// Copyright 2016 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/mouse_wheel_event_queue.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/location.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/renderer_host/input/timeout_monitor.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/base_event_utils.h"
using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebMouseWheelEvent;
namespace content {
namespace {
const float kWheelScrollX = 10;
const float kWheelScrollY = 12;
const float kWheelScrollGlobalX = 50;
const float kWheelScrollGlobalY = 72;
#define EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event) \
EXPECT_EQ(WebInputEvent::kGestureScrollBegin, event->GetType()); \
EXPECT_EQ(kWheelScrollX, event->x); \
EXPECT_EQ(kWheelScrollY, event->y); \
EXPECT_EQ(kWheelScrollGlobalX, event->global_x); \
EXPECT_EQ(kWheelScrollGlobalY, event->global_y); \
EXPECT_EQ(scroll_units, event->data.scroll_begin.delta_hint_units);
#define EXPECT_GESTURE_SCROLL_BEGIN(event) \
EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
EXPECT_FALSE(event->data.scroll_begin.synthetic); \
EXPECT_EQ(WebGestureEvent::kUnknownMomentumPhase, \
event->data.scroll_begin.inertial_phase);
#define EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(event) \
EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
EXPECT_FALSE(event->data.scroll_begin.synthetic); \
EXPECT_EQ(WebGestureEvent::kNonMomentumPhase, \
event->data.scroll_begin.inertial_phase);
#define EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(event) \
EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
EXPECT_TRUE(event->data.scroll_begin.synthetic); \
EXPECT_EQ(WebGestureEvent::kNonMomentumPhase, \
event->data.scroll_begin.inertial_phase);
#define EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
EXPECT_FALSE(event->data.scroll_begin.synthetic); \
EXPECT_EQ(WebGestureEvent::kMomentumPhase, \
event->data.scroll_begin.inertial_phase);
#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event); \
EXPECT_TRUE(event->data.scroll_begin.synthetic); \
EXPECT_EQ(WebGestureEvent::kMomentumPhase, \
event->data.scroll_begin.inertial_phase);
#define EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event) \
EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, event->GetType()); \
EXPECT_EQ(scroll_units, event->data.scroll_update.delta_units); \
EXPECT_EQ(kWheelScrollX, event->x); \
EXPECT_EQ(kWheelScrollY, event->y); \
EXPECT_EQ(kWheelScrollGlobalX, event->global_x); \
EXPECT_EQ(kWheelScrollGlobalY, event->global_y);
#define EXPECT_GESTURE_SCROLL_UPDATE(event) \
EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
EXPECT_EQ(WebGestureEvent::kUnknownMomentumPhase, \
event->data.scroll_update.inertial_phase);
#define EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(event) \
EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
EXPECT_EQ(WebGestureEvent::kNonMomentumPhase, \
event->data.scroll_update.inertial_phase);
#define EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(event) \
EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event); \
EXPECT_EQ(WebGestureEvent::kMomentumPhase, \
event->data.scroll_update.inertial_phase);
#define EXPECT_GESTURE_SCROLL_END_IMPL(event) \
EXPECT_EQ(WebInputEvent::kGestureScrollEnd, event->GetType()); \
EXPECT_EQ(scroll_units, event->data.scroll_end.delta_units); \
EXPECT_EQ(kWheelScrollX, event->x); \
EXPECT_EQ(kWheelScrollY, event->y); \
EXPECT_EQ(kWheelScrollGlobalX, event->global_x); \
EXPECT_EQ(kWheelScrollGlobalY, event->global_y);
#define EXPECT_GESTURE_SCROLL_END(event) \
EXPECT_GESTURE_SCROLL_END_IMPL(event); \
EXPECT_FALSE(event->data.scroll_end.synthetic); \
EXPECT_EQ(WebGestureEvent::kUnknownMomentumPhase, \
event->data.scroll_end.inertial_phase);
#define EXPECT_GESTURE_SCROLL_END_WITH_PHASE(event) \
EXPECT_GESTURE_SCROLL_END_IMPL(event); \
EXPECT_FALSE(event->data.scroll_end.synthetic); \
EXPECT_EQ(WebGestureEvent::kNonMomentumPhase, \
event->data.scroll_end.inertial_phase);
#define EXPECT_SYNTHETIC_GESTURE_SCROLL_END(event) \
EXPECT_GESTURE_SCROLL_END_IMPL(event); \
EXPECT_TRUE(event->data.scroll_end.synthetic); \
EXPECT_EQ(WebGestureEvent::kNonMomentumPhase, \
event->data.scroll_end.inertial_phase);
#define EXPECT_INERTIAL_GESTURE_SCROLL_END(event) \
EXPECT_GESTURE_SCROLL_END_IMPL(event); \
EXPECT_FALSE(event->data.scroll_end.synthetic); \
EXPECT_EQ(WebGestureEvent::kMomentumPhase, \
event->data.scroll_end.inertial_phase);
#define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(event) \
EXPECT_GESTURE_SCROLL_END_IMPL(event); \
EXPECT_TRUE(event->data.scroll_end.synthetic); \
EXPECT_EQ(WebGestureEvent::kMomentumPhase, \
event->data.scroll_end.inertial_phase);
#define EXPECT_MOUSE_WHEEL(event) \
EXPECT_EQ(WebInputEvent::kMouseWheel, event->GetType());
} // namespace
class MouseWheelEventQueueTest : public testing::TestWithParam<bool>,
public MouseWheelEventQueueClient {
public:
MouseWheelEventQueueTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {
scroll_latching_enabled_ = GetParam();
queue_.reset(new MouseWheelEventQueue(this, scroll_latching_enabled_));
scroll_end_timeout_ms_ = scroll_latching_enabled_ ? 100 : 0;
}
~MouseWheelEventQueueTest() override {}
// MouseWheelEventQueueClient
void SendMouseWheelEventImmediately(
const MouseWheelEventWithLatencyInfo& event) override {
WebMouseWheelEvent* cloned_event = new WebMouseWheelEvent();
std::unique_ptr<WebInputEvent> cloned_event_holder(cloned_event);
*cloned_event = event.event;
sent_events_.push_back(std::move(cloned_event_holder));
}
void ForwardGestureEventWithLatencyInfo(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency_info) override {
WebGestureEvent* cloned_event = new WebGestureEvent();
std::unique_ptr<WebInputEvent> cloned_event_holder(cloned_event);
*cloned_event = event;
sent_events_.push_back(std::move(cloned_event_holder));
}
void OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
InputEventAckState ack_result) override {
++acked_event_count_;
last_acked_event_ = event.event;
last_acked_event_state_ = ack_result;
}
base::TimeDelta DefaultScrollEndTimeoutDelay() {
return base::TimeDelta::FromMilliseconds(scroll_end_timeout_ms_);
}
bool scroll_latching_enabled() { return scroll_latching_enabled_; }
protected:
size_t queued_event_count() const { return queue_->queued_size(); }
bool event_in_flight() const { return queue_->event_in_flight(); }
std::vector<std::unique_ptr<WebInputEvent>>& all_sent_events() {
return sent_events_;
}
const std::unique_ptr<WebInputEvent>& sent_input_event(size_t index) {
return sent_events_[index];
}
const WebGestureEvent* sent_gesture_event(size_t index) {
return static_cast<WebGestureEvent*>(sent_events_[index].get());
}
const WebMouseWheelEvent& acked_event() const { return last_acked_event_; }
size_t GetAndResetSentEventCount() {
size_t count = sent_events_.size();
sent_events_.clear();
return count;
}
size_t GetAndResetAckedEventCount() {
size_t count = acked_event_count_;
acked_event_count_ = 0;
return count;
}
void SendMouseWheelEventAck(InputEventAckState ack_result) {
queue_->ProcessMouseWheelAck(ack_result, ui::LatencyInfo());
}
void SendMouseWheel(float x,
float y,
float global_x,
float global_y,
float dX,
float dY,
int modifiers,
bool high_precision,
WebInputEvent::RailsMode rails_mode) {
WebMouseWheelEvent event = SyntheticWebMouseWheelEventBuilder::Build(
x, y, global_x, global_y, dX, dY, modifiers, high_precision);
event.rails_mode = rails_mode;
queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
}
void SendMouseWheel(float x,
float y,
float global_x,
float global_y,
float dX,
float dY,
int modifiers,
bool high_precision) {
SendMouseWheel(x, y, global_x, global_y, dX, dY, modifiers, high_precision,
WebInputEvent::kRailsModeFree);
}
void SendMouseWheelWithPhase(
float x,
float y,
float global_x,
float global_y,
float dX,
float dY,
int modifiers,
bool high_precision,
blink::WebMouseWheelEvent::Phase phase,
blink::WebMouseWheelEvent::Phase momentum_phase) {
WebMouseWheelEvent event = SyntheticWebMouseWheelEventBuilder::Build(
x, y, global_x, global_y, dX, dY, modifiers, high_precision);
event.phase = phase;
event.momentum_phase = momentum_phase;
queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
}
void SendGestureEvent(WebInputEvent::Type type) {
WebGestureEvent event(type, WebInputEvent::kNoModifiers,
ui::EventTimeStampToSeconds(ui::EventTimeForNow()));
event.source_device = blink::kWebGestureDeviceTouchscreen;
queue_->OnGestureScrollEvent(
GestureEventWithLatencyInfo(event, ui::LatencyInfo()));
}
static void RunTasksAndWait(base::TimeDelta delay) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(), delay);
base::RunLoop().Run();
}
void GestureSendingTest(bool high_precision) {
const WebGestureEvent::ScrollUnits scroll_units =
high_precision ? WebGestureEvent::kPrecisePixels
: WebGestureEvent::kPixels;
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, high_precision);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// The second mouse wheel should not be sent since one is already in
// queue.
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 5, 5, 0, high_precision);
EXPECT_EQ(1U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(0U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event and release the next
// mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
if (scroll_latching_enabled_) {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_MOUSE_WHEEL(sent_input_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
RunTasksAndWait(DefaultScrollEndTimeoutDelay() * 2);
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
} else {
EXPECT_EQ(4U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_MOUSE_WHEEL(sent_input_event(3));
EXPECT_EQ(4U, GetAndResetSentEventCount());
}
}
void PhaseGestureSendingTest(bool high_precision) {
const WebGestureEvent::ScrollUnits scroll_units =
high_precision ? WebGestureEvent::kPrecisePixels
: WebGestureEvent::kPixels;
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, high_precision,
WebMouseWheelEvent::kPhaseBegan,
WebMouseWheelEvent::kPhaseNone);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
EXPECT_EQ(2U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 5, 5, 0, high_precision,
WebMouseWheelEvent::kPhaseChanged,
WebMouseWheelEvent::kPhaseNone);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
EXPECT_SYNTHETIC_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 0, 0, 0, high_precision,
WebMouseWheelEvent::kPhaseEnded,
WebMouseWheelEvent::kPhaseNone);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
// ScrollEnd is not sent right away, a timer starts instead,
// to see if a wheel event with momentumPhase arrives or not.
EXPECT_EQ(0U, all_sent_events().size());
EXPECT_EQ(0U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_END_WITH_PHASE(sent_gesture_event(1));
EXPECT_EQ(2U, GetAndResetSentEventCount());
}
// Send a double phase end; OSX does it consistently.
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 0, 0, 0, high_precision,
WebMouseWheelEvent::kPhaseEnded,
WebMouseWheelEvent::kPhaseNone);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, all_sent_events().size());
EXPECT_EQ(0U, GetAndResetSentEventCount());
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 5, 5, 0, high_precision,
WebMouseWheelEvent::kPhaseNone,
WebMouseWheelEvent::kPhaseBegan);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
// A fling has started, no ScrollEnd/ScrollBegin is sent.
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 5, 5, 0, high_precision,
WebMouseWheelEvent::kPhaseNone,
WebMouseWheelEvent::kPhaseChanged);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
SendMouseWheelWithPhase(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 0, 0, 0, high_precision,
WebMouseWheelEvent::kPhaseNone,
WebMouseWheelEvent::kPhaseEnded);
EXPECT_EQ(1U, GetAndResetSentEventCount());
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
if (scroll_latching_enabled_) {
// MomentumPhase is ended, the scroll is done, and GSE is sent
// immediately.
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(1));
EXPECT_EQ(2U, GetAndResetSentEventCount());
}
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<MouseWheelEventQueue> queue_;
std::vector<std::unique_ptr<WebInputEvent>> sent_events_;
size_t acked_event_count_;
InputEventAckState last_acked_event_state_;
WebMouseWheelEvent last_acked_event_;
int64_t scroll_end_timeout_ms_;
bool scroll_latching_enabled_;
};
// Tests that mouse wheel events are queued properly.
TEST_P(MouseWheelEventQueueTest, Basic) {
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// The second mouse wheel should not be sent since one is already in queue.
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 5, 5, 0, false);
EXPECT_EQ(1U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(0U, GetAndResetSentEventCount());
// Receive an ACK for the first mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
// Receive an ACK for the second mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
}
TEST_P(MouseWheelEventQueueTest, GestureSending) {
GestureSendingTest(false);
}
TEST_P(MouseWheelEventQueueTest, GestureSendingPrecisePixels) {
GestureSendingTest(true);
}
TEST_P(MouseWheelEventQueueTest, GestureSendingWithPhaseInformation) {
PhaseGestureSendingTest(false);
}
TEST_P(MouseWheelEventQueueTest,
GestureSendingWithPhaseInformationPrecisePixels) {
PhaseGestureSendingTest(true);
}
TEST_P(MouseWheelEventQueueTest, GestureSendingInterrupted) {
const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::kPixels;
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
if (scroll_latching_enabled_) {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_EQ(2U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
// Ensure that a gesture scroll begin terminates the current scroll event.
SendGestureEvent(WebInputEvent::kGestureScrollBegin);
if (scroll_latching_enabled_) {
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
// ScrollEnd has already been sent.
EXPECT_EQ(0U, all_sent_events().size());
}
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// New mouse wheel events won't cause gestures because a scroll
// is already in progress by another device.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, all_sent_events().size());
SendGestureEvent(WebInputEvent::kGestureScrollEnd);
EXPECT_EQ(0U, all_sent_events().size());
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
if (scroll_latching_enabled_) {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_EQ(2U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
}
TEST_P(MouseWheelEventQueueTest, GestureRailScrolling) {
const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::kPixels;
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false,
WebInputEvent::kRailsModeHorizontal);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
if (scroll_latching_enabled_) {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_x);
EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_y);
EXPECT_EQ(2U, GetAndResetSentEventCount());
RunTasksAndWait(DefaultScrollEndTimeoutDelay() * 2);
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(0));
EXPECT_EQ(1U, GetAndResetSentEventCount());
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(2));
EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_x);
EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_y);
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false,
WebInputEvent::kRailsModeVertical);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
if (scroll_latching_enabled_) {
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
} else {
EXPECT_EQ(3U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_GESTURE_SCROLL_END(sent_gesture_event(2));
}
EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_x);
EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_y);
if (scroll_latching_enabled_)
EXPECT_EQ(2U, GetAndResetSentEventCount());
else
EXPECT_EQ(3U, GetAndResetSentEventCount());
}
TEST_P(MouseWheelEventQueueTest, WheelScrollLatching) {
if (!scroll_latching_enabled_)
return;
const WebGestureEvent::ScrollUnits scroll_units = WebGestureEvent::kPixels;
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false,
WebInputEvent::kRailsModeVertical);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(2U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_BEGIN(sent_gesture_event(0));
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(1));
EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_x);
EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_y);
EXPECT_EQ(2U, GetAndResetSentEventCount());
RunTasksAndWait(DefaultScrollEndTimeoutDelay() / 2);
EXPECT_EQ(0U, GetAndResetSentEventCount());
SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
kWheelScrollGlobalY, 1, 1, 0, false,
WebInputEvent::kRailsModeVertical);
EXPECT_EQ(0U, queued_event_count());
EXPECT_TRUE(event_in_flight());
EXPECT_EQ(1U, GetAndResetSentEventCount());
// Receive an ACK for the mouse wheel event.
SendMouseWheelEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, queued_event_count());
EXPECT_FALSE(event_in_flight());
EXPECT_EQ(WebInputEvent::kMouseWheel, acked_event().GetType());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
// Scroll latching: no new scroll begin expected.
EXPECT_EQ(1U, all_sent_events().size());
EXPECT_GESTURE_SCROLL_UPDATE(sent_gesture_event(0));
EXPECT_EQ(0U, sent_gesture_event(0)->data.scroll_update.delta_x);
EXPECT_EQ(1U, sent_gesture_event(0)->data.scroll_update.delta_y);
EXPECT_EQ(1U, GetAndResetSentEventCount());
}
INSTANTIATE_TEST_CASE_P(MouseWheelEventQueueTests,
MouseWheelEventQueueTest,
testing::Bool());
} // namespace content