chromium/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/widget/input/input_handler_proxy.h"

#include <memory>

#include "base/containers/circular_deque.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h"
#include "base/test/trace_event_analyzer.h"
#include "base/types/optional_ref.h"
#include "build/build_config.h"
#include "cc/base/features.h"
#include "cc/input/browser_controls_offset_tags_info.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "cc/trees/layer_tree_settings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_input_event_attribution.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
#include "third_party/blink/public/common/input/web_pointer_event.h"
#include "third_party/blink/public/common/input/web_touch_event.h"
#include "third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.h"
#include "third_party/blink/renderer/platform/widget/input/event_with_callback.h"
#include "third_party/blink/renderer/platform/widget/input/input_handler_proxy.h"
#include "third_party/blink/renderer/platform/widget/input/input_handler_proxy_client.h"
#include "third_party/blink/renderer/platform/widget/input/scroll_predictor.h"
#include "ui/events/types/scroll_input_type.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/latency/latency_info.h"

InputHandler;
ScrollBeginThreadState;
TouchAction;
_;
AllOf;
DoAll;
Eq;
Field;
Mock;
NiceMock;
Property;
Return;
SetArgPointee;
StrictMock;

namespace blink {
namespace test {

namespace {

MATCHER_P(WheelEventsMatch, expected, "") {}

std::unique_ptr<WebInputEvent> CreateGestureScrollPinch(
    WebInputEvent::Type type,
    WebGestureDevice source_device,
    base::TimeTicks event_time,
    float delta_y_or_scale = 0,
    int x = 0,
    int y = 0) {}

class FakeCompositorDelegateForInput : public cc::CompositorDelegateForInput {};

base::LazyInstance<FakeCompositorDelegateForInput>::Leaky
    g_fake_compositor_delegate =;

class MockInputHandler : public cc::InputHandler {};

class MockSynchronousInputHandler : public SynchronousInputHandler {};

class MockInputHandlerProxyClient : public InputHandlerProxyClient {};

WebTouchPoint CreateWebTouchPoint(WebTouchPoint::State state,
                                  float x,
                                  float y) {}

const cc::InputHandler::ScrollStatus kImplThreadScrollState{};

const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState{};

constexpr auto kSampleMainThreadScrollingReason =;

const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState{};

}  // namespace

class TestInputHandlerProxy : public InputHandlerProxy {};

// Whether or not the input handler says that the viewport is scrolling the
// root scroller or a child.
enum class ScrollerType {};

// Whether or not to setup a synchronous input handler. This simulates the mode
// that WebView runs in.
enum class HandlerType {};

class InputHandlerProxyTest : public testing::Test,
                              public testing::WithParamInterface<
                                  std::tuple<ScrollerType, HandlerType>> {};

// The helper basically returns the EventDisposition that is returned by
// RouteToTypeSpecificHandler. This is done by passing in a callback when
// calling HandleInputEventWithLatencyInfo. By design, DispatchSingleInputEvent
// will then call this callback with the disposition returned by
// RouteToTypeSpecificHandler and that is what gets returned by this helper.
InputHandlerProxy::EventDisposition HandleInputEventWithLatencyInfo(
    TestInputHandlerProxy* input_handler,
    const WebInputEvent& event) {}

// This helper forces the CompositorThreadEventQueue to be flushed.
InputHandlerProxy::EventDisposition HandleInputEventAndFlushEventQueue(
    testing::StrictMock<MockInputHandler>& mock_input_handler,
    TestInputHandlerProxy* input_handler,
    const WebInputEvent& event) {}

class InputHandlerProxyEventQueueTest : public testing::Test {};

// Tests that changing source devices mid gesture scroll is handled gracefully.
// For example, when a touch scroll is in progress and the user initiates a
// scrollbar scroll before the touch scroll has had a chance to dispatch a GSE.
TEST_P(InputHandlerProxyTest, NestedGestureBasedScrollsDifferentSourceDevice) {}

TEST_P(InputHandlerProxyTest, MouseWheelNoListener) {}

TEST_P(InputHandlerProxyTest, MouseWheelPassiveListener) {}

TEST_P(InputHandlerProxyTest, MouseWheelBlockingListener) {}

TEST_P(InputHandlerProxyTest, MouseWheelBlockingAndPassiveListener) {}

TEST_P(InputHandlerProxyTest, MouseWheelEventOutsideBlockingListener) {}

TEST_P(InputHandlerProxyTest,
       MouseWheelEventOutsideBlockingListenerWithPassiveListener) {}

// Tests that changing source devices when an animated scroll is in progress
// ends the current scroll offset animation and ensures that a new one gets
// created.
TEST_P(InputHandlerProxyTest, ScrollbarScrollEndOnDeviceChange) {}

void InputHandlerProxyTest::GestureScrollStarted() {}
TEST_P(InputHandlerProxyTest, GestureScrollStarted) {}

TEST_P(InputHandlerProxyTest, GestureScrollIgnored) {}

TEST_P(InputHandlerProxyTest, GestureScrollByPage) {}

TEST_P(InputHandlerProxyTest, GestureScrollBeginThatTargetViewport) {}

void InputHandlerProxyTest::FlingAndSnap() {}

TEST_P(InputHandlerProxyTest, SnapFlingIgnoresFollowingGSUAndGSE) {}

TEST_P(InputHandlerProxyTest, GesturePinch) {}

TEST_P(InputHandlerProxyTest,
       GestureScrollOnImplThreadFlagClearedAfterScrollEnd) {}

TEST_P(InputHandlerProxyTest,
       BeginScrollWhenGestureScrollOnImplThreadFlagIsSet) {}

TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {}

// Tests that multiple mousedown(s) on scrollbar are handled gracefully and
// don't fail any DCHECK(s).
TEST_F(InputHandlerProxyEventQueueTest,
       NestedGestureBasedScrollsSameSourceDevice) {}

// Tests that the allowed touch action is correctly set when a touch is made
// non-blocking due to an ongoing fling. https://crbug.com/1048098.
TEST_F(InputHandlerProxyEventQueueTest, AckTouchActionNonBlockingForFling) {}

TEST_P(InputHandlerProxyTest, HitTestTouchEventNullTouchAction) {}

TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) {}

TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {}

TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPassivePositive) {}

TEST_P(InputHandlerProxyTest, TouchTrackingEndsOnCancel) {}

TEST_P(InputHandlerProxyTest, TouchStartPassiveAndTouchEndBlocking) {}

TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {}

TEST_P(InputHandlerProxyTest, UpdateBrowserControlsState) {}

class UnifiedScrollingInputHandlerProxyTest : public testing::Test {};

// Test that when a main thread hit test is requested, the InputHandlerProxy
// starts queueing incoming gesture event and the compositor queue is blocked
// until the hit test is satisfied.
TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestRequired) {}

// Test to ensure that a main thread hit test sets the correct flags on the
// re-injected GestureScrollBegin.
TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestEvent) {}

// Test to ensure that a main thread hit test counts the correct number of
// scrolls for metrics.
TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestMetrics) {}

// Test the case where a main thread hit test is in progress on the main thread
// and a GSE and new GSB arrive.
TEST_F(UnifiedScrollingInputHandlerProxyTest,
       ScrollEndAndBeginsDuringMainThreadHitTest) {}

// Test the case where a main thread hit test returns a null element_id. In
// this case we should reset the state and unblock the queue.
TEST_F(UnifiedScrollingInputHandlerProxyTest, MainThreadHitTestFailed) {}

TEST(SynchronousInputHandlerProxyTest, StartupShutdown) {}

TEST(SynchronousInputHandlerProxyTest, UpdateRootLayerState) {}

TEST(SynchronousInputHandlerProxyTest, SetOffset) {}

TEST_F(InputHandlerProxyEventQueueTest,
       MouseEventOnScrollbarInitiatesGestureScroll) {}

TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {}

#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
    defined(MEMORY_SANITIZER) || defined(UNDEFINED_SANITIZER)
// Flaky under sanitizers and in other "slow" bot configs:
// https://crbug.com/1029250
#define MAYBE_VSyncAlignedGestureScrollPinchScroll
#else
#define MAYBE_VSyncAlignedGestureScrollPinchScroll
#endif

TEST_F(InputHandlerProxyEventQueueTest,
       MAYBE_VSyncAlignedGestureScrollPinchScroll) {}

TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) {}

TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceScrollAndPinch) {}

TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedCoalesceTouchpadPinch) {}

TEST_F(InputHandlerProxyEventQueueTest, OriginalEventsTracing) {}

TEST_F(InputHandlerProxyEventQueueTest, TouchpadGestureScrollEndFlushQueue) {}

TEST_F(InputHandlerProxyEventQueueTest, CoalescedLatencyInfo) {}

TEST_F(InputHandlerProxyEventQueueTest, ScrollPredictorTest) {}

// Test deliver input w/o prediction enabled.
TEST_F(InputHandlerProxyEventQueueTest, DeliverInputWithHighLatencyMode) {}

TEST_F(InputHandlerProxyEventQueueTest, KeyEventAttribution) {}

TEST_F(InputHandlerProxyEventQueueTest, MouseEventAttribution) {}

TEST_F(InputHandlerProxyEventQueueTest, MouseWheelEventAttribution) {}

// Verify that the first point in a touch event is used for performing event
// attribution.
TEST_F(InputHandlerProxyEventQueueTest, TouchEventAttribution) {}

TEST_F(InputHandlerProxyEventQueueTest, GestureEventAttribution) {}

class InputHandlerProxyMainThreadScrollingReasonTest
    : public InputHandlerProxyTest {};

// Bucket 0: non-main-thread scrolls
// Bucket 1: main-thread scrolls for any reason.
#define EXPECT_NON_MAIN_THREAD_GESTURE_SCROLL_SAMPLE()
#define EXPECT_NON_MAIN_THREAD_WHEEL_SCROLL_SAMPLE()
#define EXPECT_MAIN_THREAD_GESTURE_SCROLL_SAMPLE(reason)
#define EXPECT_MAIN_THREAD_WHEEL_SCROLL_SAMPLE(reason)
#define EXPECT_MAIN_THREAD_WHEEL_SCROLL_SAMPLE_2(reason1, reason2)

// Tests GetBucketSample() returns the corresponding values defined in
// enums.xml, to ensure correctness of the tests using the function.
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, ReasonToBucket) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       GestureScrollNotScrollOnMain) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       GestureScrollTouchEventHandlerRegion) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       ImplHandled_MainThreadHitTest) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       ImplHandled_MainThreadRepaint) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       WheelScrollNotScrollingOnMain) {}

TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
       WheelScrollWheelEventHandlerRegion) {}

class InputHandlerProxyTouchScrollbarTest : public InputHandlerProxyTest {};

TEST_P(InputHandlerProxyTouchScrollbarTest,
       TouchOnScrollbarIsHandledByCompositorThread) {}

const auto kTestCombinations =;

const auto kSuffixGenerator =::string name =;

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

}  // namespace test
}  // namespace blink