1 // Copyright 2013 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 "third_party/blink/public/platform/input/input_handler_proxy.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/containers/circular_deque.h"
12 #include "base/macros.h"
13 #include "base/test/bind.h"
14 #include "base/test/metrics/histogram_tester.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/test/simple_test_tick_clock.h"
17 #include "base/test/task_environment.h"
18 #include "base/test/trace_event_analyzer.h"
19 #include "build/build_config.h"
20 #include "cc/base/features.h"
21 #include "cc/input/main_thread_scrolling_reason.h"
22 #include "cc/trees/swap_promise_monitor.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/blink/public/common/input/web_input_event.h"
26 #include "third_party/blink/public/common/input/web_input_event_attribution.h"
27 #include "third_party/blink/public/common/input/web_keyboard_event.h"
28 #include "third_party/blink/public/common/input/web_mouse_event.h"
29 #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
30 #include "third_party/blink/public/common/input/web_pointer_event.h"
31 #include "third_party/blink/public/common/input/web_touch_event.h"
32 #include "third_party/blink/public/platform/input/input_handler_proxy.h"
33 #include "third_party/blink/public/platform/input/input_handler_proxy_client.h"
34 #include "third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.h"
35 #include "third_party/blink/renderer/platform/widget/input/event_with_callback.h"
36 #include "third_party/blink/renderer/platform/widget/input/scroll_predictor.h"
37 #include "ui/events/types/scroll_input_type.h"
38 #include "ui/gfx/geometry/scroll_offset.h"
39 #include "ui/gfx/geometry/size_f.h"
40 #include "ui/latency/latency_info.h"
41
42 using cc::InputHandler;
43 using cc::ScrollBeginThreadState;
44 using cc::TouchAction;
45 using testing::_;
46 using testing::AllOf;
47 using testing::DoAll;
48 using testing::Eq;
49 using testing::Field;
50 using testing::Mock;
51 using testing::NiceMock;
52 using testing::Property;
53 using testing::Return;
54 using testing::SetArgPointee;
55 using testing::StrictMock;
56
57 namespace blink {
58 namespace test {
59
60 namespace {
61
62 MATCHER_P(WheelEventsMatch, expected, "") {
63 return WheelEventsMatch(arg, expected);
64 }
65
CreateGestureScrollPinch(WebInputEvent::Type type,WebGestureDevice source_device,base::TimeTicks event_time,float delta_y_or_scale=0,int x=0,int y=0)66 std::unique_ptr<WebInputEvent> CreateGestureScrollPinch(
67 WebInputEvent::Type type,
68 WebGestureDevice source_device,
69 base::TimeTicks event_time,
70 float delta_y_or_scale = 0,
71 int x = 0,
72 int y = 0) {
73 auto gesture = std::make_unique<WebGestureEvent>(
74 type, WebInputEvent::kNoModifiers, event_time, source_device);
75 if (type == WebInputEvent::Type::kGestureScrollUpdate) {
76 gesture->data.scroll_update.delta_y = delta_y_or_scale;
77 } else if (type == WebInputEvent::Type::kGesturePinchUpdate) {
78 gesture->data.pinch_update.scale = delta_y_or_scale;
79 gesture->SetPositionInWidget(gfx::PointF(x, y));
80 }
81 return gesture;
82 }
83
84 class MockInputHandler : public cc::InputHandler {
85 public:
86 MockInputHandler() = default;
87 ~MockInputHandler() override = default;
88
89 MockInputHandler(const MockInputHandler&) = delete;
90 MockInputHandler& operator=(const MockInputHandler&) = delete;
91
AsWeakPtr() const92 base::WeakPtr<InputHandler> AsWeakPtr() const override {
93 return weak_ptr_factory_.GetWeakPtr();
94 }
95
96 MOCK_METHOD0(PinchGestureBegin, void());
97 MOCK_METHOD2(PinchGestureUpdate,
98 void(float magnify_delta, const gfx::Point& anchor));
99 MOCK_METHOD2(PinchGestureEnd, void(const gfx::Point& anchor, bool snap));
100
101 MOCK_METHOD0(SetNeedsAnimateInput, void());
102
103 MOCK_METHOD2(ScrollBegin,
104 ScrollStatus(cc::ScrollState*, ui::ScrollInputType type));
105 MOCK_METHOD2(RootScrollBegin,
106 ScrollStatus(cc::ScrollState*, ui::ScrollInputType type));
107 MOCK_METHOD2(ScrollUpdate,
108 cc::InputHandlerScrollResult(cc::ScrollState*, base::TimeDelta));
109 MOCK_METHOD1(ScrollEnd, void(bool));
110 MOCK_METHOD2(RecordScrollBegin,
111 void(ui::ScrollInputType type,
112 cc::ScrollBeginThreadState state));
113 MOCK_METHOD1(RecordScrollEnd, void(ui::ScrollInputType type));
114 MOCK_METHOD0(ScrollingShouldSwitchtoMainThread, bool());
115 MOCK_METHOD2(MouseDown,
116 cc::InputHandlerPointerResult(const gfx::PointF& mouse_position,
117 const bool shift_modifier));
118 MOCK_METHOD1(
119 MouseUp,
120 cc::InputHandlerPointerResult(const gfx::PointF& mouse_position));
NotifyInputEvent()121 void NotifyInputEvent() override {}
122
CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo * latency)123 std::unique_ptr<cc::SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
124 ui::LatencyInfo* latency) override {
125 return nullptr;
126 }
127
128 std::unique_ptr<cc::EventsMetricsManager::ScopedMonitor>
GetScopedEventMetricsMonitor(cc::EventsMetricsManager::ScopedMonitor::DoneCallback)129 GetScopedEventMetricsMonitor(
130 cc::EventsMetricsManager::ScopedMonitor::DoneCallback) override {
131 return nullptr;
132 }
133
CreateScrollElasticityHelper()134 cc::ScrollElasticityHelper* CreateScrollElasticityHelper() override {
135 return nullptr;
136 }
GetScrollOffsetForLayer(cc::ElementId element_id,gfx::ScrollOffset * offset)137 bool GetScrollOffsetForLayer(cc::ElementId element_id,
138 gfx::ScrollOffset* offset) override {
139 return false;
140 }
ScrollLayerTo(cc::ElementId element_id,const gfx::ScrollOffset & offset)141 bool ScrollLayerTo(cc::ElementId element_id,
142 const gfx::ScrollOffset& offset) override {
143 return false;
144 }
145
BindToClient(cc::InputHandlerClient * client)146 void BindToClient(cc::InputHandlerClient* client) override {}
147
MouseLeave()148 void MouseLeave() override {}
149
150 MOCK_METHOD1(FindFrameElementIdAtPoint, cc::ElementId(const gfx::PointF&));
151
MouseMoveAt(const gfx::Point & mouse_position)152 cc::InputHandlerPointerResult MouseMoveAt(
153 const gfx::Point& mouse_position) override {
154 return cc::InputHandlerPointerResult();
155 }
156
157 MOCK_CONST_METHOD1(
158 GetEventListenerProperties,
159 cc::EventListenerProperties(cc::EventListenerClass event_class));
160 MOCK_METHOD2(EventListenerTypeForTouchStartOrMoveAt,
161 cc::InputHandler::TouchStartOrMoveEventListenerType(
162 const gfx::Point& point,
163 cc::TouchAction* touch_action));
164 MOCK_CONST_METHOD1(HasBlockingWheelEventHandlerAt, bool(const gfx::Point&));
165
166 MOCK_METHOD0(RequestUpdateForSynchronousInputHandler, void());
167 MOCK_METHOD1(SetSynchronousInputHandlerRootScrollOffset,
168 void(const gfx::ScrollOffset& root_offset));
169
IsCurrentlyScrollingViewport() const170 bool IsCurrentlyScrollingViewport() const override {
171 return is_scrolling_root_;
172 }
set_is_scrolling_root(bool is)173 void set_is_scrolling_root(bool is) { is_scrolling_root_ = is; }
174
175 MOCK_METHOD3(GetSnapFlingInfoAndSetAnimatingSnapTarget,
176 bool(const gfx::Vector2dF& natural_displacement,
177 gfx::Vector2dF* initial_offset,
178 gfx::Vector2dF* target_offset));
179 MOCK_METHOD1(ScrollEndForSnapFling, void(bool));
180
181 private:
182 bool is_scrolling_root_ = true;
183
184 base::WeakPtrFactory<MockInputHandler> weak_ptr_factory_{this};
185 };
186
187 class MockSynchronousInputHandler : public SynchronousInputHandler {
188 public:
189 MOCK_METHOD6(UpdateRootLayerState,
190 void(const gfx::ScrollOffset& total_scroll_offset,
191 const gfx::ScrollOffset& max_scroll_offset,
192 const gfx::SizeF& scrollable_size,
193 float page_scale_factor,
194 float min_page_scale_factor,
195 float max_page_scale_factor));
196 };
197
198 class MockInputHandlerProxyClient : public InputHandlerProxyClient {
199 public:
MockInputHandlerProxyClient()200 MockInputHandlerProxyClient() {}
~MockInputHandlerProxyClient()201 ~MockInputHandlerProxyClient() override {}
202
WillShutdown()203 void WillShutdown() override {}
204
205 MOCK_METHOD3(GenerateScrollBeginAndSendToMainThread,
206 void(const WebGestureEvent& update_event,
207 const WebInputEventAttribution&,
208 const cc::EventMetrics*));
209
DispatchNonBlockingEventToMainThread(std::unique_ptr<WebCoalescedInputEvent> event,const WebInputEventAttribution &,std::unique_ptr<cc::EventMetrics> metrics)210 void DispatchNonBlockingEventToMainThread(
211 std::unique_ptr<WebCoalescedInputEvent> event,
212 const WebInputEventAttribution&,
213 std::unique_ptr<cc::EventMetrics> metrics) override {}
214
215 MOCK_METHOD5(DidOverscroll,
216 void(const gfx::Vector2dF& accumulated_overscroll,
217 const gfx::Vector2dF& latest_overscroll_delta,
218 const gfx::Vector2dF& current_fling_velocity,
219 const gfx::PointF& causal_event_viewport_point,
220 const cc::OverscrollBehavior& overscroll_behavior));
DidAnimateForInput()221 void DidAnimateForInput() override {}
DidStartScrollingViewport()222 void DidStartScrollingViewport() override {}
223 MOCK_METHOD3(SetAllowedTouchAction,
224 void(cc::TouchAction touch_action,
225 uint32_t unique_touch_event_id,
226 InputHandlerProxy::EventDisposition event_disposition));
227
228 private:
229 DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClient);
230 };
231
232 class MockInputHandlerProxyClientWithDidAnimateForInput
233 : public MockInputHandlerProxyClient {
234 public:
MockInputHandlerProxyClientWithDidAnimateForInput()235 MockInputHandlerProxyClientWithDidAnimateForInput() {}
~MockInputHandlerProxyClientWithDidAnimateForInput()236 ~MockInputHandlerProxyClientWithDidAnimateForInput() override {}
237
238 MOCK_METHOD0(DidAnimateForInput, void());
239
240 private:
241 DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClientWithDidAnimateForInput);
242 };
243
CreateWebTouchPoint(WebTouchPoint::State state,float x,float y)244 WebTouchPoint CreateWebTouchPoint(WebTouchPoint::State state,
245 float x,
246 float y) {
247 WebTouchPoint point;
248 point.state = state;
249 point.SetPositionInScreen(x, y);
250 point.SetPositionInWidget(x, y);
251 return point;
252 }
253
254 const cc::InputHandler::ScrollStatus kImplThreadScrollState(
255 cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD,
256 cc::MainThreadScrollingReason::kNotScrollingOnMain);
257
258 const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState(
259 cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD,
260 cc::MainThreadScrollingReason::kNotScrollingOnMain,
261 /*needs_main_thread_hit_test=*/true);
262
263 const cc::InputHandler::ScrollStatus kMainThreadScrollState(
264 cc::InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD,
265 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
266
267 const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState(
268 cc::InputHandler::ScrollThread::SCROLL_IGNORED,
269 cc::MainThreadScrollingReason::kNotScrollable);
270
271 } // namespace
272
273 class TestInputHandlerProxy : public InputHandlerProxy {
274 public:
TestInputHandlerProxy(cc::InputHandler & input_handler,InputHandlerProxyClient * client)275 TestInputHandlerProxy(cc::InputHandler& input_handler,
276 InputHandlerProxyClient* client)
277 : InputHandlerProxy(input_handler, client) {}
RecordMainThreadScrollingReasonsForTest(WebGestureDevice device,uint32_t reasons)278 void RecordMainThreadScrollingReasonsForTest(WebGestureDevice device,
279 uint32_t reasons) {
280 RecordMainThreadScrollingReasons(device, reasons);
281 }
282
283 MOCK_METHOD0(SetNeedsAnimateInput, void());
284
HitTestTouchEventForTest(const WebTouchEvent & touch_event,bool * is_touching_scrolling_layer,cc::TouchAction * allowed_touch_action)285 EventDisposition HitTestTouchEventForTest(
286 const WebTouchEvent& touch_event,
287 bool* is_touching_scrolling_layer,
288 cc::TouchAction* allowed_touch_action) {
289 return HitTestTouchEvent(touch_event, is_touching_scrolling_layer,
290 allowed_touch_action);
291 }
292
HandleMouseWheelForTest(const WebMouseWheelEvent & wheel_event)293 EventDisposition HandleMouseWheelForTest(
294 const WebMouseWheelEvent& wheel_event) {
295 return HandleMouseWheel(wheel_event);
296 }
297
298 // This is needed because the tests can't directly call
299 // DispatchQueuedInputEvents since it is private.
DispatchQueuedInputEventsHelper()300 void DispatchQueuedInputEventsHelper() { DispatchQueuedInputEvents(); }
301 };
302
303 // Whether or not the input handler says that the viewport is scrolling the
304 // root scroller or a child.
305 enum class ScrollerType { kRoot, kChild };
306
307 // Whether or not to setup a synchronous input handler. This simulates the mode
308 // that WebView runs in.
309 enum class HandlerType { kNormal, kSynchronous };
310
311 // Run tests with unification both on and off.
312 enum class ScrollUnification { kEnabled, kDisabled };
313
314 class InputHandlerProxyTest
315 : public testing::Test,
316 public testing::WithParamInterface<
317 std::tuple<ScrollerType, HandlerType, ScrollUnification>> {
GetScrollerType()318 ScrollerType GetScrollerType() { return std::get<0>(GetParam()); }
GetHandlerType()319 HandlerType GetHandlerType() { return std::get<1>(GetParam()); }
GetScrollUnificationState()320 ScrollUnification GetScrollUnificationState() {
321 return std::get<2>(GetParam());
322 }
323
324 public:
InputHandlerProxyTest()325 InputHandlerProxyTest() {
326 if (GetScrollUnificationState() == ScrollUnification::kEnabled)
327 scoped_feature_list_.InitAndEnableFeature(features::kScrollUnification);
328 else
329 scoped_feature_list_.InitAndDisableFeature(features::kScrollUnification);
330
331 input_handler_ = std::make_unique<TestInputHandlerProxy>(
332 mock_input_handler_, &mock_client_);
333 scroll_result_did_scroll_.did_scroll = true;
334 scroll_result_did_not_scroll_.did_scroll = false;
335
336 if (GetHandlerType() == HandlerType::kSynchronous) {
337 EXPECT_CALL(mock_input_handler_,
338 RequestUpdateForSynchronousInputHandler())
339 .Times(1);
340 input_handler_->SetSynchronousInputHandler(
341 &mock_synchronous_input_handler_);
342 }
343
344 mock_input_handler_.set_is_scrolling_root(
345 GetHandlerType() == HandlerType::kSynchronous &&
346 GetScrollerType() == ScrollerType::kRoot);
347
348 // Set a default device so tests don't always have to set this.
349 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
350
351 input_handler_->set_event_attribution_enabled(false);
352 }
353
354 virtual ~InputHandlerProxyTest() = default;
355
356 // This is defined as a macro so the line numbers can be traced back to the
357 // correct spot when it fails.
358 #define EXPECT_SET_NEEDS_ANIMATE_INPUT(times) \
359 do { \
360 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(times); \
361 } while (false)
362
363 // This is defined as a macro because when an expectation is not satisfied the
364 // only output you get out of gmock is the line number that set the expectation.
365 #define VERIFY_AND_RESET_MOCKS() \
366 do { \
367 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_); \
368 testing::Mock::VerifyAndClearExpectations( \
369 &mock_synchronous_input_handler_); \
370 testing::Mock::VerifyAndClearExpectations(&mock_client_); \
371 } while (false)
372
Animate(base::TimeTicks time)373 void Animate(base::TimeTicks time) { input_handler_->Animate(time); }
374
SetSmoothScrollEnabled(bool value)375 void SetSmoothScrollEnabled(bool value) {}
376
histogram_tester()377 base::HistogramTester& histogram_tester() { return histogram_tester_; }
378
379 protected:
380 void GestureScrollStarted();
381 void ScrollHandlingSwitchedToMainThread();
382 void GestureScrollIgnored();
383 void FlingAndSnap();
384
385 testing::StrictMock<MockInputHandler> mock_input_handler_;
386 testing::StrictMock<MockSynchronousInputHandler>
387 mock_synchronous_input_handler_;
388 std::unique_ptr<TestInputHandlerProxy> input_handler_;
389 testing::StrictMock<MockInputHandlerProxyClient> mock_client_;
390 WebGestureEvent gesture_;
391 InputHandlerProxy::EventDisposition expected_disposition_ =
392 InputHandlerProxy::DID_HANDLE;
393 base::HistogramTester histogram_tester_;
394 cc::InputHandlerScrollResult scroll_result_did_scroll_;
395 cc::InputHandlerScrollResult scroll_result_did_not_scroll_;
396 base::test::ScopedFeatureList scoped_feature_list_;
397 };
398
399 // The helper basically returns the EventDisposition that is returned by
400 // RouteToTypeSpecificHandler. This is done by passing in a callback when
401 // calling HandleInputEventWithLatencyInfo. By design, DispatchSingleInputEvent
402 // will then call this callback with the disposition returned by
403 // RouteToTypeSpecificHandler and that is what gets returned by this helper.
HandleInputEventWithLatencyInfo(TestInputHandlerProxy * input_handler,const WebInputEvent & event)404 InputHandlerProxy::EventDisposition HandleInputEventWithLatencyInfo(
405 TestInputHandlerProxy* input_handler,
406 const WebInputEvent& event) {
407 std::unique_ptr<WebCoalescedInputEvent> scoped_input_event =
408 std::make_unique<WebCoalescedInputEvent>(event.Clone(),
409 ui::LatencyInfo());
410 InputHandlerProxy::EventDisposition event_disposition =
411 InputHandlerProxy::DID_NOT_HANDLE;
412 input_handler->HandleInputEventWithLatencyInfo(
413 std::move(scoped_input_event), nullptr,
414 base::BindLambdaForTesting(
415 [&event_disposition](
416 InputHandlerProxy::EventDisposition disposition,
417 std::unique_ptr<blink::WebCoalescedInputEvent> event,
418 std::unique_ptr<InputHandlerProxy::DidOverscrollParams> callback,
419 const WebInputEventAttribution& attribution,
420 std::unique_ptr<cc::EventMetrics> metrics) {
421 event_disposition = disposition;
422 }));
423 return event_disposition;
424 }
425
426 // This helper forces the CompositorThreadEventQueue to be flushed.
HandleInputEventAndFlushEventQueue(testing::StrictMock<MockInputHandler> & mock_input_handler,TestInputHandlerProxy * input_handler,const WebInputEvent & event)427 InputHandlerProxy::EventDisposition HandleInputEventAndFlushEventQueue(
428 testing::StrictMock<MockInputHandler>& mock_input_handler,
429 TestInputHandlerProxy* input_handler,
430 const WebInputEvent& event) {
431 EXPECT_CALL(mock_input_handler, SetNeedsAnimateInput())
432 .Times(testing::AnyNumber());
433
434 std::unique_ptr<WebCoalescedInputEvent> scoped_input_event =
435 std::make_unique<WebCoalescedInputEvent>(event.Clone(),
436 ui::LatencyInfo());
437 InputHandlerProxy::EventDisposition event_disposition =
438 InputHandlerProxy::DID_NOT_HANDLE;
439 input_handler->HandleInputEventWithLatencyInfo(
440 std::move(scoped_input_event), nullptr,
441 base::BindLambdaForTesting(
442 [&event_disposition](
443 InputHandlerProxy::EventDisposition disposition,
444 std::unique_ptr<blink::WebCoalescedInputEvent> event,
445 std::unique_ptr<InputHandlerProxy::DidOverscrollParams> callback,
446 const WebInputEventAttribution& attribution,
447 std::unique_ptr<cc::EventMetrics> metrics) {
448 event_disposition = disposition;
449 }));
450
451 input_handler->DispatchQueuedInputEventsHelper();
452 return event_disposition;
453 }
454
455 class InputHandlerProxyEventQueueTest : public testing::Test {
456 public:
InputHandlerProxyEventQueueTest()457 InputHandlerProxyEventQueueTest()
458 : input_handler_proxy_(mock_input_handler_, &mock_client_) {
459 SetScrollPredictionEnabled(true);
460 }
461
462 ~InputHandlerProxyEventQueueTest() = default;
463
HandleGestureEvent(WebInputEvent::Type type,float delta_y_or_scale=0,int x=0,int y=0)464 void HandleGestureEvent(WebInputEvent::Type type,
465 float delta_y_or_scale = 0,
466 int x = 0,
467 int y = 0) {
468 HandleGestureEventWithSourceDevice(type, WebGestureDevice::kTouchscreen,
469 delta_y_or_scale, x, y);
470 }
471
HandleGestureEventWithSourceDevice(WebInputEvent::Type type,WebGestureDevice source_device,float delta_y_or_scale=0,int x=0,int y=0)472 void HandleGestureEventWithSourceDevice(WebInputEvent::Type type,
473 WebGestureDevice source_device,
474 float delta_y_or_scale = 0,
475 int x = 0,
476 int y = 0) {
477 InjectInputEvent(CreateGestureScrollPinch(
478 type, source_device, input_handler_proxy_.tick_clock_->NowTicks(),
479 delta_y_or_scale, x, y));
480 }
481
InjectInputEvent(std::unique_ptr<WebInputEvent> event)482 void InjectInputEvent(std::unique_ptr<WebInputEvent> event) {
483 input_handler_proxy_.HandleInputEventWithLatencyInfo(
484 std::make_unique<WebCoalescedInputEvent>(std::move(event),
485 ui::LatencyInfo()),
486 nullptr,
487 base::BindOnce(
488 &InputHandlerProxyEventQueueTest::DidHandleInputEventAndOverscroll,
489 weak_ptr_factory_.GetWeakPtr()));
490 }
491
HandleMouseEvent(WebInputEvent::Type type,int x=0,int y=0)492 void HandleMouseEvent(WebInputEvent::Type type, int x = 0, int y = 0) {
493 WebMouseEvent mouse_event(type, WebInputEvent::kNoModifiers,
494 WebInputEvent::GetStaticTimeStampForTests());
495
496 mouse_event.SetPositionInWidget(gfx::PointF(x, y));
497 mouse_event.button = WebMouseEvent::Button::kLeft;
498 HandleInputEventWithLatencyInfo(&input_handler_proxy_, mouse_event);
499 }
500
DidHandleInputEventAndOverscroll(InputHandlerProxy::EventDisposition event_disposition,std::unique_ptr<WebCoalescedInputEvent> input_event,std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,const WebInputEventAttribution & attribution,std::unique_ptr<cc::EventMetrics> metrics)501 void DidHandleInputEventAndOverscroll(
502 InputHandlerProxy::EventDisposition event_disposition,
503 std::unique_ptr<WebCoalescedInputEvent> input_event,
504 std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,
505 const WebInputEventAttribution& attribution,
506 std::unique_ptr<cc::EventMetrics> metrics) {
507 event_disposition_recorder_.push_back(event_disposition);
508 latency_info_recorder_.push_back(input_event->latency_info());
509 }
510
event_queue()511 base::circular_deque<std::unique_ptr<EventWithCallback>>& event_queue() {
512 return input_handler_proxy_.compositor_event_queue_->queue_;
513 }
514
SetInputHandlerProxyTickClockForTesting(const base::TickClock * tick_clock)515 void SetInputHandlerProxyTickClockForTesting(
516 const base::TickClock* tick_clock) {
517 input_handler_proxy_.SetTickClockForTesting(tick_clock);
518 }
519
DeliverInputForBeginFrame()520 void DeliverInputForBeginFrame() {
521 constexpr base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
522 base::TimeTicks frame_time =
523 WebInputEvent::GetStaticTimeStampForTests() +
524 (next_begin_frame_number_ - viz::BeginFrameArgs::kStartingFrameNumber) *
525 interval;
526 input_handler_proxy_.DeliverInputForBeginFrame(viz::BeginFrameArgs::Create(
527 BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, frame_time,
528 frame_time + interval, interval, viz::BeginFrameArgs::NORMAL));
529 }
530
DeliverInputForHighLatencyMode()531 void DeliverInputForHighLatencyMode() {
532 input_handler_proxy_.DeliverInputForHighLatencyMode();
533 }
534
SetScrollPredictionEnabled(bool enabled)535 void SetScrollPredictionEnabled(bool enabled) {
536 input_handler_proxy_.scroll_predictor_ =
537 enabled ? std::make_unique<ScrollPredictor>() : nullptr;
538 }
539
540 std::unique_ptr<ui::InputPredictor::InputData>
GestureScrollEventPredictionAvailable()541 GestureScrollEventPredictionAvailable() {
542 return input_handler_proxy_.scroll_predictor_->predictor_
543 ->GeneratePrediction(WebInputEvent::GetStaticTimeStampForTests());
544 }
545
NowTimestampForEvents()546 base::TimeTicks NowTimestampForEvents() {
547 return input_handler_proxy_.tick_clock_->NowTicks();
548 }
549
550 protected:
551 testing::StrictMock<MockInputHandler> mock_input_handler_;
552 testing::StrictMock<MockInputHandlerProxyClient> mock_client_;
553 TestInputHandlerProxy input_handler_proxy_;
554 std::vector<InputHandlerProxy::EventDisposition> event_disposition_recorder_;
555 std::vector<ui::LatencyInfo> latency_info_recorder_;
556
557 uint64_t next_begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
558
559 base::test::SingleThreadTaskEnvironment task_environment_;
560 base::WeakPtrFactory<InputHandlerProxyEventQueueTest> weak_ptr_factory_{this};
561 };
562
563 // Tests that changing source devices mid gesture scroll is handled gracefully.
564 // For example, when a touch scroll is in progress and the user initiates a
565 // scrollbar scroll before the touch scroll has had a chance to dispatch a GSE.
TEST_P(InputHandlerProxyTest,NestedGestureBasedScrollsDifferentSourceDevice)566 TEST_P(InputHandlerProxyTest, NestedGestureBasedScrollsDifferentSourceDevice) {
567 // Touchpad initiates a scroll.
568 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
569 .WillOnce(testing::Return(kImplThreadScrollState));
570 EXPECT_CALL(
571 mock_input_handler_,
572 RecordScrollBegin(ui::ScrollInputType::kWheel,
573 cc::ScrollBeginThreadState::kScrollingOnCompositor))
574 .Times(1);
575
576 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
577 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
578 EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
579 HandleInputEventAndFlushEventQueue(mock_input_handler_,
580 input_handler_.get(), gesture_));
581 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
582
583 VERIFY_AND_RESET_MOCKS();
584
585 // Before ScrollEnd for touchpad is fired, user starts a thumb drag. This is
586 // expected to immediately end the touchpad scroll.
587 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(ui::ScrollInputType::kWheel))
588 .Times(1);
589 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
590 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
591 .WillOnce(testing::Return(kImplThreadScrollState));
592 EXPECT_CALL(
593 mock_input_handler_,
594 RecordScrollBegin(ui::ScrollInputType::kScrollbar,
595 cc::ScrollBeginThreadState::kScrollingOnCompositor))
596 .Times(1);
597 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
598 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
599 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
600 .WillOnce(testing::Return(false));
601 }
602
603 WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
604 WebInputEvent::kNoModifiers,
605 WebInputEvent::GetStaticTimeStampForTests());
606 mouse_event.SetPositionInWidget(gfx::PointF(0, 20));
607 mouse_event.button = WebMouseEvent::Button::kLeft;
608
609 cc::InputHandlerPointerResult pointer_down_result;
610 pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
611 pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
612 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
613 .WillOnce(testing::Return(pointer_down_result));
614
615 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
616 HandleInputEventAndFlushEventQueue(
617 mock_input_handler_, input_handler_.get(), mouse_event));
618
619 VERIFY_AND_RESET_MOCKS();
620
621 // Touchpad GSE comes in while a scrollbar drag is in progress. This is
622 // expected to be dropped because a scrollbar scroll is currently active.
623 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
624 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
625 gesture_.data.scroll_update.delta_y = 0;
626 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(ui::ScrollInputType::kWheel))
627 .Times(1);
628 EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
629 HandleInputEventAndFlushEventQueue(mock_input_handler_,
630 input_handler_.get(), gesture_));
631 VERIFY_AND_RESET_MOCKS();
632
633 // The GSE from the scrollbar needs to be handled.
634 EXPECT_CALL(mock_input_handler_,
635 RecordScrollEnd(ui::ScrollInputType::kScrollbar))
636 .Times(1);
637 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
638 cc::InputHandlerPointerResult pointer_up_result;
639 pointer_up_result.type = cc::PointerResultType::kScrollbarScroll;
640 EXPECT_CALL(mock_input_handler_, MouseUp(_))
641 .WillOnce(testing::Return(pointer_up_result));
642 mouse_event.SetType(WebInputEvent::Type::kMouseUp);
643 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
644 HandleInputEventAndFlushEventQueue(
645 mock_input_handler_, input_handler_.get(), mouse_event));
646 VERIFY_AND_RESET_MOCKS();
647 }
648
TEST_P(InputHandlerProxyTest,MouseWheelNoListener)649 TEST_P(InputHandlerProxyTest, MouseWheelNoListener) {
650 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
651 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
652 .WillRepeatedly(testing::Return(false));
653 EXPECT_CALL(mock_input_handler_,
654 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
655 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
656
657 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
658 WebInputEvent::kControlKey,
659 WebInputEvent::GetStaticTimeStampForTests());
660 EXPECT_EQ(expected_disposition_,
661 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
662 VERIFY_AND_RESET_MOCKS();
663 }
664
TEST_P(InputHandlerProxyTest,MouseWheelPassiveListener)665 TEST_P(InputHandlerProxyTest, MouseWheelPassiveListener) {
666 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
667 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
668 .WillRepeatedly(testing::Return(false));
669 EXPECT_CALL(mock_input_handler_,
670 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
671 .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
672
673 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
674 WebInputEvent::kControlKey,
675 WebInputEvent::GetStaticTimeStampForTests());
676 EXPECT_EQ(expected_disposition_,
677 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
678 VERIFY_AND_RESET_MOCKS();
679 }
680
TEST_P(InputHandlerProxyTest,MouseWheelBlockingListener)681 TEST_P(InputHandlerProxyTest, MouseWheelBlockingListener) {
682 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
683 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
684 .WillRepeatedly(testing::Return(true));
685
686 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
687 WebInputEvent::kControlKey,
688 WebInputEvent::GetStaticTimeStampForTests());
689 EXPECT_EQ(expected_disposition_,
690 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
691 VERIFY_AND_RESET_MOCKS();
692 }
693
TEST_P(InputHandlerProxyTest,MouseWheelBlockingAndPassiveListener)694 TEST_P(InputHandlerProxyTest, MouseWheelBlockingAndPassiveListener) {
695 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
696 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
697 .WillRepeatedly(testing::Return(true));
698 // We will not call GetEventListenerProperties because we early out when we
699 // hit blocking region.
700 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
701 WebInputEvent::kControlKey,
702 WebInputEvent::GetStaticTimeStampForTests());
703 EXPECT_EQ(expected_disposition_,
704 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
705 VERIFY_AND_RESET_MOCKS();
706 }
707
TEST_P(InputHandlerProxyTest,MouseWheelEventOutsideBlockingListener)708 TEST_P(InputHandlerProxyTest, MouseWheelEventOutsideBlockingListener) {
709 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
710 EXPECT_CALL(mock_input_handler_,
711 HasBlockingWheelEventHandlerAt(
712 testing::Property(&gfx::Point::y, testing::Gt(10))))
713 .WillRepeatedly(testing::Return(true));
714 EXPECT_CALL(mock_input_handler_,
715 HasBlockingWheelEventHandlerAt(
716 testing::Property(&gfx::Point::y, testing::Le(10))))
717 .WillRepeatedly(testing::Return(false));
718 EXPECT_CALL(mock_input_handler_,
719 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
720 .WillRepeatedly(testing::Return(cc::EventListenerProperties::kBlocking));
721
722 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
723 WebInputEvent::kControlKey,
724 WebInputEvent::GetStaticTimeStampForTests());
725 wheel.SetPositionInScreen(0, 5);
726 wheel.SetPositionInWidget(0, 5);
727 EXPECT_EQ(expected_disposition_,
728 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
729 VERIFY_AND_RESET_MOCKS();
730 }
731
TEST_P(InputHandlerProxyTest,MouseWheelEventOutsideBlockingListenerWithPassiveListener)732 TEST_P(InputHandlerProxyTest,
733 MouseWheelEventOutsideBlockingListenerWithPassiveListener) {
734 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
735 EXPECT_CALL(mock_input_handler_,
736 HasBlockingWheelEventHandlerAt(
737 testing::Property(&gfx::Point::y, testing::Gt(10))))
738 .WillRepeatedly(testing::Return(true));
739 EXPECT_CALL(mock_input_handler_,
740 HasBlockingWheelEventHandlerAt(
741 testing::Property(&gfx::Point::y, testing::Le(10))))
742 .WillRepeatedly(testing::Return(false));
743 EXPECT_CALL(mock_input_handler_,
744 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
745 .WillRepeatedly(
746 testing::Return(cc::EventListenerProperties::kBlockingAndPassive));
747
748 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
749 WebInputEvent::kControlKey,
750 WebInputEvent::GetStaticTimeStampForTests());
751 wheel.SetPositionInScreen(0, 5);
752 wheel.SetPositionInWidget(0, 5);
753 EXPECT_EQ(expected_disposition_,
754 HandleInputEventWithLatencyInfo(input_handler_.get(), wheel));
755 VERIFY_AND_RESET_MOCKS();
756 }
757
758 // Tests that changing source devices when an animated scroll is in progress
759 // ends the current scroll offset animation and ensures that a new one gets
760 // created.
TEST_P(InputHandlerProxyTest,ScrollbarScrollEndOnDeviceChange)761 TEST_P(InputHandlerProxyTest, ScrollbarScrollEndOnDeviceChange) {
762 // A scrollbar scroll begins.
763 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
764 .WillOnce(testing::Return(kImplThreadScrollState));
765 EXPECT_CALL(
766 mock_input_handler_,
767 RecordScrollBegin(ui::ScrollInputType::kScrollbar,
768 cc::ScrollBeginThreadState::kScrollingOnCompositor))
769 .Times(1);
770 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
771 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
772 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
773 .WillOnce(testing::Return(false));
774 }
775 WebMouseEvent mouse_event(WebInputEvent::Type::kMouseDown,
776 WebInputEvent::kNoModifiers,
777 WebInputEvent::GetStaticTimeStampForTests());
778 mouse_event.SetPositionInWidget(gfx::PointF(0, 20));
779 mouse_event.button = WebMouseEvent::Button::kLeft;
780 cc::InputHandlerPointerResult pointer_down_result;
781 pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
782 pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
783 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
784 .WillOnce(testing::Return(pointer_down_result));
785 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
786 HandleInputEventAndFlushEventQueue(
787 mock_input_handler_, input_handler_.get(), mouse_event));
788
789 EXPECT_EQ(input_handler_->currently_active_gesture_device(),
790 WebGestureDevice::kScrollbar);
791 VERIFY_AND_RESET_MOCKS();
792
793 // A mousewheel tick takes place before the scrollbar scroll ends.
794 EXPECT_CALL(mock_input_handler_,
795 RecordScrollEnd(ui::ScrollInputType::kScrollbar))
796 .Times(1);
797 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
798 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
799 .WillOnce(testing::Return(kImplThreadScrollState));
800 EXPECT_CALL(
801 mock_input_handler_,
802 RecordScrollBegin(ui::ScrollInputType::kWheel,
803 cc::ScrollBeginThreadState::kScrollingOnCompositor))
804 .Times(1);
805
806 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
807 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
808 EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
809 HandleInputEventAndFlushEventQueue(mock_input_handler_,
810 input_handler_.get(), gesture_));
811 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
812 EXPECT_EQ(input_handler_->currently_active_gesture_device(),
813 WebGestureDevice::kTouchpad);
814
815 VERIFY_AND_RESET_MOCKS();
816
817 // Mousewheel GSE is then fired and the mousewheel scroll ends.
818 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(ui::ScrollInputType::kWheel))
819 .Times(1);
820 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
821
822 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
823 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
824 EXPECT_EQ(InputHandlerProxy::DID_HANDLE,
825 HandleInputEventAndFlushEventQueue(mock_input_handler_,
826 input_handler_.get(), gesture_));
827
828 VERIFY_AND_RESET_MOCKS();
829
830 // Mouse up gets ignored as the scrollbar scroll already ended before the
831 // mousewheel tick took place.
832 EXPECT_CALL(mock_input_handler_,
833 RecordScrollEnd(ui::ScrollInputType::kScrollbar))
834 .Times(1);
835 mouse_event.SetType(WebInputEvent::Type::kMouseUp);
836 cc::InputHandlerPointerResult pointer_up_result;
837 pointer_up_result.type = cc::PointerResultType::kScrollbarScroll;
838 EXPECT_CALL(mock_input_handler_, MouseUp(_))
839 .WillOnce(testing::Return(pointer_up_result));
840 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
841 HandleInputEventAndFlushEventQueue(
842 mock_input_handler_, input_handler_.get(), mouse_event));
843 VERIFY_AND_RESET_MOCKS();
844 }
845
GestureScrollStarted()846 void InputHandlerProxyTest::GestureScrollStarted() {
847 // We shouldn't send any events to the widget for this gesture.
848 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
849 VERIFY_AND_RESET_MOCKS();
850
851 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
852 .WillOnce(testing::Return(kImplThreadScrollState));
853 EXPECT_CALL(
854 mock_input_handler_,
855 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
856 .Times(1);
857
858 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
859 EXPECT_EQ(expected_disposition_,
860 HandleInputEventAndFlushEventQueue(mock_input_handler_,
861 input_handler_.get(), gesture_));
862
863 // The event should not be marked as handled if scrolling is not possible.
864 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
865 VERIFY_AND_RESET_MOCKS();
866
867 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
868 gesture_.data.scroll_update.delta_y =
869 -40; // -Y means scroll down - i.e. in the +Y direction.
870 EXPECT_CALL(
871 mock_input_handler_,
872 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
873 _))
874 .WillOnce(testing::Return(scroll_result_did_not_scroll_));
875 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
876 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
877 .WillOnce(testing::Return(false));
878 }
879 EXPECT_EQ(expected_disposition_,
880 HandleInputEventAndFlushEventQueue(mock_input_handler_,
881 input_handler_.get(), gesture_));
882
883 // Mark the event as handled if scroll happens.
884 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
885 VERIFY_AND_RESET_MOCKS();
886
887 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
888 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
889 .WillOnce(testing::Return(false));
890 }
891 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
892 gesture_.data.scroll_update.delta_y =
893 -40; // -Y means scroll down - i.e. in the +Y direction.
894 EXPECT_CALL(
895 mock_input_handler_,
896 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
897 _))
898 .WillOnce(testing::Return(scroll_result_did_scroll_));
899 EXPECT_EQ(expected_disposition_,
900 HandleInputEventAndFlushEventQueue(mock_input_handler_,
901 input_handler_.get(), gesture_));
902
903 VERIFY_AND_RESET_MOCKS();
904
905 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
906 gesture_.data.scroll_update.delta_y = 0;
907 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
908 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
909 EXPECT_EQ(expected_disposition_,
910 HandleInputEventAndFlushEventQueue(mock_input_handler_,
911 input_handler_.get(), gesture_));
912
913 VERIFY_AND_RESET_MOCKS();
914 }
TEST_P(InputHandlerProxyTest,GestureScrollStarted)915 TEST_P(InputHandlerProxyTest, GestureScrollStarted) {
916 GestureScrollStarted();
917 }
918
TEST_P(InputHandlerProxyTest,GestureScrollOnMainThread)919 TEST_P(InputHandlerProxyTest, GestureScrollOnMainThread) {
920 // We should send all events to the widget for this gesture.
921 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
922 VERIFY_AND_RESET_MOCKS();
923
924 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
925 .WillOnce(testing::Return(kMainThreadScrollState));
926 EXPECT_CALL(
927 mock_input_handler_,
928 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
929 .Times(1);
930
931 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
932 EXPECT_EQ(expected_disposition_,
933 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
934
935 VERIFY_AND_RESET_MOCKS();
936
937 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
938 gesture_.data.scroll_update.delta_y = 40;
939 EXPECT_EQ(expected_disposition_,
940 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
941
942 VERIFY_AND_RESET_MOCKS();
943
944 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
945 gesture_.data.scroll_update.delta_y = 0;
946 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
947 EXPECT_EQ(expected_disposition_,
948 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
949
950 VERIFY_AND_RESET_MOCKS();
951 }
952
TEST_P(InputHandlerProxyTest,GestureScrollIgnored)953 TEST_P(InputHandlerProxyTest, GestureScrollIgnored) {
954 // We shouldn't handle the GestureScrollBegin.
955 // Instead, we should get a DROP_EVENT result, indicating
956 // that we could determine that there's nothing that could scroll or otherwise
957 // react to this gesture sequence and thus we should drop the whole gesture
958 // sequence on the floor, except for the ScrollEnd.
959 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
960 VERIFY_AND_RESET_MOCKS();
961
962 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
963 .WillOnce(testing::Return(kScrollIgnoredScrollState));
964 EXPECT_CALL(
965 mock_input_handler_,
966 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
967 .Times(1);
968
969 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
970 EXPECT_EQ(expected_disposition_,
971 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
972
973 VERIFY_AND_RESET_MOCKS();
974
975 // GSB is dropped and not sent to the main thread, GSE shouldn't get sent to
976 // the main thread, either.
977 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
978 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
979 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
980 EXPECT_EQ(expected_disposition_,
981 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
982
983 VERIFY_AND_RESET_MOCKS();
984 }
985
TEST_P(InputHandlerProxyTest,GestureScrollByPage)986 TEST_P(InputHandlerProxyTest, GestureScrollByPage) {
987 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
988 VERIFY_AND_RESET_MOCKS();
989
990 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
991 .WillOnce(testing::Return(kImplThreadScrollState));
992
993 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
994 gesture_.data.scroll_begin.delta_hint_units =
995 ui::ScrollGranularity::kScrollByPage;
996 EXPECT_CALL(
997 mock_input_handler_,
998 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
999 .Times(1);
1000 EXPECT_EQ(expected_disposition_,
1001 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1002
1003 VERIFY_AND_RESET_MOCKS();
1004
1005 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1006 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1007 .WillOnce(testing::Return(false));
1008 }
1009 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
1010 .WillOnce(testing::Return(scroll_result_did_scroll_));
1011
1012 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
1013 gesture_.data.scroll_update.delta_y = 1;
1014 gesture_.data.scroll_update.delta_units =
1015 ui::ScrollGranularity::kScrollByPage;
1016 EXPECT_EQ(expected_disposition_,
1017 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1018
1019 VERIFY_AND_RESET_MOCKS();
1020
1021 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(1);
1022 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
1023 gesture_.data.scroll_update.delta_y = 0;
1024 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1025 EXPECT_EQ(expected_disposition_,
1026 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1027
1028 VERIFY_AND_RESET_MOCKS();
1029 }
1030
TEST_P(InputHandlerProxyTest,GestureScrollBeginThatTargetViewport)1031 TEST_P(InputHandlerProxyTest, GestureScrollBeginThatTargetViewport) {
1032 // We shouldn't send any events to the widget for this gesture.
1033 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1034 VERIFY_AND_RESET_MOCKS();
1035
1036 EXPECT_CALL(mock_input_handler_, RootScrollBegin(_, _))
1037 .WillOnce(testing::Return(kImplThreadScrollState));
1038 EXPECT_CALL(
1039 mock_input_handler_,
1040 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
1041 .Times(1);
1042
1043 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1044 gesture_.data.scroll_begin.target_viewport = true;
1045 EXPECT_EQ(expected_disposition_,
1046 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1047
1048 VERIFY_AND_RESET_MOCKS();
1049 }
1050
FlingAndSnap()1051 void InputHandlerProxyTest::FlingAndSnap() {
1052 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1053 VERIFY_AND_RESET_MOCKS();
1054
1055 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1056 .WillOnce(testing::Return(kImplThreadScrollState));
1057 EXPECT_CALL(
1058 mock_input_handler_,
1059 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
1060 .Times(1);
1061
1062 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1063 EXPECT_EQ(expected_disposition_,
1064 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1065
1066 // The event should be dropped if InputHandler decides to snap.
1067 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
1068 VERIFY_AND_RESET_MOCKS();
1069
1070 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
1071 gesture_.data.scroll_update.delta_y =
1072 -40; // -Y means scroll down - i.e. in the +Y direction.
1073 gesture_.data.scroll_update.inertial_phase =
1074 WebGestureEvent::InertialPhaseState::kMomentum;
1075 EXPECT_CALL(mock_input_handler_,
1076 GetSnapFlingInfoAndSetAnimatingSnapTarget(_, _, _))
1077 .WillOnce(DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)),
1078 testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)),
1079 testing::Return(true)));
1080 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
1081 EXPECT_SET_NEEDS_ANIMATE_INPUT(1);
1082 EXPECT_EQ(expected_disposition_,
1083 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1084 VERIFY_AND_RESET_MOCKS();
1085 }
1086
TEST_P(InputHandlerProxyTest,SnapFlingIgnoresFollowingGSUAndGSE)1087 TEST_P(InputHandlerProxyTest, SnapFlingIgnoresFollowingGSUAndGSE) {
1088 FlingAndSnap();
1089 // The next GestureScrollUpdate should also be ignored, and will not ask for
1090 // snap position.
1091 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
1092
1093 EXPECT_CALL(mock_input_handler_,
1094 GetSnapFlingInfoAndSetAnimatingSnapTarget(_, _, _))
1095 .Times(0);
1096 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
1097 EXPECT_EQ(expected_disposition_,
1098 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1099 input_handler_.get(), gesture_));
1100 VERIFY_AND_RESET_MOCKS();
1101
1102 // The GestureScrollEnd should also be ignored.
1103 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
1104 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
1105 gesture_.data.scroll_end.inertial_phase =
1106 WebGestureEvent::InertialPhaseState::kMomentum;
1107 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(0);
1108 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(0);
1109 EXPECT_EQ(expected_disposition_,
1110 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1111 input_handler_.get(), gesture_));
1112 VERIFY_AND_RESET_MOCKS();
1113 }
1114
TEST_P(InputHandlerProxyTest,GesturePinch)1115 TEST_P(InputHandlerProxyTest, GesturePinch) {
1116 // We shouldn't send any events to the widget for this gesture.
1117 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1118 VERIFY_AND_RESET_MOCKS();
1119
1120 gesture_.SetType(WebInputEvent::Type::kGesturePinchBegin);
1121 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
1122 EXPECT_EQ(expected_disposition_,
1123 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1124 input_handler_.get(), gesture_));
1125
1126 VERIFY_AND_RESET_MOCKS();
1127
1128 gesture_.SetType(WebInputEvent::Type::kGesturePinchUpdate);
1129 gesture_.data.pinch_update.scale = 1.5;
1130 gesture_.SetPositionInWidget(gfx::PointF(7, 13));
1131 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13)));
1132 EXPECT_EQ(expected_disposition_,
1133 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1134 input_handler_.get(), gesture_));
1135
1136 VERIFY_AND_RESET_MOCKS();
1137
1138 gesture_.SetType(WebInputEvent::Type::kGesturePinchUpdate);
1139 gesture_.data.pinch_update.scale = 0.5;
1140 gesture_.SetPositionInWidget(gfx::PointF(9, 6));
1141 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6)));
1142 EXPECT_EQ(expected_disposition_,
1143 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1144 input_handler_.get(), gesture_));
1145
1146 VERIFY_AND_RESET_MOCKS();
1147
1148 gesture_.SetType(WebInputEvent::Type::kGesturePinchEnd);
1149 EXPECT_CALL(mock_input_handler_, PinchGestureEnd(gfx::Point(9, 6), true));
1150 EXPECT_EQ(expected_disposition_,
1151 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1152 input_handler_.get(), gesture_));
1153
1154 VERIFY_AND_RESET_MOCKS();
1155 }
1156
TEST_P(InputHandlerProxyTest,GesturePinchAfterScrollOnMainThread)1157 TEST_P(InputHandlerProxyTest, GesturePinchAfterScrollOnMainThread) {
1158 // This situation is no longer possible under scroll unification as all
1159 // scrolling now happens on the compositor thread. This test can be removed
1160 // when the feature ships.
1161 if (base::FeatureList::IsEnabled(features::kScrollUnification))
1162 return;
1163
1164 // Scrolls will start by being sent to the main thread.
1165 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
1166 VERIFY_AND_RESET_MOCKS();
1167
1168 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1169 .WillOnce(testing::Return(kMainThreadScrollState));
1170 EXPECT_CALL(
1171 mock_input_handler_,
1172 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
1173 .Times(1);
1174
1175 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1176 EXPECT_EQ(expected_disposition_,
1177 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1178 input_handler_.get(), gesture_));
1179
1180 VERIFY_AND_RESET_MOCKS();
1181
1182 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
1183 gesture_.data.scroll_update.delta_y = 40;
1184 EXPECT_EQ(expected_disposition_,
1185 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1186 input_handler_.get(), gesture_));
1187
1188 // However, after the pinch gesture starts, they should go to the impl
1189 // thread.
1190 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1191 VERIFY_AND_RESET_MOCKS();
1192
1193 gesture_.SetType(WebInputEvent::Type::kGesturePinchBegin);
1194 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
1195 EXPECT_EQ(expected_disposition_,
1196 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1197 input_handler_.get(), gesture_));
1198
1199 VERIFY_AND_RESET_MOCKS();
1200
1201 gesture_.SetType(WebInputEvent::Type::kGesturePinchUpdate);
1202 gesture_.data.pinch_update.scale = 1.5;
1203 gesture_.SetPositionInWidget(gfx::PointF(7, 13));
1204 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(1.5, gfx::Point(7, 13)));
1205 EXPECT_EQ(expected_disposition_,
1206 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1207 input_handler_.get(), gesture_));
1208
1209 VERIFY_AND_RESET_MOCKS();
1210
1211 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1212 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1213 .WillOnce(testing::Return(false));
1214 }
1215 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
1216 gesture_.data.scroll_update.delta_y =
1217 -40; // -Y means scroll down - i.e. in the +Y direction.
1218 EXPECT_CALL(
1219 mock_input_handler_,
1220 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
1221 _))
1222 .WillOnce(testing::Return(scroll_result_did_scroll_));
1223 EXPECT_EQ(expected_disposition_,
1224 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1225 input_handler_.get(), gesture_));
1226
1227 VERIFY_AND_RESET_MOCKS();
1228
1229 gesture_.SetType(WebInputEvent::Type::kGesturePinchUpdate);
1230 gesture_.data.pinch_update.scale = 0.5;
1231 gesture_.SetPositionInWidget(gfx::PointF(9, 6));
1232 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(.5, gfx::Point(9, 6)));
1233 EXPECT_EQ(expected_disposition_,
1234 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1235 input_handler_.get(), gesture_));
1236
1237 VERIFY_AND_RESET_MOCKS();
1238
1239 gesture_.SetType(WebInputEvent::Type::kGesturePinchEnd);
1240 EXPECT_CALL(mock_input_handler_, PinchGestureEnd(gfx::Point(9, 6), true));
1241 EXPECT_EQ(expected_disposition_,
1242 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1243 input_handler_.get(), gesture_));
1244
1245 // After the pinch gesture ends, they should go to back to the main
1246 // thread.
1247 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
1248 VERIFY_AND_RESET_MOCKS();
1249
1250 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
1251 gesture_.data.scroll_update.delta_y = 0;
1252 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1253 EXPECT_EQ(expected_disposition_,
1254 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1255
1256 VERIFY_AND_RESET_MOCKS();
1257 }
1258
ScrollHandlingSwitchedToMainThread()1259 void InputHandlerProxyTest::ScrollHandlingSwitchedToMainThread() {
1260 // We shouldn't send any events to the widget for this gesture.
1261 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1262 VERIFY_AND_RESET_MOCKS();
1263
1264 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1265 .WillOnce(testing::Return(kImplThreadScrollState));
1266 EXPECT_CALL(
1267 mock_input_handler_,
1268 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
1269 .Times(1);
1270
1271 // HandleGestureScrollBegin will set gesture_scroll_on_impl_thread_.
1272 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1273 EXPECT_EQ(expected_disposition_,
1274 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1275 input_handler_.get(), gesture_));
1276 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1277
1278 VERIFY_AND_RESET_MOCKS();
1279
1280 gesture_.SetType(WebInputEvent::Type::kGestureScrollUpdate);
1281 gesture_.data.scroll_update.delta_y = -40;
1282 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1283 .WillOnce(testing::Return(false));
1284 EXPECT_CALL(
1285 mock_input_handler_,
1286 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
1287 _))
1288 .WillOnce(testing::Return(scroll_result_did_scroll_));
1289 EXPECT_EQ(expected_disposition_,
1290 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1291 input_handler_.get(), gesture_));
1292 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1293 VERIFY_AND_RESET_MOCKS();
1294
1295 // The scroll handling switches to the main thread, a GSB is sent to the main
1296 // thread to initiate the hit testing and compute the scroll chain.
1297 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
1298 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
1299 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1300 .WillOnce(testing::Return(true));
1301 EXPECT_CALL(mock_client_, GenerateScrollBeginAndSendToMainThread(_, _, _));
1302 EXPECT_EQ(expected_disposition_,
1303 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1304 input_handler_.get(), gesture_));
1305 EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1306
1307 VERIFY_AND_RESET_MOCKS();
1308
1309 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
1310 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1311 EXPECT_EQ(expected_disposition_,
1312 HandleInputEventAndFlushEventQueue(mock_input_handler_,
1313 input_handler_.get(), gesture_));
1314
1315 VERIFY_AND_RESET_MOCKS();
1316 }
TEST_P(InputHandlerProxyTest,WheelScrollHandlingSwitchedToMainThread)1317 TEST_P(InputHandlerProxyTest, WheelScrollHandlingSwitchedToMainThread) {
1318 // This situation is no longer possible under scroll unification as all
1319 // scrolling now happens on the compositor thread. This test can be removed
1320 // when the feature ships.
1321 if (base::FeatureList::IsEnabled(features::kScrollUnification))
1322 return;
1323
1324 gesture_.SetSourceDevice(WebGestureDevice::kTouchpad);
1325 ScrollHandlingSwitchedToMainThread();
1326 }
TEST_P(InputHandlerProxyTest,TouchScrollHandlingSwitchedToMainThread)1327 TEST_P(InputHandlerProxyTest, TouchScrollHandlingSwitchedToMainThread) {
1328 // This situation is no longer possible under scroll unification as all
1329 // scrolling now happens on the compositor thread. This test can be removed
1330 // when the feature ships.
1331 if (base::FeatureList::IsEnabled(features::kScrollUnification))
1332 return;
1333
1334 gesture_.SetSourceDevice(WebGestureDevice::kTouchscreen);
1335 ScrollHandlingSwitchedToMainThread();
1336 }
1337
TEST_P(InputHandlerProxyTest,GestureScrollOnImplThreadFlagClearedAfterScrollEnd)1338 TEST_P(InputHandlerProxyTest,
1339 GestureScrollOnImplThreadFlagClearedAfterScrollEnd) {
1340 // We shouldn't send any events to the widget for this gesture.
1341 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1342 VERIFY_AND_RESET_MOCKS();
1343
1344 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1345 .WillOnce(testing::Return(kImplThreadScrollState));
1346 EXPECT_CALL(
1347 mock_input_handler_,
1348 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
1349 .Times(1);
1350
1351 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1352 EXPECT_EQ(expected_disposition_,
1353 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1354
1355 // After sending a GestureScrollBegin, the member variable
1356 // |gesture_scroll_on_impl_thread_| should be true.
1357 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1358
1359 VERIFY_AND_RESET_MOCKS();
1360
1361 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
1362 gesture_.SetType(WebInputEvent::Type::kGestureScrollEnd);
1363 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1364 EXPECT_EQ(expected_disposition_,
1365 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1366
1367 // |gesture_scroll_on_impl_thread_| should be false once a GestureScrollEnd
1368 // gets handled.
1369 EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1370
1371 VERIFY_AND_RESET_MOCKS();
1372 }
1373
TEST_P(InputHandlerProxyTest,BeginScrollWhenGestureScrollOnImplThreadFlagIsSet)1374 TEST_P(InputHandlerProxyTest,
1375 BeginScrollWhenGestureScrollOnImplThreadFlagIsSet) {
1376 // We shouldn't send any events to the widget for this gesture.
1377 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1378 VERIFY_AND_RESET_MOCKS();
1379
1380 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1381 .WillOnce(testing::Return(kImplThreadScrollState));
1382 EXPECT_CALL(
1383 mock_input_handler_,
1384 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
1385 .Times(1);
1386
1387 gesture_.SetType(WebInputEvent::Type::kGestureScrollBegin);
1388 EXPECT_EQ(expected_disposition_,
1389 HandleInputEventWithLatencyInfo(input_handler_.get(), gesture_));
1390
1391 // After sending a GestureScrollBegin, the member variable
1392 // |gesture_scroll_on_impl_thread_| should be true.
1393 EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
1394
1395 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
1396 VERIFY_AND_RESET_MOCKS();
1397 }
1398
TEST_P(InputHandlerProxyTest,HitTestTouchEventNonNullTouchAction)1399 TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
1400 // One of the touch points is on a touch-region. So the event should be sent
1401 // to the main thread.
1402 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
1403 VERIFY_AND_RESET_MOCKS();
1404
1405 EXPECT_CALL(mock_input_handler_,
1406 EventListenerTypeForTouchStartOrMoveAt(
1407 testing::Property(&gfx::Point::x, testing::Eq(0)), _))
1408 .WillOnce(testing::Invoke([](const gfx::Point&,
1409 cc::TouchAction* touch_action) {
1410 *touch_action = cc::TouchAction::kMax;
1411 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1412 }));
1413
1414 EXPECT_CALL(mock_input_handler_,
1415 EventListenerTypeForTouchStartOrMoveAt(
1416 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
1417 .WillOnce(
1418 testing::Invoke([](const gfx::Point&, cc::TouchAction* touch_action) {
1419 *touch_action = cc::TouchAction::kPanUp;
1420 return cc::InputHandler::TouchStartOrMoveEventListenerType::
1421 HANDLER_ON_SCROLLING_LAYER;
1422 }));
1423 // Since the second touch point hits a touch-region, there should be no
1424 // hit-testing for the third touch point.
1425
1426 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1427 WebInputEvent::kNoModifiers,
1428 WebInputEvent::GetStaticTimeStampForTests());
1429
1430 touch.touches_length = 3;
1431 touch.touch_start_or_first_touch_move = true;
1432 touch.touches[0] =
1433 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1434 touch.touches[1] =
1435 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1436 touch.touches[2] =
1437 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
1438
1439 bool is_touching_scrolling_layer;
1440 cc::TouchAction allowed_touch_action = cc::TouchAction::kAuto;
1441 EXPECT_EQ(expected_disposition_,
1442 input_handler_->HitTestTouchEventForTest(
1443 touch, &is_touching_scrolling_layer, &allowed_touch_action));
1444 EXPECT_TRUE(is_touching_scrolling_layer);
1445 EXPECT_EQ(allowed_touch_action, cc::TouchAction::kPanUp);
1446 VERIFY_AND_RESET_MOCKS();
1447 }
1448
1449 // Tests that multiple mousedown(s) on scrollbar are handled gracefully and
1450 // don't fail any DCHECK(s).
TEST_F(InputHandlerProxyEventQueueTest,NestedGestureBasedScrollsSameSourceDevice)1451 TEST_F(InputHandlerProxyEventQueueTest,
1452 NestedGestureBasedScrollsSameSourceDevice) {
1453 // Start with mousedown. Expect CompositorThreadEventQueue to contain [GSB,
1454 // GSU].
1455 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
1456 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1457 .Times(3)
1458 .WillRepeatedly(testing::Return(cc::ElementId()));
1459
1460 cc::InputHandlerPointerResult pointer_down_result;
1461 pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
1462 pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
1463 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
1464 .WillOnce(testing::Return(pointer_down_result));
1465
1466 HandleMouseEvent(WebInputEvent::Type::kMouseDown);
1467 EXPECT_EQ(2ul, event_queue().size());
1468 EXPECT_EQ(event_queue()[0]->event().GetType(),
1469 WebInputEvent::Type::kGestureScrollBegin);
1470 EXPECT_EQ(event_queue()[1]->event().GetType(),
1471 WebInputEvent::Type::kGestureScrollUpdate);
1472
1473 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1474 .WillOnce(Return(kImplThreadScrollState));
1475 EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
1476 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1477 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1478 .WillOnce(Return(false));
1479 }
1480 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
1481
1482 DeliverInputForBeginFrame();
1483 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1484
1485 // A mouseup adds a GSE to the CompositorThreadEventQueue.
1486 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
1487 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1488 .Times(1)
1489 .WillOnce(testing::Return(cc::ElementId()));
1490 cc::InputHandlerPointerResult pointer_up_result;
1491 pointer_up_result.type = cc::PointerResultType::kScrollbarScroll;
1492 EXPECT_CALL(mock_input_handler_, MouseUp(_))
1493 .WillOnce(testing::Return(pointer_up_result));
1494 HandleMouseEvent(WebInputEvent::Type::kMouseUp);
1495 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1496
1497 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1498 .Times(1)
1499 .WillOnce(testing::Return(cc::ElementId()));
1500 EXPECT_EQ(1ul, event_queue().size());
1501 EXPECT_EQ(event_queue()[0]->event().GetType(),
1502 WebInputEvent::Type::kGestureScrollEnd);
1503
1504 // Called when a mousedown is being handled as it tries to end the ongoing
1505 // scroll.
1506 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1507 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
1508
1509 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
1510 .WillOnce(testing::Return(pointer_down_result));
1511 // A mousedown occurs on the scrollbar *before* the GSE is dispatched.
1512 HandleMouseEvent(WebInputEvent::Type::kMouseDown);
1513 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1514
1515 EXPECT_EQ(3ul, event_queue().size());
1516 EXPECT_EQ(event_queue()[1]->event().GetType(),
1517 WebInputEvent::Type::kGestureScrollBegin);
1518 EXPECT_EQ(event_queue()[2]->event().GetType(),
1519 WebInputEvent::Type::kGestureScrollUpdate);
1520
1521 // Called when the GSE is being handled. (Note that ScrollEnd isn't called
1522 // when the GSE is being handled as the GSE gets dropped in
1523 // HandleGestureScrollEnd because handling_gesture_on_impl_thread_ is false)
1524 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1525 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1526 .WillOnce(Return(kImplThreadScrollState));
1527 EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
1528 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1529 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1530 .WillOnce(Return(false));
1531 }
1532 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
1533 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1534 .Times(3)
1535 .WillRepeatedly(testing::Return(cc::ElementId()));
1536
1537 DeliverInputForBeginFrame();
1538 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1539
1540 // Finally, a mouseup ends the scroll.
1541 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
1542 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1543 .Times(2)
1544 .WillRepeatedly(testing::Return(cc::ElementId()));
1545 EXPECT_CALL(mock_input_handler_, MouseUp(_))
1546 .WillOnce(testing::Return(pointer_up_result));
1547 HandleMouseEvent(WebInputEvent::Type::kMouseUp);
1548
1549 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
1550 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
1551
1552 DeliverInputForBeginFrame();
1553 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1554 }
1555
1556 // Tests that the allowed touch action is correctly set when a touch is made
1557 // non-blocking due to an ongoing fling. https://crbug.com/1048098.
TEST_F(InputHandlerProxyEventQueueTest,AckTouchActionNonBlockingForFling)1558 TEST_F(InputHandlerProxyEventQueueTest, AckTouchActionNonBlockingForFling) {
1559 // Simulate starting a compositor scroll and then flinging. This is setup for
1560 // the real checks below.
1561 {
1562 float delta = 10;
1563
1564 // ScrollBegin
1565 {
1566 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
1567 .WillOnce(Return(kImplThreadScrollState));
1568 EXPECT_CALL(
1569 mock_input_handler_,
1570 RecordScrollBegin(_, ScrollBeginThreadState::kScrollingOnCompositor))
1571 .Times(1);
1572 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1573 .Times(1)
1574 .WillOnce(testing::Return(cc::ElementId()));
1575
1576 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin, delta);
1577 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1578 }
1579
1580 // ScrollUpdate
1581 {
1582 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
1583 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1584 .Times(1)
1585 .WillOnce(testing::Return(cc::ElementId()));
1586 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1587 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1588 .WillOnce(Return(false));
1589 }
1590 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
1591
1592 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, delta);
1593 DeliverInputForBeginFrame();
1594 Mock::VerifyAndClearExpectations(&mock_input_handler_);
1595 }
1596
1597 // Start a fling - ScrollUpdate with momentum
1598 {
1599 cc::InputHandlerScrollResult scroll_result_did_scroll;
1600 scroll_result_did_scroll.did_scroll = true;
1601 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
1602 .WillOnce(Return(scroll_result_did_scroll));
1603 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
1604 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
1605 .Times(2)
1606 .WillRepeatedly(testing::Return(cc::ElementId()));
1607 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
1608 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
1609 .WillOnce(Return(false));
1610 }
1611 EXPECT_CALL(mock_input_handler_,
1612 GetSnapFlingInfoAndSetAnimatingSnapTarget(_, _, _))
1613 .WillOnce(Return(false));
1614
1615 auto gsu_fling = CreateGestureScrollPinch(
1616 WebInputEvent::Type::kGestureScrollUpdate,
1617 WebGestureDevice::kTouchscreen, NowTimestampForEvents(), delta,
1618 /*x=*/0, /*y=*/0);
1619 static_cast<WebGestureEvent*>(gsu_fling.get())
1620 ->data.scroll_update.inertial_phase =
1621 WebGestureEvent::InertialPhaseState::kMomentum;
1622 InjectInputEvent(std::move(gsu_fling));
1623 DeliverInputForBeginFrame();
1624 }
1625 }
1626
1627 // We're now in an active gesture fling. Simulate the user touching down on
1628 // the screen. If this touch hits a blocking region (e.g. touch-action or a
1629 // non-passive touchstart listener), we won't actually treat it as blocking;
1630 // because of the ongoing fling it will be treated as non blocking. However,
1631 // we also have to ensure that the allowed_touch_action reported is also kAuto
1632 // so that the browser knows that it shouldn't wait for an ACK with an allowed
1633 // touch-action before dispatching more scrolls.
1634 {
1635 // Simulate hitting a blocking region on the scrolling layer, as if there
1636 // was a non-passive touchstart handler.
1637 EXPECT_CALL(mock_input_handler_,
1638 EventListenerTypeForTouchStartOrMoveAt(_, _))
1639 .WillOnce(DoAll(SetArgPointee<1>(TouchAction::kNone),
1640 Return(InputHandler::TouchStartOrMoveEventListenerType::
1641 HANDLER_ON_SCROLLING_LAYER)));
1642
1643 std::unique_ptr<WebTouchEvent> touch_start =
1644 std::make_unique<WebTouchEvent>(
1645 WebInputEvent::Type::kTouchStart, WebInputEvent::kNoModifiers,
1646 WebInputEvent::GetStaticTimeStampForTests());
1647 touch_start->touches_length = 1;
1648 touch_start->touch_start_or_first_touch_move = true;
1649 touch_start->touches[0] =
1650 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1651
1652 // This is the call this test is checking: we expect that the client will
1653 // report the touch as non-blocking and also that the allowed touch action
1654 // matches the non blocking expectation (i.e. all touches are allowed).
1655 EXPECT_CALL(
1656 mock_client_,
1657 SetAllowedTouchAction(
1658 TouchAction::kAuto, touch_start->unique_touch_event_id,
1659 InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING))
1660 .WillOnce(Return());
1661
1662 InjectInputEvent(std::move(touch_start));
1663 }
1664 }
1665
TEST_P(InputHandlerProxyTest,HitTestTouchEventNullTouchAction)1666 TEST_P(InputHandlerProxyTest, HitTestTouchEventNullTouchAction) {
1667 // One of the touch points is on a touch-region. So the event should be sent
1668 // to the main thread.
1669 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
1670 VERIFY_AND_RESET_MOCKS();
1671
1672 EXPECT_CALL(mock_input_handler_,
1673 EventListenerTypeForTouchStartOrMoveAt(
1674 testing::Property(&gfx::Point::x, testing::Eq(0)), _))
1675 .WillOnce(testing::Return(
1676 cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
1677
1678 EXPECT_CALL(mock_input_handler_,
1679 EventListenerTypeForTouchStartOrMoveAt(
1680 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
1681 .WillOnce(
1682 testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
1683 HANDLER_ON_SCROLLING_LAYER));
1684 // Since the second touch point hits a touch-region, there should be no
1685 // hit-testing for the third touch point.
1686
1687 WebTouchEvent touch(WebInputEvent::Type::kTouchMove,
1688 WebInputEvent::kNoModifiers,
1689 WebInputEvent::GetStaticTimeStampForTests());
1690
1691 touch.touches_length = 3;
1692 touch.touches[0] =
1693 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1694 touch.touches[1] =
1695 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1696 touch.touches[2] =
1697 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
1698
1699 bool is_touching_scrolling_layer;
1700 cc::TouchAction* allowed_touch_action = nullptr;
1701 EXPECT_EQ(expected_disposition_,
1702 input_handler_->HitTestTouchEventForTest(
1703 touch, &is_touching_scrolling_layer, allowed_touch_action));
1704 EXPECT_TRUE(is_touching_scrolling_layer);
1705 EXPECT_TRUE(!allowed_touch_action);
1706 VERIFY_AND_RESET_MOCKS();
1707 }
1708
TEST_P(InputHandlerProxyTest,MultiTouchPointHitTestNegative)1709 TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) {
1710 // None of the three touch points fall in the touch region. So the event
1711 // should be dropped.
1712 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
1713 VERIFY_AND_RESET_MOCKS();
1714
1715 EXPECT_CALL(
1716 mock_input_handler_,
1717 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
1718 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
1719 EXPECT_CALL(
1720 mock_input_handler_,
1721 GetEventListenerProperties(cc::EventListenerClass::kTouchEndOrCancel))
1722 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
1723 EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
1724 .Times(2)
1725 .WillRepeatedly(testing::Invoke([](const gfx::Point&,
1726 cc::TouchAction* touch_action) {
1727 *touch_action = cc::TouchAction::kPanUp;
1728 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1729 }));
1730 EXPECT_CALL(mock_client_,
1731 SetAllowedTouchAction(cc::TouchAction::kPanUp, 1,
1732 InputHandlerProxy::DROP_EVENT))
1733 .WillOnce(testing::Return());
1734
1735 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1736 WebInputEvent::kNoModifiers,
1737 WebInputEvent::GetStaticTimeStampForTests());
1738
1739 touch.unique_touch_event_id = 1;
1740 touch.touches_length = 3;
1741 touch.touch_start_or_first_touch_move = true;
1742 touch.touches[0] =
1743 CreateWebTouchPoint(WebTouchPoint::State::kStateStationary, 0, 0);
1744 touch.touches[1] =
1745 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1746 touch.touches[2] =
1747 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
1748 EXPECT_EQ(expected_disposition_,
1749 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1750
1751 VERIFY_AND_RESET_MOCKS();
1752 }
1753
TEST_P(InputHandlerProxyTest,MultiTouchPointHitTestPositive)1754 TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
1755 // One of the touch points is on a touch-region. So the event should be sent
1756 // to the main thread.
1757 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
1758 VERIFY_AND_RESET_MOCKS();
1759
1760 EXPECT_CALL(mock_input_handler_,
1761 EventListenerTypeForTouchStartOrMoveAt(
1762 testing::Property(&gfx::Point::x, testing::Eq(0)), _))
1763 .WillOnce(testing::Invoke([](const gfx::Point&,
1764 cc::TouchAction* touch_action) {
1765 *touch_action = cc::TouchAction::kAuto;
1766 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1767 }));
1768 EXPECT_CALL(mock_input_handler_,
1769 EventListenerTypeForTouchStartOrMoveAt(
1770 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
1771 .WillOnce(
1772 testing::Invoke([](const gfx::Point&, cc::TouchAction* touch_action) {
1773 *touch_action = cc::TouchAction::kPanY;
1774 return cc::InputHandler::TouchStartOrMoveEventListenerType::
1775 HANDLER_ON_SCROLLING_LAYER;
1776 }));
1777 EXPECT_CALL(mock_client_, SetAllowedTouchAction(cc::TouchAction::kPanY, 1,
1778 expected_disposition_))
1779 .WillOnce(testing::Return());
1780 // Since the second touch point hits a touch-region, there should be no
1781 // hit-testing for the third touch point.
1782
1783 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1784 WebInputEvent::kNoModifiers,
1785 WebInputEvent::GetStaticTimeStampForTests());
1786
1787 touch.unique_touch_event_id = 1;
1788 touch.touches_length = 3;
1789 touch.touch_start_or_first_touch_move = true;
1790 touch.touches[0] =
1791 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1792 touch.touches[1] =
1793 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1794 touch.touches[2] =
1795 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
1796 EXPECT_EQ(expected_disposition_,
1797 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1798
1799 VERIFY_AND_RESET_MOCKS();
1800 }
1801
TEST_P(InputHandlerProxyTest,MultiTouchPointHitTestPassivePositive)1802 TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPassivePositive) {
1803 // One of the touch points is not on a touch-region. So the event should be
1804 // sent to the impl thread.
1805 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
1806 VERIFY_AND_RESET_MOCKS();
1807
1808 EXPECT_CALL(
1809 mock_input_handler_,
1810 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
1811 .WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive));
1812 EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
1813 .Times(3)
1814 .WillOnce(testing::Invoke([](const gfx::Point&,
1815 cc::TouchAction* touch_action) {
1816 *touch_action = cc::TouchAction::kPanRight;
1817 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1818 }))
1819 .WillRepeatedly(testing::Invoke([](const gfx::Point&,
1820 cc::TouchAction* touch_action) {
1821 *touch_action = cc::TouchAction::kPanX;
1822 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1823 }));
1824 EXPECT_CALL(mock_client_,
1825 SetAllowedTouchAction(cc::TouchAction::kPanRight, 1,
1826 InputHandlerProxy::DID_HANDLE_NON_BLOCKING))
1827 .WillOnce(testing::Return());
1828
1829 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1830 WebInputEvent::kNoModifiers,
1831 WebInputEvent::GetStaticTimeStampForTests());
1832
1833 touch.unique_touch_event_id = 1;
1834 touch.touches_length = 3;
1835 touch.touch_start_or_first_touch_move = true;
1836 touch.touches[0] =
1837 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1838 touch.touches[1] =
1839 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1840 touch.touches[2] =
1841 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
1842 EXPECT_EQ(expected_disposition_,
1843 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1844
1845 VERIFY_AND_RESET_MOCKS();
1846 }
1847
TEST_P(InputHandlerProxyTest,TouchStartPassiveAndTouchEndBlocking)1848 TEST_P(InputHandlerProxyTest, TouchStartPassiveAndTouchEndBlocking) {
1849 // The touch start is not in a touch-region but there is a touch end handler
1850 // so to maintain targeting we need to dispatch the touch start as
1851 // non-blocking but drop all touch moves.
1852 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
1853 VERIFY_AND_RESET_MOCKS();
1854
1855 EXPECT_CALL(
1856 mock_input_handler_,
1857 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
1858 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
1859 EXPECT_CALL(
1860 mock_input_handler_,
1861 GetEventListenerProperties(cc::EventListenerClass::kTouchEndOrCancel))
1862 .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking));
1863 EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
1864 .WillOnce(testing::Invoke([](const gfx::Point&,
1865 cc::TouchAction* touch_action) {
1866 *touch_action = cc::TouchAction::kNone;
1867 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
1868 }));
1869 EXPECT_CALL(mock_client_,
1870 SetAllowedTouchAction(cc::TouchAction::kNone, 1,
1871 InputHandlerProxy::DID_HANDLE_NON_BLOCKING))
1872 .WillOnce(testing::Return());
1873
1874 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1875 WebInputEvent::kNoModifiers,
1876 WebInputEvent::GetStaticTimeStampForTests());
1877 touch.unique_touch_event_id = 1;
1878 touch.touches_length = 1;
1879 touch.touches[0] =
1880 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1881 touch.touch_start_or_first_touch_move = true;
1882 EXPECT_EQ(expected_disposition_,
1883 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1884
1885 touch.SetType(WebInputEvent::Type::kTouchMove);
1886 touch.touches_length = 1;
1887 touch.touch_start_or_first_touch_move = false;
1888 touch.touches[0] =
1889 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
1890 EXPECT_EQ(InputHandlerProxy::DROP_EVENT,
1891 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1892 VERIFY_AND_RESET_MOCKS();
1893 }
1894
TEST_P(InputHandlerProxyTest,TouchMoveBlockingAddedAfterPassiveTouchStart)1895 TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
1896 // The touch start is not in a touch-region but there is a touch end handler
1897 // so to maintain targeting we need to dispatch the touch start as
1898 // non-blocking but drop all touch moves.
1899 VERIFY_AND_RESET_MOCKS();
1900
1901 EXPECT_CALL(
1902 mock_input_handler_,
1903 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
1904 .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
1905 EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
1906 .WillOnce(testing::Return(
1907 cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
1908 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
1909 .WillOnce(testing::Return());
1910
1911 cc::InputHandlerPointerResult pointer_down_result;
1912 pointer_down_result.type = cc::PointerResultType::kUnhandled;
1913 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
1914 .WillOnce(testing::Return(pointer_down_result));
1915
1916 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
1917 WebInputEvent::kNoModifiers,
1918 WebInputEvent::GetStaticTimeStampForTests());
1919 touch.touches_length = 1;
1920 touch.touch_start_or_first_touch_move = true;
1921 touch.touches[0] =
1922 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
1923 EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
1924 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1925
1926 EXPECT_CALL(mock_input_handler_, EventListenerTypeForTouchStartOrMoveAt(_, _))
1927 .WillOnce(testing::Return(
1928 cc::InputHandler::TouchStartOrMoveEventListenerType::HANDLER));
1929 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
1930 .WillOnce(testing::Return());
1931
1932 touch.SetType(WebInputEvent::Type::kTouchMove);
1933 touch.touches_length = 1;
1934 touch.touch_start_or_first_touch_move = true;
1935 touch.touches[0] =
1936 CreateWebTouchPoint(WebTouchPoint::State::kStateMoved, 10, 10);
1937 EXPECT_EQ(InputHandlerProxy::DID_HANDLE_NON_BLOCKING,
1938 HandleInputEventWithLatencyInfo(input_handler_.get(), touch));
1939 VERIFY_AND_RESET_MOCKS();
1940 }
1941
1942 class UnifiedScrollingInputHandlerProxyTest : public testing::Test {
1943 public:
1944 using ElementId = cc::ElementId;
1945 using ElementIdType = cc::ElementIdType;
1946 using EventDisposition = InputHandlerProxy::EventDisposition;
1947 using EventDispositionCallback = InputHandlerProxy::EventDispositionCallback;
1948 using LatencyInfo = ui::LatencyInfo;
1949 using ScrollGranularity = ui::ScrollGranularity;
1950 using ScrollState = cc::ScrollState;
1951 using ReturnedDisposition = base::Optional<EventDisposition>;
1952
UnifiedScrollingInputHandlerProxyTest()1953 UnifiedScrollingInputHandlerProxyTest()
1954 : input_handler_proxy_(mock_input_handler_, &mock_client_) {}
1955
SetUp()1956 void SetUp() override {
1957 scoped_feature_list_.InitAndEnableFeature(features::kScrollUnification);
1958 }
1959
ScrollBegin()1960 std::unique_ptr<WebCoalescedInputEvent> ScrollBegin() {
1961 auto gsb = std::make_unique<WebGestureEvent>(
1962 WebInputEvent::Type::kGestureScrollBegin, WebInputEvent::kNoModifiers,
1963 TimeForInputEvents(), WebGestureDevice::kTouchpad);
1964 gsb->data.scroll_begin.scrollable_area_element_id = 0;
1965 gsb->data.scroll_begin.main_thread_hit_tested = false;
1966 gsb->data.scroll_begin.delta_x_hint = 0;
1967 gsb->data.scroll_begin.delta_y_hint = 10;
1968 gsb->data.scroll_begin.pointer_count = 0;
1969
1970 LatencyInfo unused;
1971 return std::make_unique<WebCoalescedInputEvent>(std::move(gsb), unused);
1972 }
1973
ScrollUpdate()1974 std::unique_ptr<WebCoalescedInputEvent> ScrollUpdate() {
1975 auto gsu = std::make_unique<WebGestureEvent>(
1976 WebInputEvent::Type::kGestureScrollUpdate, WebInputEvent::kNoModifiers,
1977 TimeForInputEvents(), WebGestureDevice::kTouchpad);
1978 gsu->data.scroll_update.delta_x = 0;
1979 gsu->data.scroll_update.delta_y = 10;
1980
1981 LatencyInfo unused;
1982 return std::make_unique<WebCoalescedInputEvent>(std::move(gsu), unused);
1983 }
1984
ScrollEnd()1985 std::unique_ptr<WebCoalescedInputEvent> ScrollEnd() {
1986 auto gse = std::make_unique<WebGestureEvent>(
1987 WebInputEvent::Type::kGestureScrollEnd, WebInputEvent::kNoModifiers,
1988 TimeForInputEvents(), WebGestureDevice::kTouchpad);
1989
1990 LatencyInfo unused;
1991 return std::make_unique<WebCoalescedInputEvent>(std::move(gse), unused);
1992 }
1993
DispatchEvent(std::unique_ptr<blink::WebCoalescedInputEvent> event,ReturnedDisposition * out_disposition=nullptr)1994 void DispatchEvent(std::unique_ptr<blink::WebCoalescedInputEvent> event,
1995 ReturnedDisposition* out_disposition = nullptr) {
1996 input_handler_proxy_.HandleInputEventWithLatencyInfo(
1997 std::move(event), nullptr, BindEventHandledCallback(out_disposition));
1998 }
1999
ContinueScrollBeginAfterMainThreadHitTest(std::unique_ptr<WebCoalescedInputEvent> event,cc::ElementIdType hit_test_result,ReturnedDisposition * out_disposition=nullptr)2000 void ContinueScrollBeginAfterMainThreadHitTest(
2001 std::unique_ptr<WebCoalescedInputEvent> event,
2002 cc::ElementIdType hit_test_result,
2003 ReturnedDisposition* out_disposition = nullptr) {
2004 input_handler_proxy_.ContinueScrollBeginAfterMainThreadHitTest(
2005 std::move(event), nullptr, BindEventHandledCallback(out_disposition),
2006 hit_test_result);
2007 }
2008
MainThreadHitTestInProgress() const2009 bool MainThreadHitTestInProgress() const {
2010 return input_handler_proxy_.hit_testing_scroll_begin_on_main_thread_;
2011 }
2012
BeginFrame()2013 void BeginFrame() {
2014 constexpr base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
2015 base::TimeTicks frame_time =
2016 TimeForInputEvents() +
2017 (next_begin_frame_number_ - viz::BeginFrameArgs::kStartingFrameNumber) *
2018 interval;
2019 input_handler_proxy_.DeliverInputForBeginFrame(viz::BeginFrameArgs::Create(
2020 BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, frame_time,
2021 frame_time + interval, interval, viz::BeginFrameArgs::NORMAL));
2022 }
2023
DidScrollResult() const2024 cc::InputHandlerScrollResult DidScrollResult() const {
2025 cc::InputHandlerScrollResult result;
2026 result.did_scroll = true;
2027 return result;
2028 }
2029
2030 protected:
2031 NiceMock<MockInputHandler> mock_input_handler_;
2032 NiceMock<MockInputHandlerProxyClient> mock_client_;
2033
2034 private:
EventHandledCallback(ReturnedDisposition * out_disposition,EventDisposition event_disposition,std::unique_ptr<WebCoalescedInputEvent> input_event,std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,const WebInputEventAttribution & attribution,std::unique_ptr<cc::EventMetrics> metrics)2035 void EventHandledCallback(
2036 ReturnedDisposition* out_disposition,
2037 EventDisposition event_disposition,
2038 std::unique_ptr<WebCoalescedInputEvent> input_event,
2039 std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,
2040 const WebInputEventAttribution& attribution,
2041 std::unique_ptr<cc::EventMetrics> metrics) {
2042 if (out_disposition)
2043 *out_disposition = event_disposition;
2044 }
2045
BindEventHandledCallback(ReturnedDisposition * out_disposition=nullptr)2046 EventDispositionCallback BindEventHandledCallback(
2047 ReturnedDisposition* out_disposition = nullptr) {
2048 return base::BindOnce(
2049 &UnifiedScrollingInputHandlerProxyTest::EventHandledCallback,
2050 weak_ptr_factory_.GetWeakPtr(), out_disposition);
2051 }
2052
TimeForInputEvents() const2053 base::TimeTicks TimeForInputEvents() const {
2054 return WebInputEvent::GetStaticTimeStampForTests();
2055 }
2056
2057 InputHandlerProxy input_handler_proxy_;
2058 base::test::ScopedFeatureList scoped_feature_list_;
2059 base::SimpleTestTickClock tick_clock_;
2060 uint64_t next_begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
2061 base::WeakPtrFactory<UnifiedScrollingInputHandlerProxyTest> weak_ptr_factory_{
2062 this};
2063 };
2064
2065 // Test that when a main thread hit test is requested, the InputHandlerProxy
2066 // starts queueing incoming gesture event and the compositor queue is blocked
2067 // until the hit test is satisfied.
TEST_F(UnifiedScrollingInputHandlerProxyTest,MainThreadHitTestRequired)2068 TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestRequired) {
2069 // The hit testing state shouldn't be entered until one is actually requested.
2070 EXPECT_FALSE(MainThreadHitTestInProgress());
2071
2072 // Inject a GSB that returns RequiresMainThreadHitTest.
2073 {
2074 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2075 .WillOnce(Return(kRequiresMainThreadHitTestState));
2076
2077 ReturnedDisposition disposition;
2078 DispatchEvent(ScrollBegin(), &disposition);
2079
2080 EXPECT_TRUE(MainThreadHitTestInProgress());
2081 EXPECT_EQ(InputHandlerProxy::REQUIRES_MAIN_THREAD_HIT_TEST, *disposition);
2082
2083 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2084 }
2085
2086 ReturnedDisposition gsu1_disposition;
2087 ReturnedDisposition gsu2_disposition;
2088
2089 // Now inject a GSU. This should be queued.
2090 {
2091 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
2092
2093 DispatchEvent(ScrollUpdate(), &gsu1_disposition);
2094 EXPECT_FALSE(gsu1_disposition);
2095
2096 // Ensure the queue is blocked; a BeginFrame doesn't cause event dispatch.
2097 BeginFrame();
2098 EXPECT_FALSE(gsu1_disposition);
2099
2100 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2101 }
2102
2103 // Inject a second GSU; it should be coalesced and also queued.
2104 {
2105 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
2106
2107 DispatchEvent(ScrollUpdate(), &gsu2_disposition);
2108 EXPECT_FALSE(gsu2_disposition);
2109
2110 // Ensure the queue is blocked.
2111 BeginFrame();
2112 EXPECT_FALSE(gsu2_disposition);
2113
2114 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2115 }
2116
2117 EXPECT_TRUE(MainThreadHitTestInProgress());
2118
2119 // The hit test reply arrives. Ensure we call ScrollBegin and unblock the
2120 // queue.
2121 {
2122 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2123 .WillOnce(Return(kImplThreadScrollState));
2124
2125 // Additionally, the queue should be flushed by
2126 // ContinueScrollBeginAfterMainThreadHitTest so that the GSUs dispatched
2127 // earlier will now handled.
2128 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
2129 .WillOnce(Return(DidScrollResult()));
2130
2131 // Ensure we don't spurriously call ScrollEnd (because we think we're
2132 // already in a scroll from the first GSB).
2133 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(0);
2134
2135 ReturnedDisposition disposition;
2136 const ElementIdType kHitTestResult = 12345;
2137 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(), kHitTestResult,
2138 &disposition);
2139
2140 // The ScrollBegin should have been immediately re-injected and queue
2141 // flushed.
2142 EXPECT_FALSE(MainThreadHitTestInProgress());
2143 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2144 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gsu1_disposition);
2145 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gsu2_disposition);
2146
2147 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2148 }
2149
2150 // Injecting a new GSU should cause queueing and dispatching as usual.
2151 {
2152 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
2153 .WillOnce(Return(DidScrollResult()));
2154
2155 ReturnedDisposition disposition;
2156 DispatchEvent(ScrollUpdate(), &disposition);
2157 EXPECT_FALSE(disposition);
2158
2159 BeginFrame();
2160 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2161
2162 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2163 }
2164
2165 // Finish the scroll.
2166 {
2167 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(1);
2168 ReturnedDisposition disposition;
2169 DispatchEvent(ScrollEnd(), &disposition);
2170 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2171 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2172 }
2173
2174 EXPECT_FALSE(MainThreadHitTestInProgress());
2175 }
2176
2177 // Test to ensure that a main thread hit test sets the correct flags on the
2178 // re-injected GestureScrollBegin.
TEST_F(UnifiedScrollingInputHandlerProxyTest,MainThreadHitTestEvent)2179 TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestEvent) {
2180 // Inject a GSB that returns RequiresMainThreadHitTest.
2181 {
2182 // Ensure that by default we don't set a target. The
2183 // |is_main_thread_hit_tested| property should default to false.
2184 EXPECT_CALL(
2185 mock_input_handler_,
2186 ScrollBegin(
2187 AllOf(Property(&ScrollState::target_element_id, Eq(ElementId())),
2188 Property(&ScrollState::is_main_thread_hit_tested, Eq(false))),
2189 _))
2190 .WillOnce(Return(kRequiresMainThreadHitTestState));
2191 DispatchEvent(ScrollBegin());
2192 ASSERT_TRUE(MainThreadHitTestInProgress());
2193 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2194 }
2195
2196 // The hit test reply arrives. Ensure we call ScrollBegin with the ElementId
2197 // from the hit test and the main_thread
2198 {
2199 const ElementId kHitTestResult(12345);
2200
2201 EXPECT_CALL(
2202 mock_input_handler_,
2203 ScrollBegin(
2204 AllOf(Property(&ScrollState::target_element_id, Eq(kHitTestResult)),
2205 Property(&ScrollState::is_main_thread_hit_tested, Eq(true))),
2206 _))
2207 .Times(1);
2208
2209 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(),
2210 kHitTestResult.GetStableId());
2211 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2212 }
2213 }
2214
2215 // Test to ensure that a main thread hit test counts the correct number of
2216 // scrolls for metrics.
TEST_F(UnifiedScrollingInputHandlerProxyTest,MainThreadHitTestMetrics)2217 TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestMetrics) {
2218 // Inject a GSB that returns RequiresMainThreadHitTest followed by a GSU and
2219 // a GSE.
2220 {
2221 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2222 .WillOnce(Return(kRequiresMainThreadHitTestState))
2223 .WillOnce(Return(kImplThreadScrollState));
2224 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
2225 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(1);
2226
2227 // The record begin/end should be called exactly once.
2228 EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
2229 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
2230
2231 DispatchEvent(ScrollBegin());
2232 EXPECT_TRUE(MainThreadHitTestInProgress());
2233 DispatchEvent(ScrollUpdate());
2234 DispatchEvent(ScrollEnd());
2235
2236 // Hit test reply.
2237 const ElementIdType kHitTestResult = 12345;
2238 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(), kHitTestResult);
2239 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2240 }
2241
2242 // Ensure we don't record either a begin or an end if the hit test fails.
2243 // TODO(bokan): Though it looks odd, it appears that today we do record the
2244 // scrolling thread if the scroll is dropped. We should fix that but in the
2245 // mean-time we add a test for the unified path in this case.
2246 // https://crbug.com/1082601.
2247 {
2248 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2249 .WillOnce(Return(kRequiresMainThreadHitTestState));
2250 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
2251 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(0);
2252
2253 EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
2254 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
2255
2256 DispatchEvent(ScrollBegin());
2257 EXPECT_TRUE(MainThreadHitTestInProgress());
2258 DispatchEvent(ScrollUpdate());
2259 DispatchEvent(ScrollEnd());
2260
2261 // Hit test reply failed.
2262 const ElementIdType kHitTestResult = 0;
2263 ASSERT_FALSE(ElementId::IsValid(kHitTestResult));
2264
2265 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(), kHitTestResult);
2266 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2267 }
2268 }
2269
2270 // Test the case where a main thread hit test is in progress on the main thread
2271 // and a GSE and new GSB arrive.
TEST_F(UnifiedScrollingInputHandlerProxyTest,ScrollEndAndBeginsDuringMainThreadHitTest)2272 TEST_F(UnifiedScrollingInputHandlerProxyTest,
2273 ScrollEndAndBeginsDuringMainThreadHitTest) {
2274 ReturnedDisposition gsb1_disposition;
2275 ReturnedDisposition gsu1_disposition;
2276 ReturnedDisposition gse1_disposition;
2277 ReturnedDisposition gsb2_disposition;
2278 ReturnedDisposition gsu2_disposition;
2279 ReturnedDisposition gse2_disposition;
2280
2281 // Inject a GSB that returns RequiresMainThreadHitTest followed by a GSU and
2282 // GSE that get queued.
2283 {
2284 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2285 .WillOnce(Return(kRequiresMainThreadHitTestState));
2286 DispatchEvent(ScrollBegin(), &gsb1_disposition);
2287 ASSERT_TRUE(MainThreadHitTestInProgress());
2288 ASSERT_EQ(InputHandlerProxy::REQUIRES_MAIN_THREAD_HIT_TEST,
2289 *gsb1_disposition);
2290
2291 DispatchEvent(ScrollUpdate(), &gsu1_disposition);
2292 DispatchEvent(ScrollEnd(), &gse1_disposition);
2293
2294 // The queue is blocked so none of the events should be processed.
2295 BeginFrame();
2296
2297 ASSERT_FALSE(gsu1_disposition);
2298 ASSERT_FALSE(gse1_disposition);
2299 }
2300
2301 // Inject another group of GSB, GSU, GSE. They should all be queued.
2302 {
2303 DispatchEvent(ScrollBegin(), &gsb2_disposition);
2304 DispatchEvent(ScrollUpdate(), &gsu2_disposition);
2305 DispatchEvent(ScrollEnd(), &gse2_disposition);
2306
2307 // The queue is blocked so none of the events should be processed.
2308 BeginFrame();
2309
2310 EXPECT_FALSE(gsb2_disposition);
2311 EXPECT_FALSE(gsu2_disposition);
2312 EXPECT_FALSE(gse2_disposition);
2313 }
2314
2315 ASSERT_TRUE(MainThreadHitTestInProgress());
2316
2317 // The hit test reply arrives. Ensure we call ScrollBegin and unblock the
2318 // queue.
2319 {
2320 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2321 .Times(2)
2322 .WillRepeatedly(Return(kImplThreadScrollState));
2323 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
2324 .Times(2)
2325 .WillRepeatedly(Return(DidScrollResult()));
2326 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(2);
2327
2328 ReturnedDisposition disposition;
2329 const ElementIdType kHitTestResult = 12345;
2330 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(), kHitTestResult,
2331 &disposition);
2332
2333 // The ScrollBegin should have been immediately re-injected and queue
2334 // flushed.
2335 EXPECT_FALSE(MainThreadHitTestInProgress());
2336 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2337 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gsu1_disposition);
2338 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gse1_disposition);
2339
2340 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gsb2_disposition);
2341 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gsu2_disposition);
2342 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *gse2_disposition);
2343
2344 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2345 }
2346 }
2347
2348 // Test the case where a main thread hit test returns a null element_id. In
2349 // this case we should reset the state and unblock the queue.
TEST_F(UnifiedScrollingInputHandlerProxyTest,MainThreadHitTestFailed)2350 TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestFailed) {
2351 ReturnedDisposition gsu1_disposition;
2352
2353 // Inject a GSB that returns RequiresMainThreadHitTest.
2354 {
2355 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2356 .WillOnce(Return(kRequiresMainThreadHitTestState));
2357 DispatchEvent(ScrollBegin());
2358 DispatchEvent(ScrollUpdate(), &gsu1_disposition);
2359 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2360 }
2361
2362 // The hit test reply arrives with an invalid ElementId. We shouldn't call
2363 // ScrollBegin nor ScrollUpdate. Both should be dropped without reaching the
2364 // input handler.
2365 {
2366 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _)).Times(0);
2367 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
2368 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(0);
2369
2370 const ElementIdType kHitTestResult = 0;
2371 ASSERT_FALSE(ElementId::IsValid(kHitTestResult));
2372
2373 ReturnedDisposition gsb_disposition;
2374 ContinueScrollBeginAfterMainThreadHitTest(ScrollBegin(), kHitTestResult,
2375 &gsb_disposition);
2376
2377 EXPECT_EQ(InputHandlerProxy::DROP_EVENT, *gsb_disposition);
2378 EXPECT_EQ(InputHandlerProxy::DROP_EVENT, *gsu1_disposition);
2379 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2380 }
2381
2382 // Send a new GSU, ensure it's dropped without queueing since there's no
2383 // scroll in progress.
2384 {
2385 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(0);
2386
2387 ReturnedDisposition disposition;
2388 DispatchEvent(ScrollUpdate(), &disposition);
2389 EXPECT_EQ(InputHandlerProxy::DROP_EVENT, *disposition);
2390 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2391 }
2392
2393 // Ensure there's no left-over bad state by sending a new GSB+GSU which
2394 // should be handled by the input handler immediately. A following GSU should
2395 // be queued and dispatched at BeginFrame.
2396 {
2397 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2398 .WillOnce(Return(kImplThreadScrollState));
2399 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
2400 .WillOnce(Return(DidScrollResult()))
2401 .WillOnce(Return(DidScrollResult()));
2402
2403 // Note: The first GSU after a GSB is dispatched immediately without
2404 // queueing.
2405 ReturnedDisposition disposition;
2406 DispatchEvent(ScrollBegin(), &disposition);
2407 DispatchEvent(ScrollUpdate());
2408
2409 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2410 disposition = base::nullopt;
2411
2412 DispatchEvent(ScrollUpdate(), &disposition);
2413 EXPECT_FALSE(disposition);
2414
2415 BeginFrame();
2416 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, *disposition);
2417 Mock::VerifyAndClearExpectations(&mock_input_handler_);
2418 }
2419 }
2420
TEST(SynchronousInputHandlerProxyTest,StartupShutdown)2421 TEST(SynchronousInputHandlerProxyTest, StartupShutdown) {
2422 testing::StrictMock<MockInputHandler> mock_input_handler;
2423 testing::StrictMock<MockInputHandlerProxyClient> mock_client;
2424 testing::StrictMock<MockSynchronousInputHandler>
2425 mock_synchronous_input_handler;
2426 InputHandlerProxy proxy(mock_input_handler, &mock_client);
2427
2428 // When adding a SynchronousInputHandler, immediately request an
2429 // UpdateRootLayerStateForSynchronousInputHandler() call.
2430 EXPECT_CALL(mock_input_handler, RequestUpdateForSynchronousInputHandler())
2431 .Times(1);
2432 proxy.SetSynchronousInputHandler(&mock_synchronous_input_handler);
2433
2434 testing::Mock::VerifyAndClearExpectations(&mock_input_handler);
2435 testing::Mock::VerifyAndClearExpectations(&mock_client);
2436 testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler);
2437
2438 EXPECT_CALL(mock_input_handler, RequestUpdateForSynchronousInputHandler())
2439 .Times(0);
2440 proxy.SetSynchronousInputHandler(nullptr);
2441
2442 testing::Mock::VerifyAndClearExpectations(&mock_input_handler);
2443 testing::Mock::VerifyAndClearExpectations(&mock_client);
2444 testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler);
2445 }
2446
TEST(SynchronousInputHandlerProxyTest,UpdateRootLayerState)2447 TEST(SynchronousInputHandlerProxyTest, UpdateRootLayerState) {
2448 testing::NiceMock<MockInputHandler> mock_input_handler;
2449 testing::StrictMock<MockInputHandlerProxyClient> mock_client;
2450 testing::StrictMock<MockSynchronousInputHandler>
2451 mock_synchronous_input_handler;
2452 InputHandlerProxy proxy(mock_input_handler, &mock_client);
2453
2454 proxy.SetSynchronousInputHandler(&mock_synchronous_input_handler);
2455
2456 // When adding a SynchronousInputHandler, immediately request an
2457 // UpdateRootLayerStateForSynchronousInputHandler() call.
2458 EXPECT_CALL(
2459 mock_synchronous_input_handler,
2460 UpdateRootLayerState(gfx::ScrollOffset(1, 2), gfx::ScrollOffset(3, 4),
2461 gfx::SizeF(5, 6), 7, 8, 9))
2462 .Times(1);
2463 proxy.UpdateRootLayerStateForSynchronousInputHandler(
2464 gfx::ScrollOffset(1, 2), gfx::ScrollOffset(3, 4), gfx::SizeF(5, 6), 7, 8,
2465 9);
2466
2467 testing::Mock::VerifyAndClearExpectations(&mock_input_handler);
2468 testing::Mock::VerifyAndClearExpectations(&mock_client);
2469 testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler);
2470 }
2471
TEST(SynchronousInputHandlerProxyTest,SetOffset)2472 TEST(SynchronousInputHandlerProxyTest, SetOffset) {
2473 testing::NiceMock<MockInputHandler> mock_input_handler;
2474 testing::StrictMock<MockInputHandlerProxyClient> mock_client;
2475 testing::StrictMock<MockSynchronousInputHandler>
2476 mock_synchronous_input_handler;
2477 InputHandlerProxy proxy(mock_input_handler, &mock_client);
2478
2479 proxy.SetSynchronousInputHandler(&mock_synchronous_input_handler);
2480
2481 EXPECT_CALL(mock_input_handler, SetSynchronousInputHandlerRootScrollOffset(
2482 gfx::ScrollOffset(5, 6)));
2483 proxy.SynchronouslySetRootScrollOffset(gfx::ScrollOffset(5, 6));
2484
2485 testing::Mock::VerifyAndClearExpectations(&mock_input_handler);
2486 testing::Mock::VerifyAndClearExpectations(&mock_client);
2487 testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler);
2488 }
2489
TEST_F(InputHandlerProxyEventQueueTest,MouseEventOnScrollbarInitiatesGestureScroll)2490 TEST_F(InputHandlerProxyEventQueueTest,
2491 MouseEventOnScrollbarInitiatesGestureScroll) {
2492 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2493 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2494 .Times(2)
2495 .WillRepeatedly(testing::Return(cc::ElementId()));
2496
2497 // Test mousedown on the scrollbar. Expect to get GSB and GSU.
2498 cc::InputHandlerPointerResult pointer_down_result;
2499 pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
2500 pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
2501
2502 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
2503 .WillOnce(testing::Return(pointer_down_result));
2504 HandleMouseEvent(WebInputEvent::Type::kMouseDown);
2505 EXPECT_EQ(2ul, event_queue().size());
2506 EXPECT_EQ(event_queue()[0]->event().GetType(),
2507 WebInputEvent::Type::kGestureScrollBegin);
2508 EXPECT_EQ(event_queue()[1]->event().GetType(),
2509 WebInputEvent::Type::kGestureScrollUpdate);
2510 cc::InputHandlerPointerResult pointer_up_result;
2511 pointer_up_result.type = cc::PointerResultType::kScrollbarScroll;
2512 EXPECT_CALL(mock_input_handler_, MouseUp(_))
2513 .WillOnce(testing::Return(pointer_up_result));
2514 // Test mouseup on the scrollbar. Expect to get GSE.
2515 HandleMouseEvent(WebInputEvent::Type::kMouseUp);
2516 EXPECT_EQ(3ul, event_queue().size());
2517 EXPECT_EQ(event_queue()[2]->event().GetType(),
2518 WebInputEvent::Type::kGestureScrollEnd);
2519 }
2520
TEST_F(InputHandlerProxyEventQueueTest,VSyncAlignedGestureScroll)2521 TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {
2522 // Handle scroll on compositor.
2523 cc::InputHandlerScrollResult scroll_result_did_scroll_;
2524 scroll_result_did_scroll_.did_scroll = true;
2525
2526 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2527 .WillOnce(testing::Return(kImplThreadScrollState));
2528 EXPECT_CALL(
2529 mock_input_handler_,
2530 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2531 .Times(1);
2532 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2533 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2534 .Times(1)
2535 .WillOnce(testing::Return(cc::ElementId()));
2536
2537 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2538
2539 // GestureScrollBegin will be processed immediately.
2540 EXPECT_EQ(0ul, event_queue().size());
2541 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2542 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[0]);
2543
2544 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
2545
2546 // GestureScrollUpdate will be queued.
2547 EXPECT_EQ(1ul, event_queue().size());
2548 EXPECT_EQ(-20,
2549 static_cast<const WebGestureEvent&>(event_queue().front()->event())
2550 .data.scroll_update.delta_y);
2551 EXPECT_EQ(1ul, event_queue().front()->coalesced_count());
2552 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2553
2554 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -40);
2555
2556 // GestureScrollUpdate will be coalesced.
2557 EXPECT_EQ(1ul, event_queue().size());
2558 EXPECT_EQ(-60,
2559 static_cast<const WebGestureEvent&>(event_queue().front()->event())
2560 .data.scroll_update.delta_y);
2561 EXPECT_EQ(2ul, event_queue().front()->coalesced_count());
2562 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2563
2564 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(0);
2565 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2566
2567 // GestureScrollEnd will be queued.
2568 EXPECT_EQ(2ul, event_queue().size());
2569 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2570 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2571
2572 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2573 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2574 .WillOnce(testing::Return(false));
2575 }
2576 EXPECT_CALL(
2577 mock_input_handler_,
2578 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2579 _))
2580 .WillOnce(testing::Return(scroll_result_did_scroll_));
2581 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
2582 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2583 .Times(2)
2584 .WillRepeatedly(testing::Return(cc::ElementId()));
2585
2586 // Dispatch all queued events.
2587 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
2588 DeliverInputForBeginFrame();
2589 EXPECT_EQ(0ul, event_queue().size());
2590 // Should run callbacks for every original events.
2591 EXPECT_EQ(4ul, event_disposition_recorder_.size());
2592 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[1]);
2593 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[2]);
2594 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[3]);
2595 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2596 }
2597
2598 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
2599 defined(MEMORY_SANITIZER)
2600 // Flaky under sanitizers and in other "slow" bot configs:
2601 // https://crbug.com/1029250
2602 #define MAYBE_VSyncAlignedGestureScrollPinchScroll \
2603 DISABLED_VSyncAlignedGestureScrollPinchScroll
2604 #else
2605 #define MAYBE_VSyncAlignedGestureScrollPinchScroll \
2606 VSyncAlignedGestureScrollPinchScroll
2607 #endif
2608
TEST_F(InputHandlerProxyEventQueueTest,MAYBE_VSyncAlignedGestureScrollPinchScroll)2609 TEST_F(InputHandlerProxyEventQueueTest,
2610 MAYBE_VSyncAlignedGestureScrollPinchScroll) {
2611 // Handle scroll on compositor.
2612 cc::InputHandlerScrollResult scroll_result_did_scroll_;
2613 scroll_result_did_scroll_.did_scroll = true;
2614
2615 // Start scroll in the first frame.
2616 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2617 .WillOnce(testing::Return(kImplThreadScrollState));
2618 EXPECT_CALL(
2619 mock_input_handler_,
2620 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2621 .Times(1);
2622 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2623 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2624 .WillOnce(testing::Return(false));
2625 }
2626 EXPECT_CALL(
2627 mock_input_handler_,
2628 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2629 _))
2630 .WillOnce(testing::Return(scroll_result_did_scroll_));
2631 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2632 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2633 .Times(2)
2634 .WillRepeatedly(testing::Return(cc::ElementId()));
2635
2636 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2637 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
2638
2639 EXPECT_EQ(1ul, event_queue().size());
2640 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2641
2642 DeliverInputForBeginFrame();
2643
2644 EXPECT_EQ(0ul, event_queue().size());
2645 EXPECT_EQ(2ul, event_disposition_recorder_.size());
2646 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2647
2648 // Continue scroll in the second frame, pinch, then start another scroll.
2649 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2650 .WillOnce(testing::Return(kImplThreadScrollState));
2651 EXPECT_CALL(
2652 mock_input_handler_,
2653 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2654 .Times(1);
2655 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2656 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2657 .WillRepeatedly(testing::Return(false));
2658 }
2659 EXPECT_CALL(
2660 mock_input_handler_,
2661 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2662 _))
2663 .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
2664 EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(2);
2665 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2666 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2667 .Times(8)
2668 .WillRepeatedly(testing::Return(cc::ElementId()));
2669 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
2670 // Two |GesturePinchUpdate| will be coalesced.
2671 EXPECT_CALL(mock_input_handler_,
2672 PinchGestureUpdate(0.7f, gfx::Point(13, 17)));
2673 EXPECT_CALL(mock_input_handler_, PinchGestureEnd(gfx::Point(), false));
2674 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(2);
2675
2676 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
2677 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2678 HandleGestureEvent(WebInputEvent::Type::kGesturePinchBegin);
2679 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 1.4f, 13, 17);
2680 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 0.5f, 13, 17);
2681 HandleGestureEvent(WebInputEvent::Type::kGesturePinchEnd);
2682 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2683 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -70);
2684 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -5);
2685 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2686
2687 EXPECT_EQ(8ul, event_queue().size());
2688 EXPECT_EQ(2ul, event_disposition_recorder_.size());
2689
2690 DeliverInputForBeginFrame();
2691
2692 EXPECT_EQ(0ul, event_queue().size());
2693 EXPECT_EQ(12ul, event_disposition_recorder_.size());
2694 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2695 }
2696
TEST_F(InputHandlerProxyEventQueueTest,VSyncAlignedQueueingTime)2697 TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) {
2698 base::SimpleTestTickClock tick_clock;
2699 tick_clock.SetNowTicks(base::TimeTicks::Now());
2700 SetInputHandlerProxyTickClockForTesting(&tick_clock);
2701
2702 // Handle scroll on compositor.
2703 cc::InputHandlerScrollResult scroll_result_did_scroll_;
2704 scroll_result_did_scroll_.did_scroll = true;
2705
2706 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2707 .WillOnce(testing::Return(kImplThreadScrollState));
2708 EXPECT_CALL(
2709 mock_input_handler_,
2710 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2711 .Times(1);
2712 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2713 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2714 .Times(3)
2715 .WillRepeatedly(testing::Return(cc::ElementId()));
2716 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2717 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2718 .WillOnce(testing::Return(false));
2719 }
2720 EXPECT_CALL(
2721 mock_input_handler_,
2722 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2723 _))
2724 .WillOnce(testing::Return(scroll_result_did_scroll_));
2725 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
2726 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
2727
2728 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2729 tick_clock.Advance(base::TimeDelta::FromMicroseconds(10));
2730 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
2731 tick_clock.Advance(base::TimeDelta::FromMicroseconds(40));
2732 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -40);
2733 tick_clock.Advance(base::TimeDelta::FromMicroseconds(20));
2734 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
2735 tick_clock.Advance(base::TimeDelta::FromMicroseconds(10));
2736 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2737
2738 // Dispatch all queued events.
2739 tick_clock.Advance(base::TimeDelta::FromMicroseconds(70));
2740 DeliverInputForBeginFrame();
2741 EXPECT_EQ(0ul, event_queue().size());
2742 EXPECT_EQ(5ul, event_disposition_recorder_.size());
2743 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2744 }
2745
TEST_F(InputHandlerProxyEventQueueTest,VSyncAlignedCoalesceScrollAndPinch)2746 TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {
2747 // Start scroll in the first frame.
2748 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2749 .WillOnce(testing::Return(kImplThreadScrollState));
2750 EXPECT_CALL(
2751 mock_input_handler_,
2752 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2753 .Times(1);
2754 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
2755 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2756 .Times(1)
2757 .WillOnce(testing::Return(cc::ElementId()));
2758
2759 // GSUs and GPUs in one sequence should be coalesced into 1 GSU and 1 GPU.
2760 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2761 HandleGestureEvent(WebInputEvent::Type::kGesturePinchBegin);
2762 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
2763 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -7);
2764 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 2.0f, 13, 10);
2765 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
2766 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -6);
2767 HandleGestureEvent(WebInputEvent::Type::kGesturePinchEnd);
2768 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2769 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2770 HandleGestureEvent(WebInputEvent::Type::kGesturePinchBegin);
2771 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 0.2f, 2, 20);
2772 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 10.0f, 1, 10);
2773 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
2774 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 0.25f, 3, 30);
2775 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
2776 HandleGestureEvent(WebInputEvent::Type::kGesturePinchEnd);
2777 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2778
2779 // Only the first GSB was dispatched.
2780 EXPECT_EQ(11ul, event_queue().size());
2781 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2782
2783 EXPECT_EQ(WebInputEvent::Type::kGesturePinchBegin,
2784 event_queue()[0]->event().GetType());
2785 EXPECT_EQ(WebInputEvent::Type::kGestureScrollUpdate,
2786 event_queue()[1]->event().GetType());
2787 EXPECT_EQ(-35, static_cast<const WebGestureEvent&>(event_queue()[1]->event())
2788 .data.scroll_update.delta_y);
2789 EXPECT_EQ(WebInputEvent::Type::kGesturePinchUpdate,
2790 event_queue()[2]->event().GetType());
2791 EXPECT_EQ(2.0f, static_cast<const WebGestureEvent&>(event_queue()[2]->event())
2792 .data.pinch_update.scale);
2793 EXPECT_EQ(WebInputEvent::Type::kGesturePinchEnd,
2794 event_queue()[3]->event().GetType());
2795 EXPECT_EQ(WebInputEvent::Type::kGestureScrollEnd,
2796 event_queue()[4]->event().GetType());
2797 EXPECT_EQ(WebInputEvent::Type::kGestureScrollBegin,
2798 event_queue()[5]->event().GetType());
2799 EXPECT_EQ(WebInputEvent::Type::kGesturePinchBegin,
2800 event_queue()[6]->event().GetType());
2801 EXPECT_EQ(WebInputEvent::Type::kGestureScrollUpdate,
2802 event_queue()[7]->event().GetType());
2803 EXPECT_EQ(-85, static_cast<const WebGestureEvent&>(event_queue()[7]->event())
2804 .data.scroll_update.delta_y);
2805 EXPECT_EQ(WebInputEvent::Type::kGesturePinchUpdate,
2806 event_queue()[8]->event().GetType());
2807 EXPECT_EQ(0.5f, static_cast<const WebGestureEvent&>(event_queue()[8]->event())
2808 .data.pinch_update.scale);
2809 EXPECT_EQ(WebInputEvent::Type::kGesturePinchEnd,
2810 event_queue()[9]->event().GetType());
2811 EXPECT_EQ(WebInputEvent::Type::kGestureScrollEnd,
2812 event_queue()[10]->event().GetType());
2813 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2814 }
2815
TEST_F(InputHandlerProxyEventQueueTest,VSyncAlignedCoalesceTouchpadPinch)2816 TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceTouchpadPinch) {
2817 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
2818 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
2819 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2820 .Times(1)
2821 .WillOnce(testing::Return(cc::ElementId()));
2822
2823 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGesturePinchBegin,
2824 WebGestureDevice::kTouchpad);
2825 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGesturePinchUpdate,
2826 WebGestureDevice::kTouchpad, 1.1f, 10, 20);
2827 // The second update should coalesce with the first.
2828 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGesturePinchUpdate,
2829 WebGestureDevice::kTouchpad, 1.1f, 10, 20);
2830 // The third update has a different anchor so it should not be coalesced.
2831 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGesturePinchUpdate,
2832 WebGestureDevice::kTouchpad, 1.1f, 11, 21);
2833 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGesturePinchEnd,
2834 WebGestureDevice::kTouchpad);
2835
2836 // Only the PinchBegin was dispatched.
2837 EXPECT_EQ(3ul, event_queue().size());
2838 EXPECT_EQ(1ul, event_disposition_recorder_.size());
2839
2840 ASSERT_EQ(WebInputEvent::Type::kGesturePinchUpdate,
2841 event_queue()[0]->event().GetType());
2842 EXPECT_FLOAT_EQ(1.21f,
2843 static_cast<const WebGestureEvent&>(event_queue()[0]->event())
2844 .data.pinch_update.scale);
2845 EXPECT_EQ(WebInputEvent::Type::kGesturePinchUpdate,
2846 event_queue()[1]->event().GetType());
2847 EXPECT_EQ(WebInputEvent::Type::kGesturePinchEnd,
2848 event_queue()[2]->event().GetType());
2849 }
2850
TEST_F(InputHandlerProxyEventQueueTest,OriginalEventsTracing)2851 TEST_F(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {
2852 // Handle scroll on compositor.
2853 cc::InputHandlerScrollResult scroll_result_did_scroll_;
2854 scroll_result_did_scroll_.did_scroll = true;
2855
2856 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2857 .WillRepeatedly(testing::Return(kImplThreadScrollState));
2858 EXPECT_CALL(
2859 mock_input_handler_,
2860 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2861 .Times(2);
2862 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
2863 .Times(::testing::AtLeast(1));
2864 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2865 .Times(9)
2866 .WillRepeatedly(testing::Return(cc::ElementId()));
2867 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2868 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2869 .WillRepeatedly(testing::Return(false));
2870 }
2871 EXPECT_CALL(
2872 mock_input_handler_,
2873 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2874 _))
2875 .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
2876 EXPECT_CALL(mock_input_handler_, ScrollEnd(true))
2877 .Times(::testing::AtLeast(1));
2878 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(2);
2879
2880 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
2881 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(_, _));
2882 EXPECT_CALL(mock_input_handler_, PinchGestureEnd(_, _));
2883
2884 trace_analyzer::Start("*");
2885 // Simulate scroll.
2886 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2887 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
2888 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -40);
2889 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
2890 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2891
2892 // Simulate scroll and pinch.
2893 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
2894 HandleGestureEvent(WebInputEvent::Type::kGesturePinchBegin);
2895 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 10.0f, 1, 10);
2896 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
2897 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 2.0f, 1, 10);
2898 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
2899 HandleGestureEvent(WebInputEvent::Type::kGesturePinchEnd);
2900 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
2901
2902 // Dispatch all events.
2903 DeliverInputForBeginFrame();
2904
2905 // Retrieve tracing data.
2906 auto analyzer = trace_analyzer::Stop();
2907 trace_analyzer::TraceEventVector begin_events;
2908 trace_analyzer::Query begin_query = trace_analyzer::Query::EventPhaseIs(
2909 TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN);
2910 analyzer->FindEvents(begin_query, &begin_events);
2911
2912 trace_analyzer::TraceEventVector end_events;
2913 trace_analyzer::Query end_query =
2914 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END);
2915 analyzer->FindEvents(end_query, &end_events);
2916
2917 EXPECT_EQ(7ul, begin_events.size());
2918 EXPECT_EQ(7ul, end_events.size());
2919 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGestureScrollUpdate),
2920 end_events[0]->GetKnownArgAsInt("type"));
2921 EXPECT_EQ(3, end_events[0]->GetKnownArgAsInt("coalesced_count"));
2922 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGestureScrollEnd),
2923 end_events[1]->GetKnownArgAsInt("type"));
2924
2925 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGestureScrollBegin),
2926 end_events[2]->GetKnownArgAsInt("type"));
2927 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGesturePinchBegin),
2928 end_events[3]->GetKnownArgAsInt("type"));
2929 // Original scroll and pinch updates will be stored in the coalesced
2930 // PinchUpdate of the <ScrollUpdate, PinchUpdate> pair.
2931 // The ScrollUpdate of the pair doesn't carry original events and won't be
2932 // traced.
2933 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGesturePinchUpdate),
2934 end_events[4]->GetKnownArgAsInt("type"));
2935 EXPECT_EQ(4, end_events[4]->GetKnownArgAsInt("coalesced_count"));
2936 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGesturePinchEnd),
2937 end_events[5]->GetKnownArgAsInt("type"));
2938 EXPECT_EQ(static_cast<int>(WebInputEvent::Type::kGestureScrollEnd),
2939 end_events[6]->GetKnownArgAsInt("type"));
2940 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
2941 }
2942
TEST_F(InputHandlerProxyEventQueueTest,TouchpadGestureScrollEndFlushQueue)2943 TEST_F(InputHandlerProxyEventQueueTest, TouchpadGestureScrollEndFlushQueue) {
2944 // Handle scroll on compositor.
2945 cc::InputHandlerScrollResult scroll_result_did_scroll_;
2946 scroll_result_did_scroll_.did_scroll = true;
2947
2948 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
2949 .WillRepeatedly(testing::Return(kImplThreadScrollState));
2950 EXPECT_CALL(
2951 mock_input_handler_,
2952 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
2953 .Times(2);
2954 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
2955 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
2956 .WillRepeatedly(testing::Return(false));
2957 }
2958 EXPECT_CALL(
2959 mock_input_handler_,
2960 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
2961 _))
2962 .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
2963 EXPECT_CALL(mock_input_handler_, ScrollEnd(true))
2964 .Times(::testing::AtLeast(1));
2965 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2966 .Times(2)
2967 .WillRepeatedly(testing::Return(cc::ElementId()));
2968
2969 // Simulate scroll.
2970 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollBegin,
2971 WebGestureDevice::kTouchpad);
2972 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollUpdate,
2973 WebGestureDevice::kTouchpad, -20);
2974
2975 // Both GSB and the first GSU will be dispatched immediately since the first
2976 // GSU has blocking wheel event source.
2977 EXPECT_EQ(0ul, event_queue().size());
2978 EXPECT_EQ(2ul, event_disposition_recorder_.size());
2979
2980 // The rest of the GSU events will get queued since they have non-blocking
2981 // wheel event source.
2982 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput())
2983 .Times(::testing::AtLeast(1));
2984 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
2985 .Times(4)
2986 .WillRepeatedly(testing::Return(cc::ElementId()));
2987 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollUpdate,
2988 WebGestureDevice::kTouchpad, -20);
2989 EXPECT_EQ(1ul, event_queue().size());
2990 EXPECT_EQ(2ul, event_disposition_recorder_.size());
2991
2992 // Touchpad GSE will flush the queue.
2993 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
2994 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollEnd,
2995 WebGestureDevice::kTouchpad);
2996
2997 EXPECT_EQ(0ul, event_queue().size());
2998 // GSB, GSU(with blocking wheel source), GSU(with non-blocking wheel
2999 // source), and GSE are the sent events.
3000 EXPECT_EQ(4ul, event_disposition_recorder_.size());
3001
3002 EXPECT_FALSE(
3003 input_handler_proxy_.gesture_scroll_on_impl_thread_for_testing());
3004
3005 // Starting a new scroll sequence should have the same behavior (namely that
3006 // the first scroll update is not queued but immediately dispatched).
3007 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollBegin,
3008 WebGestureDevice::kTouchpad);
3009 HandleGestureEventWithSourceDevice(WebInputEvent::Type::kGestureScrollUpdate,
3010 WebGestureDevice::kTouchpad, -20);
3011
3012 // Both GSB and the first GSU must be dispatched immediately since the first
3013 // GSU has blocking wheel event source.
3014 EXPECT_EQ(0ul, event_queue().size());
3015 EXPECT_EQ(6ul, event_disposition_recorder_.size());
3016 }
3017
TEST_F(InputHandlerProxyEventQueueTest,CoalescedLatencyInfo)3018 TEST_F(InputHandlerProxyEventQueueTest, CoalescedLatencyInfo) {
3019 // Handle scroll on compositor.
3020 cc::InputHandlerScrollResult scroll_result_did_scroll_;
3021 scroll_result_did_scroll_.did_scroll = true;
3022
3023 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3024 .WillOnce(testing::Return(kImplThreadScrollState));
3025 EXPECT_CALL(
3026 mock_input_handler_,
3027 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3028 .Times(1);
3029 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
3030 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
3031 .Times(3)
3032 .WillRepeatedly(testing::Return(cc::ElementId()));
3033 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
3034 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
3035 .WillOnce(testing::Return(false));
3036 }
3037 EXPECT_CALL(
3038 mock_input_handler_,
3039 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
3040 _))
3041 .WillOnce(testing::Return(scroll_result_did_scroll_));
3042 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3043 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3044
3045 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
3046 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
3047 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -40);
3048 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
3049 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
3050 DeliverInputForBeginFrame();
3051
3052 EXPECT_EQ(0ul, event_queue().size());
3053 // Should run callbacks for every original events.
3054 EXPECT_EQ(5ul, event_disposition_recorder_.size());
3055 EXPECT_EQ(5ul, latency_info_recorder_.size());
3056 EXPECT_EQ(false, latency_info_recorder_[1].coalesced());
3057 // Coalesced events should have latency set to coalesced.
3058 EXPECT_EQ(true, latency_info_recorder_[2].coalesced());
3059 EXPECT_EQ(true, latency_info_recorder_[3].coalesced());
3060 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3061 }
3062
TEST_F(InputHandlerProxyEventQueueTest,CoalescedEventSwitchToMainThread)3063 TEST_F(InputHandlerProxyEventQueueTest, CoalescedEventSwitchToMainThread) {
3064 cc::InputHandlerScrollResult scroll_result_did_scroll_;
3065 cc::InputHandlerScrollResult scroll_result_did_not_scroll_;
3066 scroll_result_did_scroll_.did_scroll = true;
3067 scroll_result_did_not_scroll_.did_scroll = false;
3068
3069 // scroll begin on main thread
3070 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3071 .WillOnce(testing::Return(kMainThreadScrollState));
3072 EXPECT_CALL(
3073 mock_input_handler_,
3074 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3075 .Times(1);
3076 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(2);
3077 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
3078 .Times(8)
3079 .WillRepeatedly(testing::Return(cc::ElementId()));
3080 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
3081 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
3082 .WillOnce(testing::Return(false));
3083 }
3084 EXPECT_CALL(
3085 mock_input_handler_,
3086 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
3087 _))
3088 .WillOnce(testing::Return(scroll_result_did_not_scroll_));
3089
3090 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
3091 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
3092 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
3093 DeliverInputForBeginFrame();
3094 EXPECT_EQ(3ul, event_disposition_recorder_.size());
3095 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
3096 event_disposition_recorder_.back());
3097 // GSU should not be coalesced
3098 EXPECT_EQ(false, latency_info_recorder_[1].coalesced());
3099 EXPECT_EQ(false, latency_info_recorder_[2].coalesced());
3100
3101 // pinch start, handle scroll and pinch on compositor.
3102 EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
3103 EXPECT_CALL(mock_input_handler_, PinchGestureUpdate(_, _));
3104 EXPECT_CALL(mock_input_handler_, PinchGestureEnd(_, _));
3105
3106 HandleGestureEvent(WebInputEvent::Type::kGesturePinchBegin);
3107 HandleGestureEvent(WebInputEvent::Type::kGesturePinchUpdate, 10.0f, 1, 10);
3108 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
3109 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
3110 EXPECT_EQ(2ul, event_queue().size());
3111 DeliverInputForBeginFrame();
3112
3113 EXPECT_EQ(7ul, event_disposition_recorder_.size());
3114 EXPECT_EQ(false, latency_info_recorder_[4].coalesced());
3115 // Coalesced events should have latency set to coalesced.
3116 EXPECT_EQ(true, latency_info_recorder_[5].coalesced());
3117 EXPECT_EQ(true, latency_info_recorder_[6].coalesced());
3118 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_.back());
3119
3120 // Pinch end, handle scroll on main thread.
3121 HandleGestureEvent(WebInputEvent::Type::kGesturePinchEnd);
3122 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -40);
3123 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -30);
3124 DeliverInputForBeginFrame();
3125
3126 EXPECT_EQ(0ul, event_queue().size());
3127 // Should run callbacks for every original events.
3128 EXPECT_EQ(10ul, event_disposition_recorder_.size());
3129 EXPECT_EQ(10ul, latency_info_recorder_.size());
3130 // Latency should not be set to coalesced when send to main thread
3131 EXPECT_EQ(false, latency_info_recorder_[8].coalesced());
3132 EXPECT_EQ(false, latency_info_recorder_[9].coalesced());
3133 EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
3134 event_disposition_recorder_.back());
3135 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3136 }
3137
TEST_F(InputHandlerProxyEventQueueTest,ScrollPredictorTest)3138 TEST_F(InputHandlerProxyEventQueueTest, ScrollPredictorTest) {
3139 base::SimpleTestTickClock tick_clock;
3140 tick_clock.SetNowTicks(base::TimeTicks());
3141 SetInputHandlerProxyTickClockForTesting(&tick_clock);
3142
3143 cc::InputHandlerScrollResult scroll_result_did_scroll_;
3144 scroll_result_did_scroll_.did_scroll = true;
3145 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3146 .WillOnce(testing::Return(kImplThreadScrollState));
3147 EXPECT_CALL(
3148 mock_input_handler_,
3149 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3150 .Times(1);
3151 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(2);
3152 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
3153 .Times(2)
3154 .WillRepeatedly(testing::Return(cc::ElementId()));
3155 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
3156 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
3157 .WillOnce(testing::Return(false));
3158 }
3159 EXPECT_CALL(
3160 mock_input_handler_,
3161 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
3162 _))
3163 .WillOnce(testing::Return(scroll_result_did_scroll_));
3164
3165 // No prediction when start with a GSB
3166 tick_clock.Advance(base::TimeDelta::FromMilliseconds(8));
3167 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
3168 DeliverInputForBeginFrame();
3169 EXPECT_FALSE(GestureScrollEventPredictionAvailable());
3170
3171 // Test predictor returns last GSU delta.
3172 tick_clock.Advance(base::TimeDelta::FromMilliseconds(8));
3173 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
3174 tick_clock.Advance(base::TimeDelta::FromMilliseconds(8));
3175 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -15);
3176 DeliverInputForBeginFrame();
3177 auto result = GestureScrollEventPredictionAvailable();
3178 EXPECT_TRUE(result);
3179 EXPECT_NE(0, result->pos.y());
3180 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
3181
3182 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3183
3184 // Predictor has been reset after a new GSB.
3185 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
3186 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
3187 .Times(2)
3188 .WillRepeatedly(testing::Return(cc::ElementId()));
3189 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3190 .WillOnce(testing::Return(kImplThreadScrollState));
3191 EXPECT_CALL(mock_input_handler_, ScrollEnd(_)).Times(1);
3192 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3193 EXPECT_CALL(
3194 mock_input_handler_,
3195 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3196 .Times(1);
3197 tick_clock.Advance(base::TimeDelta::FromMilliseconds(8));
3198 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
3199 DeliverInputForBeginFrame();
3200 EXPECT_FALSE(GestureScrollEventPredictionAvailable());
3201 HandleGestureEvent(WebInputEvent::Type::kGestureScrollEnd);
3202
3203 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3204 }
3205
3206 // Test deliver input w/o prediction enabled.
TEST_F(InputHandlerProxyEventQueueTest,DeliverInputWithHighLatencyMode)3207 TEST_F(InputHandlerProxyEventQueueTest, DeliverInputWithHighLatencyMode) {
3208 SetScrollPredictionEnabled(false);
3209
3210 cc::InputHandlerScrollResult scroll_result_did_scroll_;
3211 scroll_result_did_scroll_.did_scroll = true;
3212 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3213 .WillOnce(testing::Return(kImplThreadScrollState));
3214 EXPECT_CALL(
3215 mock_input_handler_,
3216 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3217 .Times(1);
3218 EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(2);
3219 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_))
3220 .Times(3)
3221 .WillRepeatedly(testing::Return(cc::ElementId()));
3222 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
3223 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
3224 .WillRepeatedly(testing::Return(false));
3225 }
3226 EXPECT_CALL(
3227 mock_input_handler_,
3228 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
3229 _))
3230 .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
3231
3232 HandleGestureEvent(WebInputEvent::Type::kGestureScrollBegin);
3233 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
3234 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
3235 DeliverInputForBeginFrame();
3236 // 3 queued event be delivered.
3237 EXPECT_EQ(3ul, event_disposition_recorder_.size());
3238 EXPECT_EQ(0ul, event_queue().size());
3239 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_.back());
3240
3241 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -20);
3242 HandleGestureEvent(WebInputEvent::Type::kGestureScrollUpdate, -10);
3243 DeliverInputForHighLatencyMode();
3244 // 2 queued event be delivered.
3245 EXPECT_EQ(5ul, event_disposition_recorder_.size());
3246 EXPECT_EQ(0ul, event_queue().size());
3247 EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_.back());
3248
3249 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3250 }
3251
TEST_F(InputHandlerProxyEventQueueTest,KeyEventAttribution)3252 TEST_F(InputHandlerProxyEventQueueTest, KeyEventAttribution) {
3253 WebKeyboardEvent key(WebInputEvent::Type::kKeyDown,
3254 WebInputEvent::kNoModifiers,
3255 WebInputEvent::GetStaticTimeStampForTests());
3256
3257 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(_)).Times(0);
3258
3259 WebInputEventAttribution attribution =
3260 input_handler_proxy_.PerformEventAttribution(key);
3261 EXPECT_EQ(attribution.type(), WebInputEventAttribution::kFocusedFrame);
3262 EXPECT_EQ(attribution.target_frame_id(), cc::ElementId());
3263 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3264 }
3265
TEST_F(InputHandlerProxyEventQueueTest,MouseEventAttribution)3266 TEST_F(InputHandlerProxyEventQueueTest, MouseEventAttribution) {
3267 WebMouseEvent mouse_down(WebInputEvent::Type::kMouseDown,
3268 WebInputEvent::kNoModifiers,
3269 WebInputEvent::GetStaticTimeStampForTests());
3270
3271 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(gfx::PointF(0, 0)))
3272 .Times(1)
3273 .WillOnce(testing::Return(cc::ElementId(0xDEADBEEF)));
3274
3275 WebInputEventAttribution attribution =
3276 input_handler_proxy_.PerformEventAttribution(mouse_down);
3277 EXPECT_EQ(attribution.type(), WebInputEventAttribution::kTargetedFrame);
3278 EXPECT_EQ(attribution.target_frame_id(), cc::ElementId(0xDEADBEEF));
3279 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3280 }
3281
TEST_F(InputHandlerProxyEventQueueTest,MouseWheelEventAttribution)3282 TEST_F(InputHandlerProxyEventQueueTest, MouseWheelEventAttribution) {
3283 WebMouseWheelEvent wheel(WebInputEvent::Type::kMouseWheel,
3284 WebInputEvent::kNoModifiers,
3285 WebInputEvent::GetStaticTimeStampForTests());
3286
3287 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(gfx::PointF(0, 0)))
3288 .Times(1)
3289 .WillOnce(testing::Return(cc::ElementId(0xDEADBEEF)));
3290
3291 WebInputEventAttribution attribution =
3292 input_handler_proxy_.PerformEventAttribution(wheel);
3293 EXPECT_EQ(attribution.type(), WebInputEventAttribution::kTargetedFrame);
3294 EXPECT_EQ(attribution.target_frame_id(), cc::ElementId(0xDEADBEEF));
3295 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3296 }
3297
3298 // Verify that the first point in a touch event is used for performing event
3299 // attribution.
TEST_F(InputHandlerProxyEventQueueTest,TouchEventAttribution)3300 TEST_F(InputHandlerProxyEventQueueTest, TouchEventAttribution) {
3301 WebTouchEvent touch(WebInputEvent::Type::kTouchStart,
3302 WebInputEvent::kNoModifiers,
3303 WebInputEvent::GetStaticTimeStampForTests());
3304
3305 touch.touches_length = 3;
3306 touch.touch_start_or_first_touch_move = true;
3307 touch.touches[0] =
3308 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 0, 0);
3309 touch.touches[1] =
3310 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
3311 touch.touches[2] =
3312 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, -10, 10);
3313
3314 EXPECT_CALL(mock_input_handler_, FindFrameElementIdAtPoint(gfx::PointF(0, 0)))
3315 .Times(1)
3316 .WillOnce(testing::Return(cc::ElementId(0xDEADBEEF)));
3317
3318 WebInputEventAttribution attribution =
3319 input_handler_proxy_.PerformEventAttribution(touch);
3320 EXPECT_EQ(attribution.type(), WebInputEventAttribution::kTargetedFrame);
3321 EXPECT_EQ(attribution.target_frame_id(), cc::ElementId(0xDEADBEEF));
3322 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3323 }
3324
TEST_F(InputHandlerProxyEventQueueTest,GestureEventAttribution)3325 TEST_F(InputHandlerProxyEventQueueTest, GestureEventAttribution) {
3326 WebGestureEvent gesture(WebInputEvent::Type::kGestureTap,
3327 WebInputEvent::kNoModifiers,
3328 WebInputEvent::GetStaticTimeStampForTests());
3329 gesture.SetPositionInWidget(gfx::PointF(10, 10));
3330
3331 EXPECT_CALL(mock_input_handler_,
3332 FindFrameElementIdAtPoint(gfx::PointF(10, 10)))
3333 .Times(1)
3334 .WillOnce(testing::Return(cc::ElementId(0xDEADBEEF)));
3335 WebInputEventAttribution attribution =
3336 input_handler_proxy_.PerformEventAttribution(gesture);
3337 EXPECT_EQ(attribution.type(), WebInputEventAttribution::kTargetedFrame);
3338 EXPECT_EQ(attribution.target_frame_id(), cc::ElementId(0xDEADBEEF));
3339 testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
3340 }
3341
3342 class InputHandlerProxyMainThreadScrollingReasonTest
3343 : public InputHandlerProxyTest {
3344 public:
3345 enum TestEventType {
3346 Touch,
3347 MouseWheel,
3348 };
3349
InputHandlerProxyMainThreadScrollingReasonTest()3350 InputHandlerProxyMainThreadScrollingReasonTest() : InputHandlerProxyTest() {}
3351 ~InputHandlerProxyMainThreadScrollingReasonTest() = default;
3352
SetupEvents(TestEventType type)3353 void SetupEvents(TestEventType type) {
3354 touch_start_ = WebTouchEvent(WebInputEvent::Type::kTouchStart,
3355 WebInputEvent::kNoModifiers,
3356 WebInputEvent::GetStaticTimeStampForTests());
3357 touch_end_ = WebTouchEvent(WebInputEvent::Type::kTouchEnd,
3358 WebInputEvent::kNoModifiers,
3359 WebInputEvent::GetStaticTimeStampForTests());
3360 wheel_event_ = WebMouseWheelEvent(
3361 WebInputEvent::Type::kMouseWheel, WebInputEvent::kControlKey,
3362 WebInputEvent::GetStaticTimeStampForTests());
3363 gesture_scroll_begin_ = WebGestureEvent(
3364 WebInputEvent::Type::kGestureScrollBegin, WebInputEvent::kNoModifiers,
3365 WebInputEvent::GetStaticTimeStampForTests(),
3366 type == TestEventType::MouseWheel ? WebGestureDevice::kTouchpad
3367 : WebGestureDevice::kTouchscreen);
3368 gesture_scroll_end_ = WebGestureEvent(
3369 WebInputEvent::Type::kGestureScrollEnd, WebInputEvent::kNoModifiers,
3370 WebInputEvent::GetStaticTimeStampForTests(),
3371 type == TestEventType::MouseWheel ? WebGestureDevice::kTouchpad
3372 : WebGestureDevice::kTouchscreen);
3373 touch_start_.touches_length = 1;
3374 touch_start_.touch_start_or_first_touch_move = true;
3375 touch_start_.touches[0] =
3376 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
3377
3378 touch_end_.touches_length = 1;
3379 }
3380
GetBucketSample(uint32_t reason)3381 base::HistogramBase::Sample GetBucketSample(uint32_t reason) {
3382 if (reason == cc::MainThreadScrollingReason::kNotScrollingOnMain)
3383 return 0;
3384
3385 uint32_t bucket = 1;
3386 while ((reason = reason >> 1))
3387 bucket++;
3388 return bucket;
3389 }
3390
3391 protected:
3392 WebTouchEvent touch_start_;
3393 WebTouchEvent touch_end_;
3394 WebMouseWheelEvent wheel_event_;
3395 WebGestureEvent gesture_scroll_begin_;
3396 WebGestureEvent gesture_scroll_end_;
3397 };
3398
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,GestureScrollNotScrollOnMain)3399 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3400 GestureScrollNotScrollOnMain) {
3401 // Touch start with passive event listener.
3402 SetupEvents(TestEventType::Touch);
3403
3404 EXPECT_CALL(mock_input_handler_,
3405 EventListenerTypeForTouchStartOrMoveAt(
3406 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
3407 .WillOnce(testing::Return(
3408 cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
3409 EXPECT_CALL(
3410 mock_input_handler_,
3411 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
3412 .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
3413 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
3414 .WillOnce(testing::Return());
3415
3416 cc::InputHandlerPointerResult pointer_down_result;
3417 pointer_down_result.type = cc::PointerResultType::kUnhandled;
3418 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
3419 .WillOnce(testing::Return(pointer_down_result));
3420
3421 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
3422 EXPECT_EQ(expected_disposition_,
3423 HandleInputEventAndFlushEventQueue(
3424 mock_input_handler_, input_handler_.get(), touch_start_));
3425
3426 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3427 .WillOnce(testing::Return(kImplThreadScrollState));
3428 EXPECT_CALL(
3429 mock_input_handler_,
3430 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3431 .Times(1);
3432 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3433 EXPECT_EQ(
3434 expected_disposition_,
3435 HandleInputEventAndFlushEventQueue(
3436 mock_input_handler_, input_handler_.get(), gesture_scroll_begin_));
3437 EXPECT_THAT(
3438 histogram_tester().GetAllSamples(
3439 "Renderer4.MainThreadGestureScrollReason"),
3440 testing::ElementsAre(base::Bucket(
3441 GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
3442 1)));
3443
3444 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3445 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3446 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3447 EXPECT_EQ(
3448 expected_disposition_,
3449 HandleInputEventAndFlushEventQueue(
3450 mock_input_handler_, input_handler_.get(), gesture_scroll_end_));
3451 }
3452
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,GestureScrollTouchEventHandlerRegion)3453 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3454 GestureScrollTouchEventHandlerRegion) {
3455 // The touch event hits a touch event handler that is acked from the
3456 // compositor thread.
3457 SetupEvents(TestEventType::Touch);
3458
3459 EXPECT_CALL(mock_input_handler_,
3460 EventListenerTypeForTouchStartOrMoveAt(
3461 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
3462 .WillOnce(
3463 testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
3464 HANDLER_ON_SCROLLING_LAYER));
3465 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
3466 .WillOnce(testing::Return());
3467
3468 cc::InputHandlerPointerResult pointer_down_result;
3469 pointer_down_result.type = cc::PointerResultType::kUnhandled;
3470 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
3471 .WillOnce(testing::Return(pointer_down_result));
3472
3473 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
3474 EXPECT_EQ(expected_disposition_,
3475 HandleInputEventAndFlushEventQueue(
3476 mock_input_handler_, input_handler_.get(), touch_start_));
3477
3478 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3479 .WillOnce(testing::Return(kImplThreadScrollState));
3480 EXPECT_CALL(
3481 mock_input_handler_,
3482 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3483 .Times(1);
3484 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3485 EXPECT_EQ(
3486 expected_disposition_,
3487 HandleInputEventAndFlushEventQueue(
3488 mock_input_handler_, input_handler_.get(), gesture_scroll_begin_));
3489
3490 EXPECT_THAT(
3491 histogram_tester().GetAllSamples(
3492 "Renderer4.MainThreadGestureScrollReason"),
3493 testing::ElementsAre(base::Bucket(
3494 GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
3495 1)));
3496
3497 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3498 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3499 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3500 EXPECT_EQ(
3501 expected_disposition_,
3502 HandleInputEventAndFlushEventQueue(
3503 mock_input_handler_, input_handler_.get(), gesture_scroll_end_));
3504 }
3505
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,GestureScrollTouchEventHandlerRegionAndHandlingScrollFromMainThread)3506 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3507 GestureScrollTouchEventHandlerRegionAndHandlingScrollFromMainThread) {
3508 // The touch event hits a touch event handler and should block on main thread.
3509 // Since ScrollBegin doesn't allow the gesture to scroll on impl. We report
3510 // TouchEventHandler reason as well as HandlingScrollFromMainThread. Since we
3511 // do not collect HandlingScrollFromMainThread when there are other reasons
3512 // present, TouchEventHandler is the only reason being collected in the
3513 // histogram.
3514 SetupEvents(TestEventType::Touch);
3515
3516 EXPECT_CALL(mock_input_handler_,
3517 EventListenerTypeForTouchStartOrMoveAt(
3518 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
3519 .WillOnce(
3520 testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
3521 HANDLER_ON_SCROLLING_LAYER));
3522 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
3523 .WillOnce(testing::Return());
3524
3525 cc::InputHandlerPointerResult pointer_down_result;
3526 pointer_down_result.type = cc::PointerResultType::kUnhandled;
3527 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
3528 .WillOnce(testing::Return(pointer_down_result));
3529
3530 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
3531 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3532 input_handler_.get(), touch_start_));
3533
3534 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3535 .WillOnce(testing::Return(kMainThreadScrollState));
3536 EXPECT_CALL(
3537 mock_input_handler_,
3538 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3539 .Times(1);
3540 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3541 EXPECT_EQ(expected_disposition_,
3542 HandleInputEventWithLatencyInfo(input_handler_.get(),
3543 gesture_scroll_begin_));
3544
3545 EXPECT_THAT(
3546 histogram_tester().GetAllSamples(
3547 "Renderer4.MainThreadGestureScrollReason"),
3548 testing::ElementsAre(base::Bucket(
3549 GetBucketSample(
3550 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
3551 1)));
3552
3553 // Handle touch end event so that input handler proxy is out of the state of
3554 // DID_NOT_HANDLE.
3555 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3556 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3557 cc::InputHandlerPointerResult pointer_up_result;
3558 pointer_up_result.type = cc::PointerResultType::kUnhandled;
3559 EXPECT_CALL(mock_input_handler_, MouseUp(_))
3560 .WillOnce(testing::Return(pointer_up_result));
3561 EXPECT_EQ(expected_disposition_,
3562 HandleInputEventWithLatencyInfo(input_handler_.get(),
3563 gesture_scroll_end_));
3564
3565 EXPECT_EQ(expected_disposition_,
3566 HandleInputEventWithLatencyInfo(input_handler_.get(), touch_end_));
3567 }
3568
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,GestureScrollHandlingScrollFromMainThread)3569 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3570 GestureScrollHandlingScrollFromMainThread) {
3571 // Gesture scrolling on main thread. We only record
3572 // HandlingScrollFromMainThread when it's the only available reason.
3573 SetupEvents(TestEventType::Touch);
3574 EXPECT_CALL(mock_input_handler_,
3575 EventListenerTypeForTouchStartOrMoveAt(
3576 testing::Property(&gfx::Point::x, testing::Gt(0)), _))
3577 .WillOnce(testing::Return(
3578 cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
3579 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
3580 .WillOnce(testing::Return());
3581 EXPECT_CALL(mock_input_handler_, GetEventListenerProperties(_))
3582 .WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive));
3583
3584 cc::InputHandlerPointerResult pointer_down_result;
3585 pointer_down_result.type = cc::PointerResultType::kUnhandled;
3586 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
3587 .WillOnce(testing::Return(pointer_down_result));
3588
3589 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
3590 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3591 input_handler_.get(), touch_start_));
3592
3593 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3594 .WillOnce(testing::Return(kMainThreadScrollState));
3595 EXPECT_CALL(
3596 mock_input_handler_,
3597 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3598 .Times(1);
3599 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3600 EXPECT_EQ(expected_disposition_,
3601 HandleInputEventWithLatencyInfo(input_handler_.get(),
3602 gesture_scroll_begin_));
3603
3604 EXPECT_THAT(
3605 histogram_tester().GetAllSamples(
3606 "Renderer4.MainThreadGestureScrollReason"),
3607 testing::ElementsAre(base::Bucket(
3608 GetBucketSample(
3609 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
3610 1)));
3611
3612 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3613 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3614 EXPECT_EQ(expected_disposition_,
3615 HandleInputEventWithLatencyInfo(input_handler_.get(),
3616 gesture_scroll_end_));
3617 }
3618
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,WheelScrollHistogram)3619 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
3620 // Firstly check if input handler can correctly record main thread scrolling
3621 // reasons.
3622 EXPECT_CALL(
3623 mock_input_handler_,
3624 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3625 .Times(1);
3626 input_handler_->RecordMainThreadScrollingReasonsForTest(
3627 WebGestureDevice::kTouchpad,
3628 cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects |
3629 cc::MainThreadScrollingReason::kThreadedScrollingDisabled |
3630 cc::MainThreadScrollingReason::kFrameOverlay |
3631 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
3632
3633 EXPECT_THAT(
3634 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3635 testing::ElementsAre(
3636 base::Bucket(
3637 GetBucketSample(cc::MainThreadScrollingReason::
3638 kHasBackgroundAttachmentFixedObjects),
3639 1),
3640 base::Bucket(
3641 GetBucketSample(
3642 cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
3643 1),
3644 base::Bucket(
3645 GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay),
3646 1)));
3647
3648 // We only want to record "Handling scroll from main thread" reason if it's
3649 // the only reason. If it's not the only reason, the "real" reason for
3650 // scrolling on main is something else, and we only want to pay attention to
3651 // that reason. So we should only include this reason in the histogram when
3652 // its on its own.
3653 EXPECT_CALL(
3654 mock_input_handler_,
3655 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3656 .Times(1);
3657 input_handler_->RecordMainThreadScrollingReasonsForTest(
3658 WebGestureDevice::kTouchpad,
3659 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
3660
3661 EXPECT_THAT(
3662 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3663 testing::ElementsAre(
3664 base::Bucket(
3665 GetBucketSample(cc::MainThreadScrollingReason::
3666 kHasBackgroundAttachmentFixedObjects),
3667 1),
3668 base::Bucket(
3669 GetBucketSample(
3670 cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
3671 1),
3672 base::Bucket(
3673 GetBucketSample(cc::MainThreadScrollingReason::kFrameOverlay), 1),
3674 base::Bucket(
3675 GetBucketSample(
3676 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
3677 1)));
3678 }
3679
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,WheelScrollNotScrollingOnMain)3680 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3681 WheelScrollNotScrollingOnMain) {
3682 // Even if a scroller is composited, we still need to record its main thread
3683 // scrolling reason if it is blocked on a main thread event handler.
3684 SetupEvents(TestEventType::MouseWheel);
3685
3686 // We can scroll on impl for an wheel event with passive event listener.
3687 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
3688 .WillRepeatedly(testing::Return(false));
3689 EXPECT_CALL(mock_input_handler_,
3690 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
3691 .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
3692 expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
3693 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3694 input_handler_.get(), wheel_event_));
3695
3696 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3697 .WillOnce(testing::Return(kImplThreadScrollState));
3698 EXPECT_CALL(
3699 mock_input_handler_,
3700 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnCompositor))
3701 .Times(1);
3702 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3703 EXPECT_EQ(expected_disposition_,
3704 HandleInputEventWithLatencyInfo(input_handler_.get(),
3705 gesture_scroll_begin_));
3706
3707 EXPECT_THAT(
3708 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3709 testing::ElementsAre(base::Bucket(
3710 GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
3711 1)));
3712
3713 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3714 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3715 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3716 EXPECT_EQ(expected_disposition_,
3717 HandleInputEventWithLatencyInfo(input_handler_.get(),
3718 gesture_scroll_end_));
3719 }
3720
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,WheelScrollWheelEventHandlerRegion)3721 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3722 WheelScrollWheelEventHandlerRegion) {
3723 // Wheel event with blocking event listener. If there is a wheel event handler
3724 // at the point, we do not need to call GetEventListenerProperties since it
3725 // indicates kBlocking.
3726 SetupEvents(TestEventType::MouseWheel);
3727 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
3728 .WillRepeatedly(testing::Return(true));
3729 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3730 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3731 input_handler_.get(), wheel_event_));
3732
3733 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3734 .WillOnce(testing::Return(kImplThreadScrollState));
3735 EXPECT_CALL(
3736 mock_input_handler_,
3737 RecordScrollBegin(
3738 _, cc::ScrollBeginThreadState::kScrollingOnCompositorBlockedOnMain))
3739 .Times(1);
3740 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3741 EXPECT_EQ(expected_disposition_,
3742 HandleInputEventWithLatencyInfo(input_handler_.get(),
3743 gesture_scroll_begin_));
3744
3745 EXPECT_THAT(
3746 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3747 testing::ElementsAre(base::Bucket(
3748 GetBucketSample(
3749 cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
3750 1)));
3751
3752 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3753 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3754 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3755 EXPECT_EQ(expected_disposition_,
3756 HandleInputEventWithLatencyInfo(input_handler_.get(),
3757 gesture_scroll_end_));
3758 }
3759
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,WheelScrollWheelEventHandlerRegionAndHandlingScrollFromMainThread)3760 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3761 WheelScrollWheelEventHandlerRegionAndHandlingScrollFromMainThread) {
3762 // Wheel scrolling on main thread. Because we also block scrolling with wheel
3763 // event handler, we should record that reason as well.
3764 SetupEvents(TestEventType::MouseWheel);
3765 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
3766 .WillRepeatedly(testing::Return(true));
3767 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3768 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3769 input_handler_.get(), wheel_event_));
3770
3771 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3772 .WillOnce(testing::Return(kMainThreadScrollState));
3773 EXPECT_CALL(
3774 mock_input_handler_,
3775 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3776 .Times(1);
3777 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3778 EXPECT_EQ(expected_disposition_,
3779 HandleInputEventWithLatencyInfo(input_handler_.get(),
3780 gesture_scroll_begin_));
3781
3782 EXPECT_THAT(
3783 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3784 testing::ElementsAre(base::Bucket(
3785 GetBucketSample(
3786 cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
3787 1)));
3788
3789 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3790 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3791 EXPECT_EQ(expected_disposition_,
3792 HandleInputEventWithLatencyInfo(input_handler_.get(),
3793 gesture_scroll_end_));
3794 }
3795
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,WheelScrollHandlingScrollFromMainThread)3796 TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
3797 WheelScrollHandlingScrollFromMainThread) {
3798 // Gesture scrolling on main thread. We only record
3799 // HandlingScrollFromMainThread when it's the only available reason.
3800 SetupEvents(TestEventType::MouseWheel);
3801 EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(_))
3802 .WillRepeatedly(testing::Return(false));
3803 EXPECT_CALL(mock_input_handler_,
3804 GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
3805 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
3806 expected_disposition_ = InputHandlerProxy::DROP_EVENT;
3807 EXPECT_EQ(expected_disposition_, HandleInputEventWithLatencyInfo(
3808 input_handler_.get(), wheel_event_));
3809
3810 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3811 .WillOnce(testing::Return(kMainThreadScrollState));
3812 EXPECT_CALL(
3813 mock_input_handler_,
3814 RecordScrollBegin(_, cc::ScrollBeginThreadState::kScrollingOnMain))
3815 .Times(1);
3816 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3817 EXPECT_EQ(expected_disposition_,
3818 HandleInputEventWithLatencyInfo(input_handler_.get(),
3819 gesture_scroll_begin_));
3820
3821 EXPECT_THAT(
3822 histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
3823 testing::ElementsAre(base::Bucket(
3824 GetBucketSample(
3825 cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
3826 1)));
3827
3828 expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
3829 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3830 EXPECT_EQ(expected_disposition_,
3831 HandleInputEventWithLatencyInfo(input_handler_.get(),
3832 gesture_scroll_end_));
3833 }
3834
3835 class InputHandlerProxyTouchScrollbarTest : public InputHandlerProxyTest {
3836 public:
SetupEvents()3837 void SetupEvents() {
3838 touch_start_ = WebTouchEvent(WebInputEvent::Type::kTouchStart,
3839 WebInputEvent::kNoModifiers,
3840 WebInputEvent::GetStaticTimeStampForTests());
3841 touch_end_ = WebTouchEvent(WebInputEvent::Type::kTouchEnd,
3842 WebInputEvent::kNoModifiers,
3843 WebInputEvent::GetStaticTimeStampForTests());
3844 touch_start_.touches_length = 1;
3845 touch_start_.touch_start_or_first_touch_move = true;
3846 touch_start_.touches[0] =
3847 CreateWebTouchPoint(WebTouchPoint::State::kStatePressed, 10, 10);
3848
3849 touch_end_.touches_length = 1;
3850 }
3851
3852 protected:
3853 WebTouchEvent touch_start_;
3854 WebTouchEvent touch_end_;
3855 };
3856
TEST_P(InputHandlerProxyTouchScrollbarTest,TouchOnScrollbarIsHandledByCompositorThread)3857 TEST_P(InputHandlerProxyTouchScrollbarTest,
3858 TouchOnScrollbarIsHandledByCompositorThread) {
3859 // The touch event hits a touch event handler that is acked from the
3860 // compositor thread.
3861 SetupEvents();
3862 cc::InputHandlerPointerResult pointer_down_result;
3863 pointer_down_result.type = cc::PointerResultType::kScrollbarScroll;
3864 pointer_down_result.scroll_offset = gfx::ScrollOffset(0, 1);
3865 cc::InputHandlerPointerResult pointer_up_result;
3866 pointer_up_result.type = cc::PointerResultType::kScrollbarScroll;
3867
3868 EXPECT_CALL(mock_input_handler_,
3869 EventListenerTypeForTouchStartOrMoveAt(
3870 testing::Property(&gfx::Point::x, testing::Eq(10)), _))
3871 .WillOnce(testing::Invoke([](const gfx::Point&,
3872 cc::TouchAction* touch_action) {
3873 *touch_action = cc::TouchAction::kAuto;
3874 return cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER;
3875 }));
3876 EXPECT_CALL(
3877 mock_input_handler_,
3878 GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
3879 .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
3880
3881 EXPECT_CALL(mock_client_, SetAllowedTouchAction(_, _, _))
3882 .WillOnce(testing::Return());
3883
3884 EXPECT_CALL(mock_input_handler_, MouseDown(_, _))
3885 .WillOnce(testing::Return(pointer_down_result));
3886 cc::InputHandlerScrollResult scroll_result_did_scroll;
3887 scroll_result_did_scroll.did_scroll = true;
3888 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3889
3890 if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
3891 EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
3892 .WillOnce(testing::Return(false));
3893 }
3894 EXPECT_CALL(
3895 mock_input_handler_,
3896 RecordScrollBegin(ui::ScrollInputType::kScrollbar,
3897 cc::ScrollBeginThreadState::kScrollingOnCompositor))
3898 .Times(1);
3899 EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
3900 .WillOnce(testing::Return(kImplThreadScrollState));
3901 EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _))
3902 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
3903 EXPECT_CALL(mock_input_handler_, MouseUp(_))
3904 .WillOnce(testing::Return(pointer_up_result));
3905
3906 EXPECT_EQ(expected_disposition_,
3907 HandleInputEventAndFlushEventQueue(
3908 mock_input_handler_, input_handler_.get(), touch_start_));
3909
3910 EXPECT_CALL(mock_input_handler_, ScrollEnd(true));
3911 EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
3912 expected_disposition_ = InputHandlerProxy::DID_HANDLE;
3913 EXPECT_EQ(expected_disposition_,
3914 HandleInputEventAndFlushEventQueue(
3915 mock_input_handler_, input_handler_.get(), touch_end_));
3916 }
3917
3918 class InputHandlerProxyMomentumScrollJankTest : public testing::Test {
3919 public:
InputHandlerProxyMomentumScrollJankTest()3920 InputHandlerProxyMomentumScrollJankTest()
3921 : input_handler_proxy_(mock_input_handler_, &mock_client_) {
3922 tick_clock_.SetNowTicks(base::TimeTicks::Now());
3923 // Disable scroll predictor for this test.
3924 input_handler_proxy_.scroll_predictor_ = nullptr;
3925 input_handler_proxy_.SetTickClockForTesting(&tick_clock_);
3926 }
3927
3928 ~InputHandlerProxyMomentumScrollJankTest() = default;
3929
HandleScrollBegin()3930 void HandleScrollBegin() {
3931 auto gesture = std::make_unique<WebGestureEvent>(
3932 WebInputEvent::Type::kGestureScrollBegin, WebInputEvent::kNoModifiers,
3933 tick_clock_.NowTicks(), WebGestureDevice::kTouchscreen);
3934 HandleGesture(std::move(gesture));
3935 }
3936
HandleScrollEnd()3937 void HandleScrollEnd() {
3938 auto gesture = std::make_unique<WebGestureEvent>(
3939 WebInputEvent::Type::kGestureScrollEnd, WebInputEvent::kNoModifiers,
3940 tick_clock_.NowTicks(), WebGestureDevice::kTouchscreen);
3941 HandleGesture(std::move(gesture));
3942 }
3943
HandleScrollUpdate(bool is_momentum)3944 void HandleScrollUpdate(bool is_momentum) {
3945 auto gesture = std::make_unique<WebGestureEvent>(
3946 WebInputEvent::Type::kGestureScrollUpdate, WebInputEvent::kNoModifiers,
3947 tick_clock_.NowTicks(), WebGestureDevice::kTouchscreen);
3948 gesture->data.scroll_update.delta_y = -20;
3949 if (is_momentum) {
3950 gesture->data.scroll_update.inertial_phase =
3951 WebGestureEvent::InertialPhaseState::kMomentum;
3952 }
3953 HandleGesture(std::move(gesture));
3954 }
3955
AdvanceClock(uint32_t milliseconds)3956 void AdvanceClock(uint32_t milliseconds) {
3957 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(milliseconds));
3958 }
3959
AddNonJankyEvents(uint32_t count)3960 void AddNonJankyEvents(uint32_t count) {
3961 for (uint32_t i = 0; i < count; ++i) {
3962 AdvanceClock(16);
3963 HandleScrollUpdate(true /* is_momentum */);
3964 DeliverInputForBeginFrame();
3965 }
3966 }
3967
DeliverInputForBeginFrame()3968 void DeliverInputForBeginFrame() {
3969 constexpr base::TimeDelta interval = base::TimeDelta::FromMilliseconds(16);
3970 base::TimeTicks frame_time =
3971 base::TimeTicks() +
3972 (next_begin_frame_number_ - viz::BeginFrameArgs::kStartingFrameNumber) *
3973 interval;
3974 input_handler_proxy_.DeliverInputForBeginFrame(viz::BeginFrameArgs::Create(
3975 BEGINFRAME_FROM_HERE, 0, next_begin_frame_number_++, frame_time,
3976 frame_time + interval, interval, viz::BeginFrameArgs::NORMAL));
3977 }
3978
3979 protected:
HandleGesture(std::unique_ptr<WebInputEvent> event)3980 void HandleGesture(std::unique_ptr<WebInputEvent> event) {
3981 input_handler_proxy_.HandleInputEventWithLatencyInfo(
3982 std::make_unique<WebCoalescedInputEvent>(std::move(event),
3983 ui::LatencyInfo()),
3984 nullptr, base::DoNothing());
3985 }
3986
3987 uint64_t next_begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
3988
3989 testing::NiceMock<MockInputHandler> mock_input_handler_;
3990 testing::NiceMock<MockInputHandlerProxyClient> mock_client_;
3991 TestInputHandlerProxy input_handler_proxy_;
3992 base::SimpleTestTickClock tick_clock_;
3993 };
3994
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestJank)3995 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestJank) {
3996 cc::InputHandlerScrollResult scroll_result_did_scroll;
3997 scroll_result_did_scroll.did_scroll = true;
3998 EXPECT_CALL(
3999 mock_input_handler_,
4000 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4001 _))
4002 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4003
4004 base::HistogramTester histogram_tester;
4005 HandleScrollBegin();
4006
4007 // Flush one update, the first update is always ignored.
4008 AdvanceClock(16);
4009 HandleScrollUpdate(true /* is_momentum */);
4010 DeliverInputForBeginFrame();
4011
4012 // Enqueue three updates, they will be coalesced and count as two janks.
4013 AdvanceClock(16);
4014 HandleScrollUpdate(true /* is_momentum */);
4015 AdvanceClock(16);
4016 HandleScrollUpdate(true /* is_momentum */);
4017 AdvanceClock(16);
4018 HandleScrollUpdate(true /* is_momentum */);
4019 AdvanceClock(1);
4020 DeliverInputForBeginFrame();
4021
4022 // Enqueue two updates, they will be coalesced and count as one jank
4023 // (https://crbug.com/952930).
4024 AdvanceClock(16);
4025 HandleScrollUpdate(true /* is_momentum */);
4026 AdvanceClock(16);
4027 HandleScrollUpdate(true /* is_momentum */);
4028 AdvanceClock(1);
4029 DeliverInputForBeginFrame();
4030
4031 // Enqueue two updates, they will be coalesced and count as one
4032 // jank(https://crbug.com/952930).
4033 AdvanceClock(16);
4034 HandleScrollUpdate(true /* is_momentum */);
4035 AdvanceClock(16);
4036 HandleScrollUpdate(true /* is_momentum */);
4037 AdvanceClock(1);
4038 DeliverInputForBeginFrame();
4039
4040 // Add 93 non-janky events, bringing us to a total of 100 events.
4041 AddNonJankyEvents(93);
4042
4043 HandleScrollEnd();
4044 DeliverInputForBeginFrame();
4045
4046 histogram_tester.ExpectUniqueSample("Renderer4.MomentumScrollJankPercentage",
4047 4, 1);
4048 }
4049
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestJankMultipleGestures)4050 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestJankMultipleGestures) {
4051 cc::InputHandlerScrollResult scroll_result_did_scroll;
4052 scroll_result_did_scroll.did_scroll = true;
4053 EXPECT_CALL(
4054 mock_input_handler_,
4055 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4056 _))
4057 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4058
4059 base::HistogramTester histogram_tester;
4060
4061 for (int i = 0; i < 3; ++i) {
4062 HandleScrollBegin();
4063
4064 // Flush one update, the first update is always ignored.
4065 AdvanceClock(16);
4066 HandleScrollUpdate(true /* is_momentum */);
4067 DeliverInputForBeginFrame();
4068
4069 // Enqueue two updates, they will be coalesced and count as one jank
4070 // (https://crbug.com/952930).
4071 AdvanceClock(16);
4072 HandleScrollUpdate(true /* is_momentum */);
4073 AdvanceClock(16);
4074 HandleScrollUpdate(true /* is_momentum */);
4075 AdvanceClock(1);
4076 DeliverInputForBeginFrame();
4077
4078 // Add 98 non-janky events, bringing us to a total of 100 events.
4079 AddNonJankyEvents(98);
4080
4081 HandleScrollEnd();
4082 DeliverInputForBeginFrame();
4083
4084 histogram_tester.ExpectUniqueSample(
4085 "Renderer4.MomentumScrollJankPercentage", 1, i + 1);
4086 }
4087 }
4088
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestJankRounding)4089 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestJankRounding) {
4090 cc::InputHandlerScrollResult scroll_result_did_scroll;
4091 scroll_result_did_scroll.did_scroll = true;
4092 EXPECT_CALL(
4093 mock_input_handler_,
4094 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4095 _))
4096 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4097
4098 base::HistogramTester histogram_tester;
4099
4100 HandleScrollBegin();
4101
4102 // Flush one update, the first update is always ignored.
4103 AdvanceClock(16);
4104 HandleScrollUpdate(true /* is_momentum */);
4105 DeliverInputForBeginFrame();
4106
4107 // Enqueue two updates, they will be coalesced and count as one jank
4108 // (https://crbug.com/952930).
4109 AdvanceClock(16);
4110 HandleScrollUpdate(true /* is_momentum */);
4111 AdvanceClock(16);
4112 HandleScrollUpdate(true /* is_momentum */);
4113 AdvanceClock(1);
4114 DeliverInputForBeginFrame();
4115
4116 // Add 500 non-janky events. Even with this many events, our round-up logic
4117 // should cause us to report 1% jank.
4118 AddNonJankyEvents(500);
4119
4120 HandleScrollEnd();
4121 DeliverInputForBeginFrame();
4122
4123 histogram_tester.ExpectUniqueSample("Renderer4.MomentumScrollJankPercentage",
4124 1, 1);
4125 }
4126
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestSimpleNoJank)4127 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestSimpleNoJank) {
4128 cc::InputHandlerScrollResult scroll_result_did_scroll;
4129 scroll_result_did_scroll.did_scroll = true;
4130 EXPECT_CALL(
4131 mock_input_handler_,
4132 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4133 _))
4134 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4135
4136 base::HistogramTester histogram_tester;
4137 HandleScrollBegin();
4138
4139 // Flush one update, the first update is always ignored.
4140 AdvanceClock(16);
4141 HandleScrollUpdate(true /* is_momentum */);
4142 AdvanceClock(1);
4143 DeliverInputForBeginFrame();
4144
4145 // Enqueue one updates, no jank.
4146 AdvanceClock(16);
4147 HandleScrollUpdate(true /* is_momentum */);
4148 AdvanceClock(1);
4149 DeliverInputForBeginFrame();
4150
4151 // Enqueue one updates, no jank.
4152 AdvanceClock(16);
4153 HandleScrollUpdate(true /* is_momentum */);
4154 AdvanceClock(1);
4155 DeliverInputForBeginFrame();
4156
4157 HandleScrollEnd();
4158 DeliverInputForBeginFrame();
4159
4160 histogram_tester.ExpectUniqueSample("Renderer4.MomentumScrollJankPercentage",
4161 0, 1);
4162 }
4163
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestFirstGestureNoJank)4164 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestFirstGestureNoJank) {
4165 cc::InputHandlerScrollResult scroll_result_did_scroll;
4166 scroll_result_did_scroll.did_scroll = true;
4167 EXPECT_CALL(
4168 mock_input_handler_,
4169 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4170 _))
4171 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4172
4173 base::HistogramTester histogram_tester;
4174 HandleScrollBegin();
4175
4176 // Even with 3 coalesced frames, the first gesture should not trigger a jank.
4177 AdvanceClock(16);
4178 HandleScrollUpdate(true /* is_momentum */);
4179 AdvanceClock(16);
4180 HandleScrollUpdate(true /* is_momentum */);
4181 AdvanceClock(16);
4182 HandleScrollUpdate(true /* is_momentum */);
4183 AdvanceClock(1);
4184 DeliverInputForBeginFrame();
4185
4186 HandleScrollEnd();
4187 DeliverInputForBeginFrame();
4188
4189 histogram_tester.ExpectTotalCount("Renderer4.MomentumScrollJankPercentage",
4190 0);
4191 }
4192
TEST_F(InputHandlerProxyMomentumScrollJankTest,TestNonMomentumNoJank)4193 TEST_F(InputHandlerProxyMomentumScrollJankTest, TestNonMomentumNoJank) {
4194 cc::InputHandlerScrollResult scroll_result_did_scroll;
4195 scroll_result_did_scroll.did_scroll = true;
4196 EXPECT_CALL(
4197 mock_input_handler_,
4198 ScrollUpdate(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0)),
4199 _))
4200 .WillRepeatedly(testing::Return(scroll_result_did_scroll));
4201
4202 base::HistogramTester histogram_tester;
4203 HandleScrollBegin();
4204
4205 // Flush one update, the first update is always ignored.
4206 AdvanceClock(16);
4207 HandleScrollUpdate(false /* is_momentum */);
4208 AdvanceClock(1);
4209 DeliverInputForBeginFrame();
4210
4211 // Enqueue three updates, these will not cause jank, as none are momentum.
4212 AdvanceClock(16);
4213 HandleScrollUpdate(false /* is_momentum */);
4214 AdvanceClock(16);
4215 HandleScrollUpdate(false /* is_momentum */);
4216 AdvanceClock(16);
4217 HandleScrollUpdate(false /* is_momentum */);
4218 AdvanceClock(1);
4219 DeliverInputForBeginFrame();
4220
4221 HandleScrollEnd();
4222 DeliverInputForBeginFrame();
4223
4224 histogram_tester.ExpectTotalCount("Renderer4.MomentumScrollJankPercentage",
4225 0);
4226 }
4227
4228 const auto kTestCombinations = testing::Combine(
4229 testing::Values(ScrollerType::kRoot, ScrollerType::kChild),
4230 testing::Values(HandlerType::kNormal, HandlerType::kSynchronous),
4231 testing::Values(ScrollUnification::kEnabled, ScrollUnification::kDisabled));
4232
4233 const auto kSuffixGenerator =
4234 [](const testing::TestParamInfo<
__anon8a50c1ea0d02(const testing::TestParamInfo< std::tuple<ScrollerType, HandlerType, ScrollUnification>>& info) 4235 std::tuple<ScrollerType, HandlerType, ScrollUnification>>& info) {
4236 std::string name = std::get<1>(info.param) == HandlerType::kSynchronous
4237 ? "Synchronous"
4238 : "";
4239 name += std::get<0>(info.param) == ScrollerType::kRoot ? "Root" : "Child";
4240 name += std::get<2>(info.param) == ScrollUnification::kEnabled
4241 ? "UnifiedScroll"
4242 : "LegacyScroll";
4243 return name;
4244 };
4245
4246 INSTANTIATE_TEST_SUITE_P(All,
4247 InputHandlerProxyTest,
4248 kTestCombinations,
4249 kSuffixGenerator);
4250
4251 INSTANTIATE_TEST_SUITE_P(All,
4252 InputHandlerProxyMainThreadScrollingReasonTest,
4253 kTestCombinations,
4254 kSuffixGenerator);
4255
4256 INSTANTIATE_TEST_SUITE_P(All,
4257 InputHandlerProxyTouchScrollbarTest,
4258 kTestCombinations,
4259 kSuffixGenerator);
4260
4261 } // namespace test
4262 } // namespace blink
4263