| // Copyright 2015 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 <stddef.h> |
| |
| #include "base/stl_util.h" |
| #include "components/viz/common/quads/compositor_frame.h" |
| #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" |
| #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" |
| #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" |
| #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" |
| #include "components/viz/service/surfaces/surface.h" |
| #include "components/viz/service/surfaces/surface_hittest.h" |
| #include "components/viz/service/surfaces/surface_manager.h" |
| #include "components/viz/test/compositor_frame_helpers.h" |
| #include "components/viz/test/fake_compositor_frame_sink_client.h" |
| #include "components/viz/test/surface_hittest_test_helpers.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace viz { |
| |
| namespace { |
| |
| constexpr bool kIsRoot = true; |
| constexpr bool kIsChildRoot = false; |
| constexpr bool kNeedsSyncPoints = true; |
| constexpr FrameSinkId kRootFrameSink(2, 0); |
| constexpr FrameSinkId kChildFrameSink(65563, 0); |
| constexpr FrameSinkId kArbitraryFrameSink(1337, 7331); |
| |
| struct TestCase { |
| SurfaceId input_surface_id; |
| gfx::Point input_point; |
| SurfaceId expected_layer_tree_frame_sink_id; |
| gfx::Point expected_output_point; |
| bool query_renderer; |
| }; |
| |
| void RunTests(SurfaceHittestDelegate* delegate, |
| SurfaceManager* manager, |
| TestCase* tests, |
| size_t test_count) { |
| SurfaceHittest hittest(delegate, manager); |
| bool query_renderer; |
| for (size_t i = 0; i < test_count; ++i) { |
| const TestCase& test = tests[i]; |
| gfx::Point point(test.input_point); |
| gfx::Transform transform; |
| EXPECT_EQ(test.expected_layer_tree_frame_sink_id, |
| hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point, |
| &transform, &query_renderer)); |
| transform.TransformPoint(&point); |
| EXPECT_EQ(test.expected_output_point, point); |
| EXPECT_EQ(test.query_renderer, query_renderer); |
| |
| // Verify that GetTransformToTargetSurface returns true and returns the same |
| // transform as returned by GetTargetSurfaceAtPoint. |
| gfx::Transform target_transform; |
| EXPECT_TRUE(hittest.GetTransformToTargetSurface( |
| test.input_surface_id, test.expected_layer_tree_frame_sink_id, |
| &target_transform)); |
| EXPECT_EQ(transform, target_transform); |
| } |
| } |
| |
| } // namespace |
| |
| using namespace test; |
| |
| class SurfaceHittestTest : public testing::Test { |
| public: |
| SurfaceHittestTest() : frame_sink_manager_(&shared_bitmap_manager_) {} |
| ~SurfaceHittestTest() override = default; |
| |
| CompositorFrameSinkSupport& root_support() { return *supports_[0]; } |
| |
| CompositorFrameSinkSupport& child_support() { return *supports_[1]; } |
| |
| SurfaceManager* surface_manager() { |
| return frame_sink_manager_.surface_manager(); |
| } |
| |
| // testing::Test: |
| void SetUp() override { |
| testing::Test::SetUp(); |
| |
| supports_.push_back(std::make_unique<CompositorFrameSinkSupport>( |
| &client_, &frame_sink_manager_, kRootFrameSink, kIsRoot, |
| kNeedsSyncPoints)); |
| supports_.push_back(std::make_unique<CompositorFrameSinkSupport>( |
| &client_, &frame_sink_manager_, kChildFrameSink, kIsChildRoot, |
| kNeedsSyncPoints)); |
| } |
| |
| void TearDown() override { supports_.clear(); } |
| |
| private: |
| ServerSharedBitmapManager shared_bitmap_manager_; |
| FrameSinkManagerImpl frame_sink_manager_; |
| std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_; |
| FakeCompositorFrameSinkClient client_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SurfaceHittestTest); |
| }; |
| |
| // This test verifies that hit testing on a surface that does not exist does |
| // not crash. |
| TEST_F(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Add a reference to a non-existant child surface on the root surface. |
| SurfaceId child_surface_id( |
| kArbitraryFrameSink, |
| LocalSurfaceId(0xdeadbeef, 0xdeadbeef, base::UnguessableToken::Create())); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad(root_pass, gfx::Transform(), root_rect, child_rect, |
| child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| { |
| SurfaceHittest hittest(nullptr, surface_manager()); |
| // It is expected this test will complete without crashes. |
| gfx::Transform transform; |
| bool query_renderer; |
| EXPECT_EQ(root_surface_id, hittest.GetTargetSurfaceAtPoint( |
| root_surface_id, gfx::Point(100, 100), |
| &transform, &query_renderer)); |
| } |
| } |
| |
| TEST_F(SurfaceHittestTest, Hittest_SingleSurface) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| TestCase tests[] = { |
| {root_surface_id, gfx::Point(100, 100), root_surface_id, |
| gfx::Point(100, 100), false}, |
| }; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| } |
| |
| TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Add a reference to the child surface on the root surface. |
| ParentLocalSurfaceIdAllocator child_allocator; |
| child_allocator.GenerateId(); |
| SurfaceId child_surface_id( |
| kChildFrameSink, |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Creates a child surface. |
| RenderPass* child_pass = nullptr; |
| CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass); |
| |
| // Add a solid quad in the child surface. |
| gfx::Rect child_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad( |
| child_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_solid_quad_rect); |
| |
| // Submit the frame. |
| child_support().SubmitCompositorFrame( |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(child_frame)); |
| |
| TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, |
| gfx::Point(10, 10), false}, |
| {root_surface_id, gfx::Point(99, 99), root_surface_id, |
| gfx::Point(99, 99), true}, |
| {root_surface_id, gfx::Point(100, 100), child_surface_id, |
| gfx::Point(50, 50), true}, |
| {root_surface_id, gfx::Point(199, 199), child_surface_id, |
| gfx::Point(149, 149), true}, |
| {root_surface_id, gfx::Point(200, 200), root_surface_id, |
| gfx::Point(200, 200), true}, |
| {root_surface_id, gfx::Point(290, 290), root_surface_id, |
| gfx::Point(290, 290), false}}; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| |
| // Submit another root frame, with a slightly perturbed child Surface. |
| root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Verify that point (100, 100) no longer falls on the child surface. |
| // Verify that the transform to the child surface's space has also shifted. |
| { |
| SurfaceHittest hittest(nullptr, surface_manager()); |
| |
| gfx::Point point(100, 100); |
| gfx::Transform transform; |
| bool query_renderer; |
| EXPECT_EQ(root_surface_id, |
| hittest.GetTargetSurfaceAtPoint(root_surface_id, point, |
| &transform, &query_renderer)); |
| transform.TransformPoint(&point); |
| EXPECT_EQ(gfx::Point(100, 100), point); |
| EXPECT_EQ(query_renderer, true); |
| |
| gfx::Point point_in_target_space(100, 100); |
| gfx::Transform target_transform; |
| EXPECT_TRUE(hittest.GetTransformToTargetSurface( |
| root_surface_id, child_surface_id, &target_transform)); |
| target_transform.TransformPoint(&point_in_target_space); |
| EXPECT_NE(transform, target_transform); |
| EXPECT_EQ(gfx::Point(25, 25), point_in_target_space); |
| } |
| } |
| |
| TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Add a solid quad to the root surface, occluding the child surface. |
| gfx::Rect root_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, root_solid_quad_rect); |
| |
| // Add a reference to the child surface on the root surface. |
| ParentLocalSurfaceIdAllocator child_allocator; |
| child_allocator.GenerateId(); |
| SurfaceId child_surface_id( |
| kChildFrameSink, |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Creates a child surface. |
| RenderPass* child_pass = nullptr; |
| CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass); |
| |
| // Add a solid quad in the child surface. |
| gfx::Rect child_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad( |
| child_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_solid_quad_rect); |
| |
| // Submit the frame. |
| child_support().SubmitCompositorFrame( |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(child_frame)); |
| |
| TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, |
| gfx::Point(10, 10), false}, |
| {root_surface_id, gfx::Point(99, 99), root_surface_id, |
| gfx::Point(99, 99), true}, |
| {root_surface_id, gfx::Point(100, 100), root_surface_id, |
| gfx::Point(100, 100), true}, |
| {root_surface_id, gfx::Point(199, 199), child_surface_id, |
| gfx::Point(149, 149), true}, |
| {root_surface_id, gfx::Point(200, 200), root_surface_id, |
| gfx::Point(200, 200), true}, |
| {root_surface_id, gfx::Point(290, 290), root_surface_id, |
| gfx::Point(290, 290), false}}; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| } |
| |
| // This test verifies that hit testing will progress to the next quad if it |
| // encounters an invalid RenderPassDrawQuad for whatever reason. |
| TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Create a RenderPassDrawQuad to a non-existant RenderPass. |
| int invalid_render_pass_id = 1337; |
| CreateRenderPassDrawQuad(root_pass, gfx::Transform(), root_rect, root_rect, |
| invalid_render_pass_id); |
| |
| // Add a reference to the child surface on the root surface. |
| ParentLocalSurfaceIdAllocator child_allocator; |
| child_allocator.GenerateId(); |
| LocalSurfaceId child_local_surface_id = |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(); |
| SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Creates a child surface. |
| RenderPass* child_pass = nullptr; |
| CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass); |
| |
| // Add a solid quad in the child surface. |
| gfx::Rect child_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad( |
| child_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_solid_quad_rect); |
| |
| // Submit the frame. |
| child_support().SubmitCompositorFrame( |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(child_frame)); |
| |
| TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, |
| gfx::Point(10, 10), false}, |
| {root_surface_id, gfx::Point(99, 99), root_surface_id, |
| gfx::Point(99, 99), true}, |
| {root_surface_id, gfx::Point(100, 100), child_surface_id, |
| gfx::Point(50, 50), true}, |
| {root_surface_id, gfx::Point(199, 199), child_surface_id, |
| gfx::Point(149, 149), true}, |
| {root_surface_id, gfx::Point(200, 200), root_surface_id, |
| gfx::Point(200, 200), true}, |
| {root_surface_id, gfx::Point(290, 290), root_surface_id, |
| gfx::Point(290, 290), false}}; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| } |
| |
| TEST_F(SurfaceHittestTest, Hittest_RenderPassDrawQuad) { |
| // Create a CompositorFrame with two RenderPasses. |
| gfx::Rect root_rect(300, 300); |
| CompositorFrame root_frame = MakeDefaultCompositorFrame(); |
| RenderPassList& render_pass_list = root_frame.render_pass_list; |
| |
| // Create a child RenderPass. |
| int child_render_pass_id = 3; |
| gfx::Transform transform_to_root_target(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, |
| 0.0f, 50.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 1.0f); |
| CreateRenderPass(child_render_pass_id, gfx::Rect(100, 100), |
| transform_to_root_target, &render_pass_list); |
| |
| // Create the root RenderPass. |
| int root_render_pass_id = 2; |
| CreateRenderPass(root_render_pass_id, root_rect, gfx::Transform(), |
| &render_pass_list); |
| |
| RenderPass* root_pass = nullptr; |
| root_pass = root_frame.render_pass_list.back().get(); |
| |
| // Create a RenderPassDrawQuad. |
| gfx::Rect render_pass_quad_rect(100, 100); |
| CreateRenderPassDrawQuad(root_pass, transform_to_root_target, root_rect, |
| render_pass_quad_rect, child_render_pass_id); |
| |
| // Add a solid quad in the child render pass. |
| RenderPass* child_render_pass = root_frame.render_pass_list.front().get(); |
| gfx::Rect child_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad(child_render_pass, gfx::Transform(), |
| gfx::Rect(100, 100), child_solid_quad_rect); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| TestCase tests[] = {// These tests just miss the RenderPassDrawQuad. |
| {root_surface_id, gfx::Point(49, 49), root_surface_id, |
| gfx::Point(49, 49), false}, |
| {root_surface_id, gfx::Point(150, 150), root_surface_id, |
| gfx::Point(150, 150), false}, |
| // These tests just hit the boundaries of the |
| // RenderPassDrawQuad. |
| {root_surface_id, gfx::Point(50, 50), root_surface_id, |
| gfx::Point(50, 50), false}, |
| {root_surface_id, gfx::Point(149, 149), root_surface_id, |
| gfx::Point(149, 149), false}, |
| // These tests fall somewhere in the center of the |
| // RenderPassDrawQuad. |
| {root_surface_id, gfx::Point(99, 99), root_surface_id, |
| gfx::Point(99, 99), false}, |
| {root_surface_id, gfx::Point(100, 100), root_surface_id, |
| gfx::Point(100, 100), false}}; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| } |
| |
| TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Add a reference to the child surface on the root surface. |
| ParentLocalSurfaceIdAllocator child_allocator; |
| child_allocator.GenerateId(); |
| SurfaceId child_surface_id( |
| kChildFrameSink, |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Creates a child surface. |
| RenderPass* child_pass = nullptr; |
| CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass); |
| |
| // Add a solid quad in the child surface. |
| gfx::Rect child_solid_quad_rect(190, 190); |
| CreateSolidColorDrawQuad( |
| child_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 5.0f, 0.0f, 1.0f, 0.0f, 5.0f, 0.0f, 0.0f, |
| 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_solid_quad_rect); |
| |
| // Submit the frame. |
| child_support().SubmitCompositorFrame( |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(child_frame)); |
| |
| TestCase test_expectations_without_insets[] = { |
| {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5), |
| true}, |
| {root_surface_id, gfx::Point(60, 60), child_surface_id, |
| gfx::Point(10, 10), true}, |
| {root_surface_id, gfx::Point(239, 239), child_surface_id, |
| gfx::Point(189, 189), true}, |
| {root_surface_id, gfx::Point(244, 244), child_surface_id, |
| gfx::Point(194, 194), true}, |
| {root_surface_id, gfx::Point(50, 50), root_surface_id, gfx::Point(50, 50), |
| true}, |
| {root_surface_id, gfx::Point(249, 249), root_surface_id, |
| gfx::Point(249, 249), true}, |
| }; |
| |
| TestSurfaceHittestDelegate empty_delegate; |
| RunTests(&empty_delegate, surface_manager(), test_expectations_without_insets, |
| base::size(test_expectations_without_insets)); |
| |
| // Verify that insets have NOT affected hit targeting. |
| EXPECT_EQ(0, empty_delegate.reject_target_overrides()); |
| EXPECT_EQ(0, empty_delegate.accept_target_overrides()); |
| |
| TestCase test_expectations_with_reject_insets[] = { |
| // Point (55, 55) falls outside the child surface due to the insets |
| // introduced above. |
| {root_surface_id, gfx::Point(55, 55), root_surface_id, gfx::Point(55, 55), |
| false}, |
| // These two points still fall within the child surface. |
| {root_surface_id, gfx::Point(60, 60), child_surface_id, |
| gfx::Point(10, 10), true}, |
| {root_surface_id, gfx::Point(239, 239), child_surface_id, |
| gfx::Point(189, 189), true}, |
| // Point (244, 244) falls outside the child surface due to the insets |
| // introduced above. |
| {root_surface_id, gfx::Point(244, 244), root_surface_id, |
| gfx::Point(244, 244), false}, |
| // Next two points also fall within within the insets indroduced above. |
| {root_surface_id, gfx::Point(50, 50), root_surface_id, gfx::Point(50, 50), |
| false}, |
| {root_surface_id, gfx::Point(249, 249), root_surface_id, |
| gfx::Point(249, 249), false}, |
| }; |
| |
| TestSurfaceHittestDelegate reject_delegate; |
| reject_delegate.AddInsetsForRejectSurface(child_surface_id, |
| gfx::Insets(10, 10, 10, 10)); |
| RunTests(&reject_delegate, surface_manager(), |
| test_expectations_with_reject_insets, |
| base::size(test_expectations_with_reject_insets)); |
| |
| // Verify that insets have affected hit targeting. |
| EXPECT_EQ(4, reject_delegate.reject_target_overrides()); |
| EXPECT_EQ(0, reject_delegate.accept_target_overrides()); |
| |
| TestCase test_expectations_with_accept_insets[] = { |
| {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5), |
| true}, |
| {root_surface_id, gfx::Point(60, 60), child_surface_id, |
| gfx::Point(10, 10), true}, |
| {root_surface_id, gfx::Point(239, 239), child_surface_id, |
| gfx::Point(189, 189), true}, |
| {root_surface_id, gfx::Point(244, 244), child_surface_id, |
| gfx::Point(194, 194), true}, |
| // Next two points fall within within the insets indroduced above. |
| {root_surface_id, gfx::Point(50, 50), child_surface_id, gfx::Point(0, 0), |
| true}, |
| {root_surface_id, gfx::Point(249, 249), child_surface_id, |
| gfx::Point(199, 199), true}, |
| }; |
| |
| TestSurfaceHittestDelegate accept_delegate; |
| accept_delegate.AddInsetsForAcceptSurface(child_surface_id, |
| gfx::Insets(5, 5, 5, 5)); |
| RunTests(&accept_delegate, surface_manager(), |
| test_expectations_with_accept_insets, |
| base::size(test_expectations_with_accept_insets)); |
| |
| // Verify that insets have affected hit targeting. |
| EXPECT_EQ(0, accept_delegate.reject_target_overrides()); |
| EXPECT_EQ(2, accept_delegate.accept_target_overrides()); |
| } |
| |
| // Hit test against a child surface that has a non-flat transform. This |
| // verifies that the transform is flattened before hit testing. |
| TEST_F(SurfaceHittestTest, Hittest_ChildSurfaceWithNonFlatTransform) { |
| // Creates a root surface. |
| gfx::Rect root_rect(300, 300); |
| RenderPass* root_pass = nullptr; |
| CompositorFrame root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| |
| // Add a reference to the child surface on the root surface. |
| ParentLocalSurfaceIdAllocator child_allocator; |
| child_allocator.GenerateId(); |
| SurfaceId child_surface_id( |
| kChildFrameSink, |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| gfx::Rect child_rect(200, 200); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 1.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| |
| // Submit the root frame. |
| ParentLocalSurfaceIdAllocator root_allocator; |
| root_allocator.GenerateId(); |
| SurfaceId root_surface_id( |
| kRootFrameSink, |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Creates a child surface. |
| RenderPass* child_pass = nullptr; |
| CompositorFrame child_frame = CreateCompositorFrame(child_rect, &child_pass); |
| |
| // Add a solid quad in the child surface. |
| gfx::Rect child_solid_quad_rect(100, 100); |
| CreateSolidColorDrawQuad( |
| child_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_solid_quad_rect); |
| |
| // Submit the frame. |
| child_support().SubmitCompositorFrame( |
| child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(child_frame)); |
| |
| TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, |
| gfx::Point(10, 10), false}, |
| {root_surface_id, gfx::Point(99, 99), root_surface_id, |
| gfx::Point(99, 99), true}, |
| {root_surface_id, gfx::Point(100, 100), child_surface_id, |
| gfx::Point(50, 50), true}, |
| {root_surface_id, gfx::Point(199, 199), child_surface_id, |
| gfx::Point(149, 149), true}, |
| {root_surface_id, gfx::Point(200, 200), root_surface_id, |
| gfx::Point(200, 200), true}, |
| {root_surface_id, gfx::Point(290, 290), root_surface_id, |
| gfx::Point(290, 290), false}}; |
| |
| RunTests(nullptr, surface_manager(), tests, base::size(tests)); |
| |
| // Submit another root frame, with a slightly perturbed child Surface. |
| root_frame = CreateCompositorFrame(root_rect, &root_pass); |
| CreateSurfaceDrawQuad( |
| root_pass, |
| gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), |
| root_rect, child_rect, child_surface_id); |
| root_support().SubmitCompositorFrame( |
| root_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(), |
| std::move(root_frame)); |
| |
| // Verify that point (100, 100) no longer falls on the child surface. |
| // Verify that the transform to the child surface's space has also shifted. |
| { |
| SurfaceHittest hittest(nullptr, surface_manager()); |
| |
| gfx::Point point(100, 100); |
| gfx::Transform transform; |
| bool query_renderer; |
| EXPECT_EQ(root_surface_id, |
| hittest.GetTargetSurfaceAtPoint(root_surface_id, point, |
| &transform, &query_renderer)); |
| transform.TransformPoint(&point); |
| EXPECT_EQ(gfx::Point(100, 100), point); |
| EXPECT_EQ(query_renderer, true); |
| |
| gfx::Point point_in_target_space(100, 100); |
| gfx::Transform target_transform; |
| EXPECT_TRUE(hittest.GetTransformToTargetSurface( |
| root_surface_id, child_surface_id, &target_transform)); |
| target_transform.TransformPoint(&point_in_target_space); |
| EXPECT_NE(transform, target_transform); |
| EXPECT_EQ(gfx::Point(25, 25), point_in_target_space); |
| } |
| } |
| |
| } // namespace viz |