1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/renderer_host/input/mouse_wheel_event_queue.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "base/location.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/test/metrics/histogram_tester.h"
16 #include "base/test/task_environment.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "build/build_config.h"
19 #include "build/chromeos_buildflags.h"
20 #include "content/browser/renderer_host/input/timeout_monitor.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
23 #include "third_party/blink/public/common/input/web_input_event.h"
24 #include "ui/events/base_event_utils.h"
25 
26 using blink::WebGestureEvent;
27 using blink::WebInputEvent;
28 using blink::WebMouseWheelEvent;
29 
30 namespace content {
31 namespace {
32 
33 const float kWheelScrollX = 10;
34 const float kWheelScrollY = 12;
35 const float kWheelScrollGlobalX = 50;
36 const float kWheelScrollGlobalY = 72;
37 
38 #define EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event)                          \
39   EXPECT_EQ(WebInputEvent::Type::kGestureScrollBegin, event->GetType()); \
40   EXPECT_EQ(kWheelScrollX, event->PositionInWidget().x());               \
41   EXPECT_EQ(kWheelScrollY, event->PositionInWidget().y());               \
42   EXPECT_EQ(kWheelScrollGlobalX, event->PositionInScreen().x());         \
43   EXPECT_EQ(kWheelScrollGlobalY, event->PositionInScreen().y());         \
44   EXPECT_EQ(scroll_units, event->data.scroll_begin.delta_hint_units);
45 
46 #define EXPECT_GESTURE_SCROLL_BEGIN(event)                         \
47   EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                         \
48   EXPECT_FALSE(event->data.scroll_begin.synthetic);                \
49   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kUnknownMomentum, \
50             event->data.scroll_begin.inertial_phase);
51 
52 #define EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(event)          \
53   EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                     \
54   EXPECT_FALSE(event->data.scroll_begin.synthetic);            \
55   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kNonMomentum, \
56             event->data.scroll_begin.inertial_phase);
57 
58 #define EXPECT_SYNTHETIC_GESTURE_SCROLL_BEGIN(event)           \
59   EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                     \
60   EXPECT_TRUE(event->data.scroll_begin.synthetic);             \
61   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kNonMomentum, \
62             event->data.scroll_begin.inertial_phase);
63 
64 #define EXPECT_INERTIAL_GESTURE_SCROLL_BEGIN(event)         \
65   EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                  \
66   EXPECT_FALSE(event->data.scroll_begin.synthetic);         \
67   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum, \
68             event->data.scroll_begin.inertial_phase);
69 
70 #define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_BEGIN(event) \
71   EXPECT_GESTURE_SCROLL_BEGIN_IMPL(event);                    \
72   EXPECT_TRUE(event->data.scroll_begin.synthetic);            \
73   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum,   \
74             event->data.scroll_begin.inertial_phase);
75 
76 #define EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event)                          \
77   EXPECT_EQ(WebInputEvent::Type::kGestureScrollUpdate, event->GetType()); \
78   EXPECT_EQ(scroll_units, event->data.scroll_update.delta_units);         \
79   EXPECT_EQ(kWheelScrollX, event->PositionInWidget().x());                \
80   EXPECT_EQ(kWheelScrollY, event->PositionInWidget().y());                \
81   EXPECT_EQ(kWheelScrollGlobalX, event->PositionInScreen().x());          \
82   EXPECT_EQ(kWheelScrollGlobalY, event->PositionInScreen().y());
83 
84 #define EXPECT_GESTURE_SCROLL_UPDATE(event)                        \
85   EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event);                        \
86   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kUnknownMomentum, \
87             event->data.scroll_update.inertial_phase);
88 
89 #define EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(event)         \
90   EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event);                    \
91   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kNonMomentum, \
92             event->data.scroll_update.inertial_phase);
93 
94 #define EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(event)        \
95   EXPECT_GESTURE_SCROLL_UPDATE_IMPL(event);                 \
96   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum, \
97             event->data.scroll_update.inertial_phase);
98 
99 #define EXPECT_GESTURE_SCROLL_END_IMPL(event)                          \
100   EXPECT_EQ(WebInputEvent::Type::kGestureScrollEnd, event->GetType()); \
101   EXPECT_EQ(scroll_units, event->data.scroll_end.delta_units);         \
102   EXPECT_EQ(kWheelScrollX, event->PositionInWidget().x());             \
103   EXPECT_EQ(kWheelScrollY, event->PositionInWidget().y());             \
104   EXPECT_EQ(kWheelScrollGlobalX, event->PositionInScreen().x());       \
105   EXPECT_EQ(kWheelScrollGlobalY, event->PositionInScreen().y());
106 
107 #define EXPECT_GESTURE_SCROLL_END(event)                           \
108   EXPECT_GESTURE_SCROLL_END_IMPL(event);                           \
109   EXPECT_FALSE(event->data.scroll_end.synthetic);                  \
110   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kUnknownMomentum, \
111             event->data.scroll_end.inertial_phase);
112 
113 #define EXPECT_GESTURE_SCROLL_END_WITH_PHASE(event)            \
114   EXPECT_GESTURE_SCROLL_END_IMPL(event);                       \
115   EXPECT_FALSE(event->data.scroll_end.synthetic);              \
116   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kNonMomentum, \
117             event->data.scroll_end.inertial_phase);
118 
119 #define EXPECT_SYNTHETIC_GESTURE_SCROLL_END(event)             \
120   EXPECT_GESTURE_SCROLL_END_IMPL(event);                       \
121   EXPECT_TRUE(event->data.scroll_end.synthetic);               \
122   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kNonMomentum, \
123             event->data.scroll_end.inertial_phase);
124 
125 #define EXPECT_INERTIAL_GESTURE_SCROLL_END(event)           \
126   EXPECT_GESTURE_SCROLL_END_IMPL(event);                    \
127   EXPECT_FALSE(event->data.scroll_end.synthetic);           \
128   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum, \
129             event->data.scroll_end.inertial_phase);
130 
131 #if BUILDFLAG(IS_CHROMEOS_ASH)
132 #define EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(event) \
133   EXPECT_GESTURE_SCROLL_END_IMPL(event);                    \
134   EXPECT_TRUE(event->data.scroll_end.synthetic);            \
135   EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum, \
136             event->data.scroll_end.inertial_phase);         \
137   EXPECT_TRUE(event->data.scroll_end.generated_by_fling_controller);
138 #endif
139 
140 #define EXPECT_MOUSE_WHEEL(event) \
141   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, event->GetType());
142 
143 }  // namespace
144 
145 class MouseWheelEventQueueTest : public testing::Test,
146                                  public MouseWheelEventQueueClient {
147  public:
MouseWheelEventQueueTest()148   MouseWheelEventQueueTest()
149       : task_environment_(
150             base::test::SingleThreadTaskEnvironment::MainThreadType::UI),
151         acked_event_count_(0),
152         last_acked_event_state_(blink::mojom::InputEventResultState::kUnknown) {
153     queue_.reset(new MouseWheelEventQueue(this));
154   }
155 
~MouseWheelEventQueueTest()156   ~MouseWheelEventQueueTest() override {}
157 
158   // MouseWheelEventQueueClient
SendMouseWheelEventImmediately(const MouseWheelEventWithLatencyInfo & event,MouseWheelEventHandledCallback callback)159   void SendMouseWheelEventImmediately(
160       const MouseWheelEventWithLatencyInfo& event,
161       MouseWheelEventHandledCallback callback) override {
162     WebMouseWheelEvent* cloned_event = new WebMouseWheelEvent();
163     std::unique_ptr<WebInputEvent> cloned_event_holder(cloned_event);
164     *cloned_event = event.event;
165     sent_events_.push_back(std::move(cloned_event_holder));
166     callbacks_.emplace_back(base::BindOnce(
167         [](MouseWheelEventHandledCallback callback,
168            const MouseWheelEventWithLatencyInfo& event,
169            blink::mojom::InputEventResultSource ack_source,
170            blink::mojom::InputEventResultState ack_result) {
171           std::move(callback).Run(event, ack_source, ack_result);
172         },
173         std::move(callback), event));
174   }
175 
ForwardGestureEventWithLatencyInfo(const blink::WebGestureEvent & event,const ui::LatencyInfo & latency_info)176   void ForwardGestureEventWithLatencyInfo(
177       const blink::WebGestureEvent& event,
178       const ui::LatencyInfo& latency_info) override {
179     WebGestureEvent* cloned_event = new WebGestureEvent();
180     std::unique_ptr<WebInputEvent> cloned_event_holder(cloned_event);
181     *cloned_event = event;
182     if (event.GetType() == WebInputEvent::Type::kGestureScrollBegin) {
183       is_wheel_scroll_in_progress_ = true;
184     } else if (event.GetType() == WebInputEvent::Type::kGestureScrollEnd) {
185       is_wheel_scroll_in_progress_ = false;
186     }
187     sent_events_.push_back(std::move(cloned_event_holder));
188   }
189 
OnMouseWheelEventAck(const MouseWheelEventWithLatencyInfo & event,blink::mojom::InputEventResultSource ack_source,blink::mojom::InputEventResultState ack_result)190   void OnMouseWheelEventAck(
191       const MouseWheelEventWithLatencyInfo& event,
192       blink::mojom::InputEventResultSource ack_source,
193       blink::mojom::InputEventResultState ack_result) override {
194     ++acked_event_count_;
195     last_acked_event_ = event.event;
196     last_acked_event_state_ = ack_result;
197   }
198 
IsWheelScrollInProgress()199   bool IsWheelScrollInProgress() override {
200     return is_wheel_scroll_in_progress_;
201   }
202 
IsAutoscrollInProgress()203   bool IsAutoscrollInProgress() override { return false; }
204 
205  protected:
206   using HandleEventCallback =
207       base::OnceCallback<void(blink::mojom::InputEventResultSource ack_source,
208                               blink::mojom::InputEventResultState ack_result)>;
209 
queued_event_count() const210   size_t queued_event_count() const { return queue_->queued_size(); }
211 
event_in_flight() const212   bool event_in_flight() const { return queue_->event_in_flight(); }
213 
all_sent_events()214   std::vector<std::unique_ptr<WebInputEvent>>& all_sent_events() {
215     return sent_events_;
216   }
217 
sent_input_event(size_t index)218   const std::unique_ptr<WebInputEvent>& sent_input_event(size_t index) {
219     return sent_events_[index];
220   }
sent_gesture_event(size_t index)221   const WebGestureEvent* sent_gesture_event(size_t index) {
222     return static_cast<WebGestureEvent*>(sent_events_[index].get());
223   }
224 
acked_event() const225   const WebMouseWheelEvent& acked_event() const { return last_acked_event_; }
226 
GetAndResetSentEventCount()227   size_t GetAndResetSentEventCount() {
228     size_t count = sent_events_.size();
229     sent_events_.clear();
230     return count;
231   }
232 
GetAndResetAckedEventCount()233   size_t GetAndResetAckedEventCount() {
234     size_t count = acked_event_count_;
235     acked_event_count_ = 0;
236     return count;
237   }
238 
SendMouseWheelEventAck(blink::mojom::InputEventResultState ack_result)239   void SendMouseWheelEventAck(blink::mojom::InputEventResultState ack_result) {
240     std::move(callbacks_.front())
241         .Run(blink::mojom::InputEventResultSource::kCompositorThread,
242              ack_result);
243     callbacks_.pop_front();
244   }
245 
SendMouseWheel(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,WebInputEvent::RailsMode rails_mode,bool has_synthetic_phase=false)246   void SendMouseWheel(float x,
247                       float y,
248                       float global_x,
249                       float global_y,
250                       float dX,
251                       float dY,
252                       int modifiers,
253                       bool high_precision,
254                       blink::WebMouseWheelEvent::Phase phase,
255                       blink::WebMouseWheelEvent::Phase momentum_phase,
256                       WebInputEvent::RailsMode rails_mode,
257                       bool has_synthetic_phase = false) {
258     WebMouseWheelEvent event = blink::SyntheticWebMouseWheelEventBuilder::Build(
259         x, y, global_x, global_y, dX, dY, modifiers,
260         high_precision ? ui::ScrollGranularity::kScrollByPrecisePixel
261                        : ui::ScrollGranularity::kScrollByPixel);
262     event.phase = phase;
263     event.momentum_phase = momentum_phase;
264     event.rails_mode = rails_mode;
265     event.has_synthetic_phase = has_synthetic_phase;
266     queue_->QueueEvent(MouseWheelEventWithLatencyInfo(event));
267   }
SendMouseWheel(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,bool has_synthetic_phase=false)268   void SendMouseWheel(float x,
269                       float y,
270                       float global_x,
271                       float global_y,
272                       float dX,
273                       float dY,
274                       int modifiers,
275                       bool high_precision,
276                       blink::WebMouseWheelEvent::Phase phase,
277                       blink::WebMouseWheelEvent::Phase momentum_phase,
278                       bool has_synthetic_phase = false) {
279     SendMouseWheel(x, y, global_x, global_y, dX, dY, modifiers, high_precision,
280                    phase, momentum_phase, WebInputEvent::kRailsModeFree,
281                    has_synthetic_phase);
282   }
283 
SendGestureEvent(WebInputEvent::Type type)284   void SendGestureEvent(WebInputEvent::Type type) {
285     WebGestureEvent event(type, WebInputEvent::kNoModifiers,
286                           ui::EventTimeForNow(),
287                           blink::WebGestureDevice::kTouchscreen);
288     queue_->OnGestureScrollEvent(
289         GestureEventWithLatencyInfo(event, ui::LatencyInfo()));
290   }
291 
RunTasksAndWait(base::TimeDelta delay)292   static void RunTasksAndWait(base::TimeDelta delay) {
293     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
294         FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
295         delay);
296     base::RunLoop().Run();
297   }
298 
GestureSendingTest(bool high_precision)299   void GestureSendingTest(bool high_precision) {
300     const ui::ScrollGranularity scroll_units =
301         high_precision ? ui::ScrollGranularity::kScrollByPrecisePixel
302                        : ui::ScrollGranularity::kScrollByPixel;
303     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
304                    kWheelScrollGlobalY, 1, 1, 0, high_precision,
305                    WebMouseWheelEvent::kPhaseBegan,
306                    WebMouseWheelEvent::kPhaseNone);
307     EXPECT_EQ(0U, queued_event_count());
308     EXPECT_TRUE(event_in_flight());
309     EXPECT_EQ(1U, GetAndResetSentEventCount());
310 
311     // The second mouse wheel should not be sent since one is already in
312     // queue.
313     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
314                    kWheelScrollGlobalY, 5, 5, 0, high_precision,
315                    WebMouseWheelEvent::kPhaseChanged,
316                    WebMouseWheelEvent::kPhaseNone);
317     EXPECT_EQ(1U, queued_event_count());
318     EXPECT_TRUE(event_in_flight());
319     EXPECT_EQ(0U, GetAndResetSentEventCount());
320 
321     // Receive an ACK for the mouse wheel event and release the next
322     // mouse wheel event.
323     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
324     EXPECT_EQ(0U, queued_event_count());
325     EXPECT_TRUE(event_in_flight());
326     EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
327     EXPECT_EQ(1U, GetAndResetAckedEventCount());
328     EXPECT_EQ(3U, all_sent_events().size());
329     EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
330     EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
331     EXPECT_MOUSE_WHEEL(sent_input_event(2));
332     EXPECT_EQ(3U, GetAndResetSentEventCount());
333   }
334 
PhaseGestureSendingTest(bool high_precision)335   void PhaseGestureSendingTest(bool high_precision) {
336     const ui::ScrollGranularity scroll_units =
337         high_precision ? ui::ScrollGranularity::kScrollByPrecisePixel
338                        : ui::ScrollGranularity::kScrollByPixel;
339 
340     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
341                    kWheelScrollGlobalY, 1, 1, 0, high_precision,
342                    WebMouseWheelEvent::kPhaseBegan,
343                    WebMouseWheelEvent::kPhaseNone);
344     EXPECT_EQ(1U, GetAndResetSentEventCount());
345     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
346     EXPECT_EQ(2U, all_sent_events().size());
347     EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
348     EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
349     EXPECT_EQ(2U, GetAndResetSentEventCount());
350 
351     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
352                    kWheelScrollGlobalY, 5, 5, 0, high_precision,
353                    WebMouseWheelEvent::kPhaseChanged,
354                    WebMouseWheelEvent::kPhaseNone);
355     EXPECT_EQ(1U, GetAndResetSentEventCount());
356     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
357     EXPECT_EQ(1U, all_sent_events().size());
358     EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(0));
359     EXPECT_EQ(1U, GetAndResetSentEventCount());
360 
361     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
362                    kWheelScrollGlobalY, 5, 5, 0, high_precision,
363                    WebMouseWheelEvent::kPhaseNone,
364                    WebMouseWheelEvent::kPhaseBegan);
365     EXPECT_EQ(1U, GetAndResetSentEventCount());
366     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
367     // A fling has started, no ScrollEnd/ScrollBegin is sent.
368     EXPECT_EQ(1U, all_sent_events().size());
369     EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(0));
370     EXPECT_EQ(1U, GetAndResetSentEventCount());
371 
372     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
373                    kWheelScrollGlobalY, 5, 5, 0, high_precision,
374                    WebMouseWheelEvent::kPhaseNone,
375                    WebMouseWheelEvent::kPhaseChanged);
376     EXPECT_EQ(1U, GetAndResetSentEventCount());
377     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
378     EXPECT_EQ(1U, all_sent_events().size());
379     EXPECT_INERTIAL_GESTURE_SCROLL_UPDATE(sent_gesture_event(0));
380     EXPECT_EQ(1U, GetAndResetSentEventCount());
381 
382     SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
383                    kWheelScrollGlobalY, 0, 0, 0, high_precision,
384                    WebMouseWheelEvent::kPhaseNone,
385                    WebMouseWheelEvent::kPhaseEnded);
386     EXPECT_EQ(1U, GetAndResetSentEventCount());
387     SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
388     // MomentumPhase is ended, the scroll is done, and GSE is sent
389     // immediately.
390     EXPECT_EQ(1U, all_sent_events().size());
391     EXPECT_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(0));
392     EXPECT_EQ(1U, GetAndResetSentEventCount());
393   }
394 
395   base::test::SingleThreadTaskEnvironment task_environment_;
396   std::unique_ptr<MouseWheelEventQueue> queue_;
397   std::vector<std::unique_ptr<WebInputEvent>> sent_events_;
398   base::circular_deque<HandleEventCallback> callbacks_;
399   size_t acked_event_count_;
400   blink::mojom::InputEventResultState last_acked_event_state_;
401   WebMouseWheelEvent last_acked_event_;
402 
403  private:
404   bool is_wheel_scroll_in_progress_ = false;
405 };
406 
407 // Tests that mouse wheel events are queued properly.
TEST_F(MouseWheelEventQueueTest,Basic)408 TEST_F(MouseWheelEventQueueTest, Basic) {
409   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
410                  kWheelScrollGlobalY, 1, 1, 0, false,
411                  WebMouseWheelEvent::kPhaseBegan,
412                  WebMouseWheelEvent::kPhaseNone);
413   EXPECT_EQ(0U, queued_event_count());
414   EXPECT_TRUE(event_in_flight());
415   EXPECT_EQ(1U, GetAndResetSentEventCount());
416 
417   // The second mouse wheel should not be sent since one is already in queue.
418   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
419                  kWheelScrollGlobalY, 5, 5, 0, false,
420                  WebMouseWheelEvent::kPhaseChanged,
421                  WebMouseWheelEvent::kPhaseNone);
422   EXPECT_EQ(1U, queued_event_count());
423   EXPECT_TRUE(event_in_flight());
424   EXPECT_EQ(0U, GetAndResetSentEventCount());
425 
426   // Receive an ACK for the first mouse wheel event.
427   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kConsumed);
428   EXPECT_EQ(0U, queued_event_count());
429   EXPECT_TRUE(event_in_flight());
430   EXPECT_EQ(1U, GetAndResetSentEventCount());
431   EXPECT_EQ(1U, GetAndResetAckedEventCount());
432   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
433 
434   // Receive an ACK for the second mouse wheel event.
435   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kConsumed);
436   EXPECT_EQ(0U, queued_event_count());
437   EXPECT_FALSE(event_in_flight());
438   EXPECT_EQ(0U, GetAndResetSentEventCount());
439   EXPECT_EQ(1U, GetAndResetAckedEventCount());
440   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
441 }
442 
TEST_F(MouseWheelEventQueueTest,GestureSending)443 TEST_F(MouseWheelEventQueueTest, GestureSending) {
444   GestureSendingTest(false);
445 }
446 
TEST_F(MouseWheelEventQueueTest,GestureSendingPrecisePixels)447 TEST_F(MouseWheelEventQueueTest, GestureSendingPrecisePixels) {
448   GestureSendingTest(true);
449 }
450 
TEST_F(MouseWheelEventQueueTest,GestureSendingWithPhaseInformation)451 TEST_F(MouseWheelEventQueueTest, GestureSendingWithPhaseInformation) {
452   PhaseGestureSendingTest(false);
453 }
454 
TEST_F(MouseWheelEventQueueTest,GestureSendingWithPhaseInformationPrecisePixels)455 TEST_F(MouseWheelEventQueueTest,
456        GestureSendingWithPhaseInformationPrecisePixels) {
457   PhaseGestureSendingTest(true);
458 }
459 
460 // Tests that a Wheel event with synthetic momentumn_phase == PhaseEnded that is
461 // generated by the fling controller properly populates
462 // scroll_end.data.scroll_end.generated_by_fling_controller.
463 #if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(MouseWheelEventQueueTest,WheelEndWithMomentumPhaseEndedInformation)464 TEST_F(MouseWheelEventQueueTest, WheelEndWithMomentumPhaseEndedInformation) {
465   const ui::ScrollGranularity scroll_units =
466       ui::ScrollGranularity::kScrollByPrecisePixel;
467   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
468                  kWheelScrollGlobalY, 1, 1, 0, true /* high_precision */,
469                  WebMouseWheelEvent::kPhaseBegan,
470                  WebMouseWheelEvent::kPhaseNone);
471   EXPECT_EQ(0U, queued_event_count());
472   EXPECT_TRUE(event_in_flight());
473   EXPECT_EQ(1U, GetAndResetSentEventCount());
474   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
475   EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
476   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
477   EXPECT_EQ(2U, GetAndResetSentEventCount());
478 
479   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
480                  kWheelScrollGlobalY, 0, 0, 0, true /* high_precision */,
481                  WebMouseWheelEvent::kPhaseNone,
482                  WebMouseWheelEvent::kPhaseEnded, true /*has_synthetic_phase*/);
483   EXPECT_EQ(0U, queued_event_count());
484   EXPECT_TRUE(event_in_flight());
485   EXPECT_EQ(1U, GetAndResetSentEventCount());
486   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
487 
488   EXPECT_EQ(1U, all_sent_events().size());
489   EXPECT_SYNTHETIC_INERTIAL_GESTURE_SCROLL_END(sent_gesture_event(0));
490   EXPECT_EQ(1U, GetAndResetSentEventCount());
491 }
492 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
493 
TEST_F(MouseWheelEventQueueTest,GestureSendingInterrupted)494 TEST_F(MouseWheelEventQueueTest, GestureSendingInterrupted) {
495   const ui::ScrollGranularity scroll_units =
496       ui::ScrollGranularity::kScrollByPixel;
497   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
498                  kWheelScrollGlobalY, 1, 1, 0, false,
499                  WebMouseWheelEvent::kPhaseBegan,
500                  WebMouseWheelEvent::kPhaseNone);
501   EXPECT_EQ(0U, queued_event_count());
502   EXPECT_TRUE(event_in_flight());
503   EXPECT_EQ(1U, GetAndResetSentEventCount());
504 
505   // Receive an ACK for the mouse wheel event.
506   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
507   EXPECT_EQ(0U, queued_event_count());
508   EXPECT_FALSE(event_in_flight());
509   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
510   EXPECT_EQ(1U, GetAndResetAckedEventCount());
511   EXPECT_EQ(2U, all_sent_events().size());
512   EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
513   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
514   EXPECT_EQ(2U, GetAndResetSentEventCount());
515 
516   // When a touch based GSB arrives in the
517   // middle of wheel scrolling sequence, a synthetic wheel event with zero
518   // deltas and phase = |kPhaseEnded| will be sent.
519   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
520                  kWheelScrollGlobalY, 0, 0, 0, false,
521                  WebMouseWheelEvent::kPhaseEnded,
522                  WebMouseWheelEvent::kPhaseNone);
523   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
524   EXPECT_EQ(1U, GetAndResetAckedEventCount());
525 
526   // Ensure that a gesture scroll begin terminates the current scroll event.
527   SendGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
528 
529   EXPECT_EQ(2U, all_sent_events().size());
530   EXPECT_GESTURE_SCROLL_END_WITH_PHASE(sent_gesture_event(1));
531   EXPECT_EQ(2U, GetAndResetSentEventCount());
532 
533   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
534                  kWheelScrollGlobalY, 1, 1, 0, false,
535                  WebMouseWheelEvent::kPhaseBegan,
536                  WebMouseWheelEvent::kPhaseNone);
537 
538   EXPECT_EQ(0U, queued_event_count());
539   EXPECT_TRUE(event_in_flight());
540   EXPECT_EQ(1U, GetAndResetSentEventCount());
541 
542   // New mouse wheel events won't cause gestures because a scroll
543   // is already in progress by another device.
544   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
545   EXPECT_EQ(0U, queued_event_count());
546   EXPECT_FALSE(event_in_flight());
547   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
548   EXPECT_EQ(1U, GetAndResetAckedEventCount());
549   EXPECT_EQ(0U, all_sent_events().size());
550 
551   SendGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
552   EXPECT_EQ(0U, all_sent_events().size());
553 
554   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
555                  kWheelScrollGlobalY, 1, 1, 0, false,
556                  WebMouseWheelEvent::kPhaseBegan,
557                  WebMouseWheelEvent::kPhaseNone);
558 
559   EXPECT_EQ(0U, queued_event_count());
560   EXPECT_TRUE(event_in_flight());
561   EXPECT_EQ(1U, GetAndResetSentEventCount());
562 
563   // Receive an ACK for the mouse wheel event.
564   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
565   EXPECT_EQ(0U, queued_event_count());
566   EXPECT_FALSE(event_in_flight());
567   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
568   EXPECT_EQ(1U, GetAndResetAckedEventCount());
569   EXPECT_EQ(2U, all_sent_events().size());
570   EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
571   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
572   EXPECT_EQ(2U, GetAndResetSentEventCount());
573 }
574 
TEST_F(MouseWheelEventQueueTest,GestureRailScrolling)575 TEST_F(MouseWheelEventQueueTest, GestureRailScrolling) {
576   const ui::ScrollGranularity scroll_units =
577       ui::ScrollGranularity::kScrollByPixel;
578   SendMouseWheel(
579       kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, kWheelScrollGlobalY, 1,
580       1, 0, false, WebMouseWheelEvent::kPhaseBegan,
581       WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeHorizontal);
582   EXPECT_EQ(0U, queued_event_count());
583   EXPECT_TRUE(event_in_flight());
584   EXPECT_EQ(1U, GetAndResetSentEventCount());
585 
586   // Receive an ACK for the mouse wheel event.
587   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
588   EXPECT_EQ(0U, queued_event_count());
589   EXPECT_FALSE(event_in_flight());
590   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
591   EXPECT_EQ(1U, GetAndResetAckedEventCount());
592   EXPECT_EQ(2U, all_sent_events().size());
593   EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
594   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
595   EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_x);
596   EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_y);
597   EXPECT_EQ(2U, GetAndResetSentEventCount());
598 
599   SendMouseWheel(
600       kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, kWheelScrollGlobalY, 1,
601       1, 0, false, WebMouseWheelEvent::kPhaseChanged,
602       WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeVertical);
603 
604   EXPECT_EQ(0U, queued_event_count());
605   EXPECT_TRUE(event_in_flight());
606   EXPECT_EQ(1U, GetAndResetSentEventCount());
607 
608   // Receive an ACK for the mouse wheel event.
609   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
610   EXPECT_EQ(0U, queued_event_count());
611   EXPECT_FALSE(event_in_flight());
612   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
613   EXPECT_EQ(1U, GetAndResetAckedEventCount());
614   size_t scroll_update_index = 0;
615   EXPECT_EQ(1U, all_sent_events().size());
616   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(0));
617 
618   EXPECT_EQ(
619       0U, sent_gesture_event(scroll_update_index)->data.scroll_update.delta_x);
620   EXPECT_EQ(
621       1U, sent_gesture_event(scroll_update_index)->data.scroll_update.delta_y);
622     EXPECT_EQ(1U, GetAndResetSentEventCount());
623 }
624 
TEST_F(MouseWheelEventQueueTest,WheelScrollLatching)625 TEST_F(MouseWheelEventQueueTest, WheelScrollLatching) {
626   const ui::ScrollGranularity scroll_units =
627       ui::ScrollGranularity::kScrollByPixel;
628   SendMouseWheel(
629       kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, kWheelScrollGlobalY, 1,
630       1, 0, false, WebMouseWheelEvent::kPhaseBegan,
631       WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeVertical);
632   EXPECT_EQ(0U, queued_event_count());
633   EXPECT_TRUE(event_in_flight());
634   EXPECT_EQ(1U, GetAndResetSentEventCount());
635 
636   // Receive an ACK for the mouse wheel event.
637   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
638   EXPECT_EQ(0U, queued_event_count());
639   EXPECT_FALSE(event_in_flight());
640   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
641   EXPECT_EQ(1U, GetAndResetAckedEventCount());
642   EXPECT_EQ(2U, all_sent_events().size());
643   EXPECT_GESTURE_SCROLL_BEGIN_WITH_PHASE(sent_gesture_event(0));
644   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(1));
645   EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_x);
646   EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_y);
647   EXPECT_EQ(2U, GetAndResetSentEventCount());
648 
649   SendMouseWheel(
650       kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, kWheelScrollGlobalY, 1,
651       1, 0, false, WebMouseWheelEvent::kPhaseChanged,
652       WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeVertical);
653   EXPECT_EQ(0U, queued_event_count());
654   EXPECT_TRUE(event_in_flight());
655   EXPECT_EQ(1U, GetAndResetSentEventCount());
656 
657   // Receive an ACK for the mouse wheel event.
658   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
659   EXPECT_EQ(0U, queued_event_count());
660   EXPECT_FALSE(event_in_flight());
661   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
662   EXPECT_EQ(1U, GetAndResetAckedEventCount());
663 
664   // Scroll latching: no new scroll begin expected.
665   EXPECT_EQ(1U, all_sent_events().size());
666   EXPECT_GESTURE_SCROLL_UPDATE_WITH_PHASE(sent_gesture_event(0));
667   EXPECT_EQ(0U, sent_gesture_event(0)->data.scroll_update.delta_x);
668   EXPECT_EQ(1U, sent_gesture_event(0)->data.scroll_update.delta_y);
669   EXPECT_EQ(1U, GetAndResetSentEventCount());
670 }
671 
TEST_F(MouseWheelEventQueueTest,WheelScrollingWasLatchedHistogramCheck)672 TEST_F(MouseWheelEventQueueTest, WheelScrollingWasLatchedHistogramCheck) {
673   base::HistogramTester histogram_tester;
674   const char latching_histogram_name[] = "WheelScrolling.WasLatched";
675 
676   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
677                  kWheelScrollGlobalY, 1, 1, 0, false,
678                  WebMouseWheelEvent::kPhaseBegan,
679                  WebMouseWheelEvent::kPhaseNone);
680   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
681   histogram_tester.ExpectBucketCount(latching_histogram_name, 0, 1);
682 
683   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
684                  kWheelScrollGlobalY, 1, 1, 0, false,
685                  WebMouseWheelEvent::kPhaseChanged,
686                  WebMouseWheelEvent::kPhaseNone);
687   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
688   histogram_tester.ExpectBucketCount(latching_histogram_name, 0, 1);
689   histogram_tester.ExpectBucketCount(latching_histogram_name, 1, 1);
690 }
691 
692 #if defined(OS_MAC)
TEST_F(MouseWheelEventQueueTest,DoNotSwapXYForShiftScroll)693 TEST_F(MouseWheelEventQueueTest, DoNotSwapXYForShiftScroll) {
694   // Send an event with shift modifier, zero value for delta X, and no direction
695   // for |rails_mode|. Do not swap the scroll direction.
696   SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
697                  kWheelScrollGlobalY, 0.0, 1.0, WebInputEvent::kShiftKey, false,
698                  WebMouseWheelEvent::kPhaseBegan,
699                  WebMouseWheelEvent::kPhaseNone, WebInputEvent::kRailsModeFree);
700   EXPECT_EQ(0U, queued_event_count());
701   EXPECT_TRUE(event_in_flight());
702   EXPECT_EQ(1U, GetAndResetSentEventCount());
703 
704   // Receive an ACK for the mouse wheel event.
705   SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
706   EXPECT_EQ(0U, queued_event_count());
707   EXPECT_FALSE(event_in_flight());
708   EXPECT_EQ(WebInputEvent::Type::kMouseWheel, acked_event().GetType());
709   EXPECT_EQ(1U, GetAndResetAckedEventCount());
710 
711   EXPECT_EQ(2U, all_sent_events().size());
712   EXPECT_EQ(0U, sent_gesture_event(1)->data.scroll_update.delta_x);
713   EXPECT_EQ(1U, sent_gesture_event(1)->data.scroll_update.delta_y);
714   EXPECT_EQ(2U, GetAndResetSentEventCount());
715 }
716 #endif
717 }  // namespace content
718