blob: d2ef353423edc3b6d2fed957dcdd5cad802afddb [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include <vector>
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/host/hit_test/hit_test_query.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "components/viz/test/host_frame_sink_manager_test_api.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/compositor/test/test_image_transport_factory.h"
#include "content/browser/renderer_host/frame_connector_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/render_widget_targeter.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/mock_render_widget_host_delegate.h"
#include "content/test/mock_widget_impl.h"
#include "content/test/test_render_view_host.h"
#include "services/viz/public/interfaces/hit_test/input_target_client.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
class MockFrameConnectorDelegate : public FrameConnectorDelegate {
public:
MockFrameConnectorDelegate(bool use_zoom_for_device_scale_factor)
: FrameConnectorDelegate(use_zoom_for_device_scale_factor) {}
~MockFrameConnectorDelegate() override {}
RenderWidgetHostViewBase* GetRootRenderWidgetHostView() override {
return root_view_;
}
void set_root_view(RenderWidgetHostViewBase* root_view) {
root_view_ = root_view;
}
private:
RenderWidgetHostViewBase* root_view_;
DISALLOW_COPY_AND_ASSIGN(MockFrameConnectorDelegate);
};
// Used as a target for the RenderWidgetHostInputEventRouter. We record what
// events were forwarded to us in order to verify that the events are being
// routed correctly.
class TestRenderWidgetHostViewChildFrame
: public RenderWidgetHostViewChildFrame {
public:
explicit TestRenderWidgetHostViewChildFrame(RenderWidgetHost* widget)
: RenderWidgetHostViewChildFrame(widget),
frame_sink_id_(2, 1),
last_gesture_seen_(blink::WebInputEvent::kUndefined) {}
~TestRenderWidgetHostViewChildFrame() override = default;
void ProcessGestureEvent(const blink::WebGestureEvent& event,
const ui::LatencyInfo&) override {
last_gesture_seen_ = event.GetType();
}
void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) override {
unique_id_for_last_touch_ack_ = touch.event.unique_touch_event_id;
}
void SetBounds(const gfx::Rect& rect) override { bounds_ = rect; }
gfx::Rect GetViewBounds() const override { return bounds_; }
const viz::FrameSinkId& GetFrameSinkId() const override {
return frame_sink_id_;
}
blink::WebInputEvent::Type last_gesture_seen() { return last_gesture_seen_; }
uint32_t last_id_for_touch_ack() { return unique_id_for_last_touch_ack_; }
void Reset() { last_gesture_seen_ = blink::WebInputEvent::kUndefined; }
private:
gfx::Rect bounds_;
viz::FrameSinkId frame_sink_id_;
blink::WebInputEvent::Type last_gesture_seen_;
uint32_t unique_id_for_last_touch_ack_ = 0;
};
// The RenderWidgetHostInputEventRouter uses the root RWHV for hittesting, so
// here we stub out the hittesting logic so we can control which RWHV will be
// the result of a hittest by the RWHIER.
class MockRootRenderWidgetHostView : public TestRenderWidgetHostView {
public:
MockRootRenderWidgetHostView(
RenderWidgetHost* rwh,
std::map<RenderWidgetHostViewBase*, viz::FrameSinkId>& frame_sink_id_map)
: TestRenderWidgetHostView(rwh),
frame_sink_id_(1, 1),
frame_sink_id_map_(frame_sink_id_map),
current_hittest_result_(nullptr),
force_query_renderer_on_hit_test_(false),
last_gesture_seen_(blink::WebInputEvent::kUndefined) {}
~MockRootRenderWidgetHostView() override {}
viz::FrameSinkId FrameSinkIdAtPoint(viz::SurfaceHittestDelegate*,
const gfx::PointF&,
gfx::PointF*,
bool* query_renderer) override {
if (force_query_renderer_on_hit_test_)
*query_renderer = true;
DCHECK(current_hittest_result_)
<< "Must set a Hittest result before calling this function";
return frame_sink_id_map_[current_hittest_result_];
}
bool TransformPointToCoordSpaceForView(
const gfx::PointF& point,
RenderWidgetHostViewBase* target_view,
gfx::PointF* transformed_point,
viz::EventSource source = viz::EventSource::ANY) override {
return true;
}
void ProcessGestureEvent(const blink::WebGestureEvent& event,
const ui::LatencyInfo&) override {
last_gesture_seen_ = event.GetType();
}
void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) override {
unique_id_for_last_touch_ack_ = touch.event.unique_touch_event_id;
}
void SetBounds(const gfx::Rect& rect) override { bounds_ = rect; }
gfx::Rect GetViewBounds() const override { return bounds_; }
const viz::FrameSinkId& GetFrameSinkId() const override {
return frame_sink_id_;
}
viz::FrameSinkId GetRootFrameSinkId() override { return frame_sink_id_; }
blink::WebInputEvent::Type last_gesture_seen() { return last_gesture_seen_; }
uint32_t last_id_for_touch_ack() { return unique_id_for_last_touch_ack_; }
void SetHittestResult(RenderWidgetHostViewBase* view) {
current_hittest_result_ = view;
}
void set_force_query_renderer_on_hit_test(bool force) {
force_query_renderer_on_hit_test_ = force;
}
void Reset() { last_gesture_seen_ = blink::WebInputEvent::kUndefined; }
private:
gfx::Rect bounds_;
viz::FrameSinkId frame_sink_id_;
std::map<RenderWidgetHostViewBase*, viz::FrameSinkId>& frame_sink_id_map_;
RenderWidgetHostViewBase* current_hittest_result_;
bool force_query_renderer_on_hit_test_;
blink::WebInputEvent::Type last_gesture_seen_;
uint32_t unique_id_for_last_touch_ack_ = 0;
};
} // namespace
class RenderWidgetHostInputEventRouterTest : public testing::Test {
public:
RenderWidgetHostInputEventRouterTest() {}
// Initializes the hit testing data required when
// features::IsVizHitTestingEnabled. Where both |view_root_flags| and
// |view_other_flags| are viz::HitTestRegionFlags, representing the type of
// events to be responded to by each view, along with how they are processed.
void InitVizHitTestData(int view_root_flags, int view_other_flags);
protected:
// testing::Test:
void SetUp() override {
browser_context_ = std::make_unique<TestBrowserContext>();
// ImageTransportFactory doesn't exist on Android. This is needed to create
// a RenderWidgetHostViewChildFrame in the test.
#if !defined(OS_ANDROID)
ImageTransportFactory::SetFactory(
std::make_unique<TestImageTransportFactory>());
#endif
process_host1_ =
std::make_unique<MockRenderProcessHost>(browser_context_.get());
process_host2_ =
std::make_unique<MockRenderProcessHost>(browser_context_.get());
mojom::WidgetPtr widget1;
widget_impl1_ =
std::make_unique<MockWidgetImpl>(mojo::MakeRequest(&widget1));
widget_host1_ = std::make_unique<RenderWidgetHostImpl>(
&delegate_, process_host1_.get(), process_host1_->GetNextRoutingID(),
std::move(widget1), false);
mojom::WidgetPtr widget2;
widget_impl2_ =
std::make_unique<MockWidgetImpl>(mojo::MakeRequest(&widget2));
widget_host2_ = std::make_unique<RenderWidgetHostImpl>(
&delegate_, process_host2_.get(), process_host2_->GetNextRoutingID(),
std::move(widget2), false);
view_root_ = std::make_unique<MockRootRenderWidgetHostView>(
widget_host1_.get(), frame_sink_id_map_);
view_other_ = std::make_unique<TestRenderWidgetHostViewChildFrame>(
widget_host2_.get());
test_frame_connector_ = std::make_unique<MockFrameConnectorDelegate>(
false /* use_zoom_for_device_scale_factor */);
test_frame_connector_->set_root_view(view_root_.get());
test_frame_connector_->SetView(view_other_.get());
view_other_->SetFrameConnectorDelegate(test_frame_connector_.get());
// Set up the RWHIER's FrameSinkId to RWHV map so that we can control the
// result of RWHIER's hittesting.
frame_sink_id_map_ = {{view_root_.get(), view_root_->GetFrameSinkId()},
{view_other_.get(), view_other_->GetFrameSinkId()}};
rwhier_.AddFrameSinkIdOwner(frame_sink_id_map_[view_root_.get()],
view_root_.get());
rwhier_.AddFrameSinkIdOwner(frame_sink_id_map_[view_other_.get()],
view_other_.get());
}
void TearDown() override {
view_root_.reset();
view_other_.reset();
base::RunLoop().RunUntilIdle();
#if !defined(OS_ANDROID)
ImageTransportFactory::Terminate();
#endif
}
RenderWidgetHostViewBase* touch_target() {
return rwhier_.touch_target_.target;
}
RenderWidgetHostViewBase* touchscreen_gesture_target() {
return rwhier_.touchscreen_gesture_target_.target;
}
TestBrowserThreadBundle thread_bundle_;
MockRenderWidgetHostDelegate delegate_;
std::unique_ptr<BrowserContext> browser_context_;
std::unique_ptr<viz::HostFrameSinkManagerTestApi>
host_frame_sink_manager_test_api_;
std::unique_ptr<MockRenderProcessHost> process_host1_;
std::unique_ptr<MockRenderProcessHost> process_host2_;
std::unique_ptr<MockWidgetImpl> widget_impl1_;
std::unique_ptr<RenderWidgetHostImpl> widget_host1_;
std::unique_ptr<MockWidgetImpl> widget_impl2_;
std::unique_ptr<RenderWidgetHostImpl> widget_host2_;
std::unique_ptr<MockRootRenderWidgetHostView> view_root_;
std::unique_ptr<TestRenderWidgetHostViewChildFrame> view_other_;
std::unique_ptr<MockFrameConnectorDelegate> test_frame_connector_;
std::map<RenderWidgetHostViewBase*, viz::FrameSinkId> frame_sink_id_map_;
RenderWidgetHostInputEventRouter rwhier_;
private:
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouterTest);
};
void RenderWidgetHostInputEventRouterTest::InitVizHitTestData(
int view_root_flags,
int view_other_flags) {
if (!features::IsVizHitTestingEnabled())
return;
DCHECK(GetHostFrameSinkManager());
// Bounds chosen so that both |view_root_| and |view_other_| occupy (0, 0);
// the default position in WebPointerProperties. This is done as the test
// suite overrides enough of the classic hit testing path that there the
// bounds do not matter. However Viz hit-testing always performs a contains
// check on input events. This allows both views to handle the input
// targetting in the tests below.
view_root_->SetBounds(gfx::Rect(0, 0, 10, 10));
view_other_->SetBounds(gfx::Rect(0, 0, 10, 5));
host_frame_sink_manager_test_api_ =
std::make_unique<viz::HostFrameSinkManagerTestApi>(
GetHostFrameSinkManager());
viz::HostFrameSinkManager::DisplayHitTestQueryMap hit_test_map;
hit_test_map[view_root_->GetFrameSinkId()] =
std::make_unique<viz::HitTestQuery>();
std::vector<viz::AggregatedHitTestRegion> hit_test_data;
uint32_t async_hit_test_reasons_root =
(view_root_flags & viz::HitTestRegionFlags::kHitTestAsk)
? viz::AsyncHitTestReasons::kIrregularClip
: viz::AsyncHitTestReasons::kNotAsyncHitTest;
uint32_t async_hit_test_reasons_other =
(view_other_flags & viz::HitTestRegionFlags::kHitTestAsk)
? viz::AsyncHitTestReasons::kIrregularClip
: viz::AsyncHitTestReasons::kNotAsyncHitTest;
hit_test_data.push_back(viz::AggregatedHitTestRegion(
view_root_->GetFrameSinkId(), view_root_flags,
view_root_->GetViewBounds(), gfx::Transform(), 1,
async_hit_test_reasons_root));
hit_test_data.push_back(viz::AggregatedHitTestRegion(
view_other_->GetFrameSinkId(), view_other_flags,
view_other_->GetViewBounds(), gfx::Transform(), 0,
async_hit_test_reasons_other));
hit_test_map[view_root_->GetFrameSinkId()]
->OnAggregatedHitTestRegionListUpdated(hit_test_data);
host_frame_sink_manager_test_api_->SetDisplayHitTestQuery(
std::move(hit_test_map));
}
// Make sure that when a touch scroll crosses out of the area for a
// RenderWidgetHostView, the RenderWidgetHostInputEventRouter continues to
// route gesture events to the same RWHV until the end of the gesture.
// See crbug.com/739831
TEST_F(RenderWidgetHostInputEventRouterTest,
DoNotChangeTargetViewDuringTouchScrollGesture) {
// Simulate the touch and gesture events produced from scrolling on a
// touchscreen.
// We start the touch in the area for |view_other_|.
view_root_->SetHittestResult(view_other_.get());
// Each view will want to process the touch event.
InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine,
viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine);
blink::WebTouchEvent touch_event(
blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
touch_event.touches_length = 1;
touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
touch_event.unique_touch_event_id = 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(view_other_.get(), touch_target());
blink::WebGestureEvent gesture_event(
blink::WebInputEvent::kGestureTapDown, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::kWebGestureDeviceTouchscreen);
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(view_other_.get(), touchscreen_gesture_target());
EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
view_other_->last_gesture_seen());
EXPECT_NE(blink::WebInputEvent::kGestureTapDown,
view_root_->last_gesture_seen());
touch_event.SetType(blink::WebInputEvent::kTouchMove);
touch_event.touches[0].state = blink::WebTouchPoint::kStateMoved;
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.SetType(blink::WebInputEvent::kGestureTapCancel);
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.SetType(blink::WebInputEvent::kGestureScrollBegin);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.SetType(blink::WebInputEvent::kGestureScrollUpdate);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
// The continuation of the touch moves should maintain their current target of
// |view_other_|, even if they move outside of that view, and into
// |view_root_|.
//
// Since this test is not using actual view sizes, nor event positions, we
// need to setup our hit testing overrides to prevent targeting |view_other_|.
//
// If the target is maintained through the gesture this will pass. If instead
// the hit testing logic is refered to, then this test will fail.
view_root_->SetHittestResult(view_root_.get());
InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine,
viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestIgnore);
view_root_->Reset();
view_other_->Reset();
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(view_other_.get(), touch_target());
EXPECT_EQ(view_other_.get(), touchscreen_gesture_target());
EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate,
view_other_->last_gesture_seen());
EXPECT_NE(blink::WebInputEvent::kGestureScrollUpdate,
view_root_->last_gesture_seen());
touch_event.SetType(blink::WebInputEvent::kTouchEnd);
touch_event.touches[0].state = blink::WebTouchPoint::kStateReleased;
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
gesture_event.SetType(blink::WebInputEvent::kGestureScrollEnd);
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
view_other_->last_gesture_seen());
EXPECT_NE(blink::WebInputEvent::kGestureScrollEnd,
view_root_->last_gesture_seen());
}
// Ensure that when RenderWidgetHostInputEventRouter receives an unexpected
// touch event, it calls the root view's method to Ack the event before
// dropping it.
TEST_F(RenderWidgetHostInputEventRouterTest, EnsureDroppedTouchEventsAreAcked) {
// Send a touch move without a touch start.
blink::WebTouchEvent touch_move_event(
blink::WebInputEvent::kTouchMove, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
touch_move_event.touches_length = 1;
touch_move_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
touch_move_event.unique_touch_event_id = 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_move_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(view_root_->last_id_for_touch_ack(), 1lu);
// Send a touch cancel without a touch start.
blink::WebTouchEvent touch_cancel_event(
blink::WebInputEvent::kTouchCancel, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
touch_cancel_event.touches_length = 1;
touch_cancel_event.touches[0].state = blink::WebTouchPoint::kStateCancelled;
touch_cancel_event.unique_touch_event_id = 2;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_cancel_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(view_root_->last_id_for_touch_ack(), 2lu);
}
TEST_F(RenderWidgetHostInputEventRouterTest, DoNotCoalesceTouchEvents) {
RenderWidgetTargeter* targeter = rwhier_.GetRenderWidgetTargeterForTests();
view_root_->SetHittestResult(view_root_.get());
view_root_->set_force_query_renderer_on_hit_test(true);
// Also force the renderer to be queried.
InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine |
viz::HitTestRegionFlags::kHitTestAsk,
viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine |
viz::HitTestRegionFlags::kHitTestAsk);
// We need to set up a comm pipe, or else the targeter will crash when it
// tries to query the renderer. It doesn't matter that the pipe isn't
// connected on the other end, as we really don't want it to respond anyways.
std::unique_ptr<service_manager::InterfaceProvider> remote_interfaces =
std::make_unique<service_manager::InterfaceProvider>();
viz::mojom::InputTargetClientPtr input_target_client;
remote_interfaces->GetInterface(&input_target_client);
widget_host1_->SetInputTargetClient(std::move(input_target_client));
// Send TouchStart, TouchMove, TouchMove, TouchMove, TouchEnd and make sure
// the targeter doesn't attempt to coalesce.
blink::WebTouchEvent touch_event(
blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
touch_event.touches_length = 1;
touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
touch_event.unique_touch_event_id = 1;
EXPECT_EQ(0u, targeter->num_requests_in_queue_for_testing());
EXPECT_FALSE(targeter->is_request_in_flight_for_testing());
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(0u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
touch_event.SetType(blink::WebInputEvent::kTouchMove);
touch_event.touches[0].state = blink::WebTouchPoint::kStateMoved;
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(1u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(2u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
touch_event.SetType(blink::WebInputEvent::kTouchEnd);
touch_event.touches[0].state = blink::WebTouchPoint::kStateReleased;
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(3u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
}
TEST_F(RenderWidgetHostInputEventRouterTest, DoNotCoalesceGestureEvents) {
RenderWidgetTargeter* targeter = rwhier_.GetRenderWidgetTargeterForTests();
view_root_->SetHittestResult(view_root_.get());
view_root_->set_force_query_renderer_on_hit_test(true);
// Also force the renderer to be queried.
InitVizHitTestData(viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine |
viz::HitTestRegionFlags::kHitTestAsk,
viz::HitTestRegionFlags::kHitTestTouch |
viz::HitTestRegionFlags::kHitTestMine |
viz::HitTestRegionFlags::kHitTestAsk);
// We need to set up a comm pipe, or else the targeter will crash when it
// tries to query the renderer. It doesn't matter that the pipe isn't
// connected on the other end, as we really don't want it to respond anyways.
std::unique_ptr<service_manager::InterfaceProvider> remote_interfaces =
std::make_unique<service_manager::InterfaceProvider>();
viz::mojom::InputTargetClientPtr input_target_client;
remote_interfaces->GetInterface(&input_target_client);
widget_host1_->SetInputTargetClient(std::move(input_target_client));
// Send TouchStart, GestureTapDown, TouchEnd, GestureScrollBegin,
// GestureScrollUpdate (x2), GestureScrollEnd and make sure
// the targeter doesn't attempt to coalesce.
blink::WebTouchEvent touch_event(
blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
touch_event.touches_length = 1;
touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
touch_event.unique_touch_event_id = 1;
EXPECT_EQ(0u, targeter->num_requests_in_queue_for_testing());
EXPECT_FALSE(targeter->is_request_in_flight_for_testing());
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(0u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
blink::WebGestureEvent gesture_event(
blink::WebInputEvent::kGestureTapDown, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::kWebGestureDeviceTouchscreen);
gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(1u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
touch_event.SetType(blink::WebInputEvent::kTouchEnd);
touch_event.touches[0].state = blink::WebTouchPoint::kStateReleased;
touch_event.unique_touch_event_id += 1;
rwhier_.RouteTouchEvent(view_root_.get(), &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(2u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
gesture_event.SetType(blink::WebInputEvent::kGestureScrollBegin);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(3u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
gesture_event.SetType(blink::WebInputEvent::kGestureScrollUpdate);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(4u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
gesture_event.SetType(blink::WebInputEvent::kGestureScrollUpdate);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(5u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
gesture_event.SetType(blink::WebInputEvent::kGestureScrollEnd);
rwhier_.RouteGestureEvent(view_root_.get(), &gesture_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
EXPECT_EQ(6u, targeter->num_requests_in_queue_for_testing());
EXPECT_TRUE(targeter->is_request_in_flight_for_testing());
}
} // namespace content