| Index: ui/events/blink/input_handler_proxy_unittest.cc
|
| diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
|
| index 78608b2d4ea9c316c87ee4bfeab3098c1395be41..d125c4ef76207082b26e4d9051409309bdbdc646 100644
|
| --- a/ui/events/blink/input_handler_proxy_unittest.cc
|
| +++ b/ui/events/blink/input_handler_proxy_unittest.cc
|
| @@ -6,8 +6,12 @@
|
|
|
| #include <memory>
|
|
|
| +#include "base/bind.h"
|
| #include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/test/histogram_tester.h"
|
| +#include "base/test/scoped_feature_list.h"
|
| +#include "base/test/simple_test_tick_clock.h"
|
| #include "cc/input/main_thread_scrolling_reason.h"
|
| #include "cc/trees/swap_promise_monitor.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| @@ -17,7 +21,11 @@
|
| #include "third_party/WebKit/public/platform/WebGestureCurve.h"
|
| #include "third_party/WebKit/public/platform/WebInputEvent.h"
|
| #include "third_party/WebKit/public/platform/WebPoint.h"
|
| +#include "ui/events/blink/compositor_thread_event_queue.h"
|
| +#include "ui/events/blink/did_overscroll_params.h"
|
| +#include "ui/events/blink/event_with_callback.h"
|
| #include "ui/events/blink/input_handler_proxy_client.h"
|
| +#include "ui/events/blink/web_input_event_traits.h"
|
| #include "ui/events/latency_info.h"
|
| #include "ui/gfx/geometry/scroll_offset.h"
|
| #include "ui/gfx/geometry/size_f.h"
|
| @@ -41,6 +49,15 @@ namespace test {
|
|
|
| namespace {
|
|
|
| +const char* kCoalescedCountHistogram =
|
| + "Event.CompositorThreadEventQueue.CoalescedCount";
|
| +const char* kContinuousHeadQueueingTimeHistogram =
|
| + "Event.CompositorThreadEventQueue.Continuous.HeadQueueingTime";
|
| +const char* kContinuousTailQueueingTimeHistogram =
|
| + "Event.CompositorThreadEventQueue.Continuous.TailQueueingTime";
|
| +const char* kNonContinuousQueueingTimeHistogram =
|
| + "Event.CompositorThreadEventQueue.NonContinuous.QueueingTime";
|
| +
|
| enum InputHandlerProxyTestType {
|
| ROOT_SCROLL_NORMAL_HANDLER,
|
| ROOT_SCROLL_SYNCHRONOUS_HANDLER,
|
| @@ -103,6 +120,23 @@ WebGestureEvent CreateFling(WebGestureDevice source_device,
|
| modifiers);
|
| }
|
|
|
| +ScopedWebInputEvent CreateGestureScrollOrPinch(WebInputEvent::Type type,
|
| + float deltaYOrScale = 0,
|
| + int x = 0,
|
| + int y = 0) {
|
| + WebGestureEvent gesture;
|
| + gesture.sourceDevice = blink::WebGestureDeviceTouchpad;
|
| + gesture.type = type;
|
| + if (type == WebInputEvent::GestureScrollUpdate) {
|
| + gesture.data.scrollUpdate.deltaY = deltaYOrScale;
|
| + } else if (type == WebInputEvent::GesturePinchUpdate) {
|
| + gesture.data.pinchUpdate.scale = deltaYOrScale;
|
| + gesture.x = x;
|
| + gesture.y = y;
|
| + }
|
| + return WebInputEventTraits::Clone(gesture);
|
| +}
|
| +
|
| class MockInputHandler : public cc::InputHandler {
|
| public:
|
| MockInputHandler() {}
|
| @@ -437,6 +471,62 @@ class InputHandlerProxyTest
|
| cc::InputHandlerScrollResult scroll_result_did_not_scroll_;
|
| };
|
|
|
| +class InputHandlerProxyEventQueueTest : public testing::Test {
|
| + public:
|
| + InputHandlerProxyEventQueueTest() : weak_ptr_factory_(this) {
|
| + feature_list_.InitAndEnableFeature(features::kVsyncAlignedInputEvents);
|
| + }
|
| +
|
| + ~InputHandlerProxyEventQueueTest() { input_handler_proxy_.reset(); }
|
| +
|
| + void SetUp() override {
|
| + event_disposition_recorder_.clear();
|
| + input_handler_proxy_ = base::MakeUnique<TestInputHandlerProxy>(
|
| + &mock_input_handler_, &mock_client_);
|
| + if (input_handler_proxy_->compositor_event_queue_)
|
| + input_handler_proxy_->compositor_event_queue_ =
|
| + base::MakeUnique<CompositorThreadEventQueue>();
|
| + }
|
| +
|
| + void HandleGestureEvent(WebInputEvent::Type type,
|
| + float deltay_or_scale = 0,
|
| + int x = 0,
|
| + int y = 0) {
|
| + LatencyInfo latency;
|
| + input_handler_proxy_->HandleInputEventWithLatencyInfo(
|
| + CreateGestureScrollOrPinch(type, deltay_or_scale, x, y), latency,
|
| + base::Bind(
|
| + &InputHandlerProxyEventQueueTest::DidHandleInputEventAndOverscroll,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + void DidHandleInputEventAndOverscroll(
|
| + InputHandlerProxy::EventDisposition event_disposition,
|
| + ui::ScopedWebInputEvent input_event,
|
| + const ui::LatencyInfo& latency_info,
|
| + std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
|
| + event_disposition_recorder_.push_back(event_disposition);
|
| + }
|
| +
|
| + std::deque<std::unique_ptr<EventWithCallback>>& event_queue() {
|
| + return input_handler_proxy_->compositor_event_queue_->queue_;
|
| + }
|
| +
|
| + void SetInputHandlerProxyTickClockForTesting(
|
| + std::unique_ptr<base::TickClock> tick_clock) {
|
| + input_handler_proxy_->SetTickClockForTesting(std::move(tick_clock));
|
| + }
|
| +
|
| + protected:
|
| + base::test::ScopedFeatureList feature_list_;
|
| + testing::StrictMock<MockInputHandler> mock_input_handler_;
|
| + std::unique_ptr<TestInputHandlerProxy> input_handler_proxy_;
|
| + testing::StrictMock<MockInputHandlerProxyClient> mock_client_;
|
| + std::vector<InputHandlerProxy::EventDisposition> event_disposition_recorder_;
|
| +
|
| + base::WeakPtrFactory<InputHandlerProxyEventQueueTest> weak_ptr_factory_;
|
| +};
|
| +
|
| TEST_P(InputHandlerProxyTest, MouseWheelNoListener) {
|
| expected_disposition_ = InputHandlerProxy::DROP_EVENT;
|
| EXPECT_CALL(mock_input_handler_,
|
| @@ -2815,9 +2905,187 @@ TEST_P(InputHandlerProxyTest, MainThreadScrollingMouseWheelHistograms) {
|
| base::Bucket(5, 1), base::Bucket(14, 1)));
|
| }
|
|
|
| +TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {
|
| + base::HistogramTester histogram_tester;
|
| +
|
| + // Handle scroll on compositor.
|
| + cc::InputHandlerScrollResult scroll_result_did_scroll_;
|
| + scroll_result_did_scroll_.did_scroll = true;
|
| +
|
| + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
|
| + .WillOnce(testing::Return(kImplThreadScrollState));
|
| + EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollBegin);
|
| +
|
| + // GestureScrollBegin will be processed immediately.
|
| + EXPECT_EQ(0ul, event_queue().size());
|
| + EXPECT_EQ(1ul, event_disposition_recorder_.size());
|
| + EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[0]);
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -20);
|
| +
|
| + // GestureScrollUpdate will be queued.
|
| + EXPECT_EQ(1ul, event_queue().size());
|
| + EXPECT_EQ(-20, static_cast<const blink::WebGestureEvent&>(
|
| + event_queue().front()->event())
|
| + .data.scrollUpdate.deltaY);
|
| + EXPECT_EQ(1ul, event_queue().front()->coalesced_count());
|
| + EXPECT_EQ(1ul, event_disposition_recorder_.size());
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -40);
|
| +
|
| + // GestureScrollUpdate will be coalesced.
|
| + EXPECT_EQ(1ul, event_queue().size());
|
| + EXPECT_EQ(-60, static_cast<const blink::WebGestureEvent&>(
|
| + event_queue().front()->event())
|
| + .data.scrollUpdate.deltaY);
|
| + EXPECT_EQ(2ul, event_queue().front()->coalesced_count());
|
| + EXPECT_EQ(1ul, event_disposition_recorder_.size());
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollEnd);
|
| +
|
| + // GestureScrollEnd will be queued.
|
| + EXPECT_EQ(2ul, event_queue().size());
|
| + EXPECT_EQ(1ul, event_disposition_recorder_.size());
|
| + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
|
| +
|
| + EXPECT_CALL(
|
| + mock_input_handler_,
|
| + ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
|
| + .WillOnce(testing::Return(scroll_result_did_scroll_));
|
| + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
|
| +
|
| + // Dispatch all queued events.
|
| + input_handler_proxy_->DeliverInputForBeginFrame();
|
| + EXPECT_EQ(0ul, event_queue().size());
|
| + // Should run callbacks for every original events.
|
| + EXPECT_EQ(4ul, event_disposition_recorder_.size());
|
| + EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[1]);
|
| + EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[2]);
|
| + EXPECT_EQ(InputHandlerProxy::DID_HANDLE, event_disposition_recorder_[3]);
|
| + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
|
| + histogram_tester.ExpectUniqueSample(kCoalescedCountHistogram, 2, 1);
|
| +}
|
| +
|
| +TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScrollPinchScroll) {
|
| + base::HistogramTester histogram_tester;
|
| +
|
| + // Handle scroll on compositor.
|
| + cc::InputHandlerScrollResult scroll_result_did_scroll_;
|
| + scroll_result_did_scroll_.did_scroll = true;
|
| +
|
| + // Start scroll in the first frame.
|
| + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
|
| + .WillOnce(testing::Return(kImplThreadScrollState));
|
| + EXPECT_CALL(
|
| + mock_input_handler_,
|
| + ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
|
| + .WillOnce(testing::Return(scroll_result_did_scroll_));
|
| + EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollBegin);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -20);
|
| +
|
| + EXPECT_EQ(1ul, event_queue().size());
|
| + EXPECT_EQ(1ul, event_disposition_recorder_.size());
|
| +
|
| + input_handler_proxy_->DeliverInputForBeginFrame();
|
| +
|
| + EXPECT_EQ(0ul, event_queue().size());
|
| + EXPECT_EQ(2ul, event_disposition_recorder_.size());
|
| + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
|
| +
|
| + // Continue scroll in the second frame, pinch, then start another scroll.
|
| + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
|
| + .WillOnce(testing::Return(kImplThreadScrollState));
|
| + EXPECT_CALL(
|
| + mock_input_handler_,
|
| + ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
|
| + .WillRepeatedly(testing::Return(scroll_result_did_scroll_));
|
| + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_)).Times(2);
|
| + EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
|
| + EXPECT_CALL(mock_input_handler_,
|
| + GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
|
| + .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
|
| + EXPECT_CALL(mock_input_handler_, PinchGestureBegin());
|
| + // Two |GesturePinchUpdate| will be coalesced.
|
| + EXPECT_CALL(mock_input_handler_,
|
| + PinchGestureUpdate(0.7f, gfx::Point(13, 17)));
|
| + EXPECT_CALL(mock_input_handler_, PinchGestureEnd());
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -30);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollEnd);
|
| + HandleGestureEvent(WebInputEvent::GesturePinchBegin);
|
| + HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 1.4f, 13, 17);
|
| + HandleGestureEvent(WebInputEvent::GesturePinchUpdate, 0.5f, 13, 17);
|
| + HandleGestureEvent(WebInputEvent::GesturePinchEnd);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollBegin);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -70);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -5);
|
| + HandleGestureEvent(WebInputEvent::GestureScrollEnd);
|
| +
|
| + EXPECT_EQ(8ul, event_queue().size());
|
| + EXPECT_EQ(2ul, event_disposition_recorder_.size());
|
| +
|
| + input_handler_proxy_->DeliverInputForBeginFrame();
|
| +
|
| + EXPECT_EQ(0ul, event_queue().size());
|
| + EXPECT_EQ(12ul, event_disposition_recorder_.size());
|
| + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
|
| + histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 1, 2);
|
| + histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 2, 2);
|
| +}
|
| +
|
| +TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) {
|
| + base::HistogramTester histogram_tester;
|
| + std::unique_ptr<base::SimpleTestTickClock> tick_clock =
|
| + base::MakeUnique<base::SimpleTestTickClock>();
|
| + base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
|
| + tick_clock_ptr->SetNowTicks(base::TimeTicks::Now());
|
| + SetInputHandlerProxyTickClockForTesting(std::move(tick_clock));
|
| +
|
| + // Handle scroll on compositor.
|
| + cc::InputHandlerScrollResult scroll_result_did_scroll_;
|
| + scroll_result_did_scroll_.did_scroll = true;
|
| +
|
| + EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
|
| + .WillOnce(testing::Return(kImplThreadScrollState));
|
| + EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
|
| + EXPECT_CALL(
|
| + mock_input_handler_,
|
| + ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
|
| + .WillOnce(testing::Return(scroll_result_did_scroll_));
|
| + EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
|
| +
|
| + HandleGestureEvent(WebInputEvent::GestureScrollBegin);
|
| + tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(10));
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -20);
|
| + tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(40));
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -40);
|
| + tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(20));
|
| + HandleGestureEvent(WebInputEvent::GestureScrollUpdate, -10);
|
| + tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(10));
|
| + HandleGestureEvent(WebInputEvent::GestureScrollEnd);
|
| +
|
| + // Dispatch all queued events.
|
| + tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(70));
|
| + input_handler_proxy_->DeliverInputForBeginFrame();
|
| + EXPECT_EQ(0ul, event_queue().size());
|
| + EXPECT_EQ(5ul, event_disposition_recorder_.size());
|
| + testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
|
| + histogram_tester.ExpectUniqueSample(kContinuousHeadQueueingTimeHistogram, 140,
|
| + 1);
|
| + histogram_tester.ExpectUniqueSample(kContinuousTailQueueingTimeHistogram, 80,
|
| + 1);
|
| + histogram_tester.ExpectBucketCount(kNonContinuousQueueingTimeHistogram, 0, 1);
|
| + histogram_tester.ExpectBucketCount(kNonContinuousQueueingTimeHistogram, 70,
|
| + 1);
|
| +}
|
|
|
| INSTANTIATE_TEST_CASE_P(AnimateInput,
|
| InputHandlerProxyTest,
|
| testing::ValuesIn(test_types));
|
| +
|
| } // namespace test
|
| } // namespace ui
|
|
|