summaryrefslogtreecommitdiffstats
path: root/cc/surfaces
diff options
context:
space:
mode:
authorfsamuel <fsamuel@chromium.org>2015-10-05 17:57:05 -0700
committerCommit bot <commit-bot@chromium.org>2015-10-06 00:57:53 +0000
commitbd4d66ea87a1fa3b41cbf5b73661e5b74928a3a4 (patch)
treea96ee00dc29145d4331e536c597a5acc96253e8b /cc/surfaces
parent981b371bf42e3f5d53f3c06b272d974cb11c7f1f (diff)
downloadchromium_src-bd4d66ea87a1fa3b41cbf5b73661e5b74928a3a4.zip
chromium_src-bd4d66ea87a1fa3b41cbf5b73661e5b74928a3a4.tar.gz
chromium_src-bd4d66ea87a1fa3b41cbf5b73661e5b74928a3a4.tar.bz2
Surface hit testing: Introduce GetTransformToTargetSurface
In order to support pointer capture, we need to be able to transform points to a target surface's space even if the point no longer falls within the bounds of the target surface. BUG=533161 CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel TBR=jbauman@chromium.org Review URL: https://codereview.chromium.org/1383283002 Cr-Commit-Position: refs/heads/master@{#352496}
Diffstat (limited to 'cc/surfaces')
-rw-r--r--cc/surfaces/surface_hittest.cc104
-rw-r--r--cc/surfaces/surface_hittest.h22
-rw-r--r--cc/surfaces/surface_hittest_unittest.cc240
3 files changed, 275 insertions, 91 deletions
diff --git a/cc/surfaces/surface_hittest.cc b/cc/surfaces/surface_hittest.cc
index 3a3864e..752a708 100644
--- a/cc/surfaces/surface_hittest.cc
+++ b/cc/surfaces/surface_hittest.cc
@@ -22,20 +22,34 @@ SurfaceHittest::SurfaceHittest(SurfaceManager* manager) : manager_(manager) {}
SurfaceHittest::~SurfaceHittest() {}
-SurfaceId SurfaceHittest::GetTargetSurfaceAtPoint(SurfaceId surface_id,
+SurfaceId SurfaceHittest::GetTargetSurfaceAtPoint(SurfaceId root_surface_id,
const gfx::Point& point,
gfx::Transform* transform) {
- SurfaceId hittest_surface_id = surface_id;
+ SurfaceId out_surface_id = root_surface_id;
+
// Reset the output transform to identity.
if (transform)
*transform = gfx::Transform();
std::set<const RenderPass*> referenced_passes;
- GetTargetSurfaceAtPointInternal(surface_id, RenderPassId(), point,
- &referenced_passes, &hittest_surface_id,
+ GetTargetSurfaceAtPointInternal(root_surface_id, RenderPassId(), point,
+ &referenced_passes, &out_surface_id,
transform);
- return hittest_surface_id;
+ return out_surface_id;
+}
+
+bool SurfaceHittest::GetTransformToTargetSurface(SurfaceId root_surface_id,
+ SurfaceId target_surface_id,
+ gfx::Transform* transform) {
+ // Reset the output transform to identity.
+ if (transform)
+ *transform = gfx::Transform();
+
+ std::set<const RenderPass*> referenced_passes;
+ return GetTransformToTargetSurfaceInternal(root_surface_id, target_surface_id,
+ RenderPassId(), &referenced_passes,
+ transform);
}
bool SurfaceHittest::GetTargetSurfaceAtPointInternal(
@@ -120,6 +134,86 @@ bool SurfaceHittest::GetTargetSurfaceAtPointInternal(
return false;
}
+bool SurfaceHittest::GetTransformToTargetSurfaceInternal(
+ SurfaceId root_surface_id,
+ SurfaceId target_surface_id,
+ const RenderPassId& render_pass_id,
+ std::set<const RenderPass*>* referenced_passes,
+ gfx::Transform* out_transform) {
+ if (root_surface_id == target_surface_id) {
+ *out_transform = gfx::Transform();
+ return true;
+ }
+
+ const RenderPass* render_pass =
+ GetRenderPassForSurfaceById(root_surface_id, render_pass_id);
+ if (!render_pass)
+ return false;
+
+ // To avoid an infinite recursion, we need to skip the RenderPass if it's
+ // already been referenced.
+ if (referenced_passes->find(render_pass) != referenced_passes->end())
+ return false;
+
+ referenced_passes->insert(render_pass);
+
+ // The |transform_to_root_target| matrix cannot be inverted if it has a
+ // z-scale of 0 or due to floating point errors.
+ gfx::Transform transform_from_root_target;
+ if (!render_pass->transform_to_root_target.GetInverse(
+ &transform_from_root_target)) {
+ return false;
+ }
+
+ for (const DrawQuad* quad : render_pass->quad_list) {
+ if (quad->material == DrawQuad::SURFACE_CONTENT) {
+ gfx::Transform target_to_quad_transform;
+ if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
+ &target_to_quad_transform)) {
+ return false;
+ }
+
+ const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
+ if (surface_quad->surface_id == target_surface_id) {
+ *out_transform = target_to_quad_transform * transform_from_root_target;
+ return true;
+ }
+
+ // This isn't the target surface. Let's recurse deeper to see if we can
+ // find the |target_surface_id| there.
+ gfx::Transform transform_to_child_space;
+ if (GetTransformToTargetSurfaceInternal(
+ surface_quad->surface_id, target_surface_id, RenderPassId(),
+ referenced_passes, &transform_to_child_space)) {
+ *out_transform = transform_to_child_space * target_to_quad_transform *
+ transform_from_root_target;
+ return true;
+ }
+ continue;
+ }
+
+ if (quad->material == DrawQuad::RENDER_PASS) {
+ // We've hit a RenderPassDrawQuad, we need to recurse into this
+ // RenderPass.
+ const RenderPassDrawQuad* render_quad =
+ RenderPassDrawQuad::MaterialCast(quad);
+
+ gfx::Transform transform_to_child_space;
+ if (GetTransformToTargetSurfaceInternal(
+ root_surface_id, target_surface_id, render_quad->render_pass_id,
+ referenced_passes, &transform_to_child_space)) {
+ *out_transform = transform_to_child_space;
+ return true;
+ }
+
+ continue;
+ }
+ }
+
+ // The target surface was not found.
+ return false;
+}
+
const RenderPass* SurfaceHittest::GetRenderPassForSurfaceById(
SurfaceId surface_id,
const RenderPassId& render_pass_id) {
diff --git a/cc/surfaces/surface_hittest.h b/cc/surfaces/surface_hittest.h
index b5e1a67..60fa893 100644
--- a/cc/surfaces/surface_hittest.h
+++ b/cc/surfaces/surface_hittest.h
@@ -28,13 +28,20 @@ class CC_SURFACES_EXPORT SurfaceHittest {
explicit SurfaceHittest(SurfaceManager* manager);
~SurfaceHittest();
- // Hittests against Surface with SurfaceId |surface_id|, return the contained
- // surface that the point is hitting and the |transformed_point| in the
- // surface space.
- SurfaceId GetTargetSurfaceAtPoint(SurfaceId surface_id,
+ // Returns the target surface that falls underneath the provided |point|.
+ // Also returns the |transform| to convert the |point| to the target surface's
+ // space.
+ SurfaceId GetTargetSurfaceAtPoint(SurfaceId root_surface_id,
const gfx::Point& point,
gfx::Transform* transform);
+ // Returns whether the target surface falls inside the provide root surface.
+ // Returns the |transform| to convert points from the root surface coordinate
+ // space to the target surface coordinate space.
+ bool GetTransformToTargetSurface(SurfaceId root_surface_id,
+ SurfaceId target_surface_id,
+ gfx::Transform* transform);
+
private:
bool GetTargetSurfaceAtPointInternal(
SurfaceId surface_id,
@@ -44,6 +51,13 @@ class CC_SURFACES_EXPORT SurfaceHittest {
SurfaceId* out_surface_id,
gfx::Transform* out_transform);
+ bool GetTransformToTargetSurfaceInternal(
+ SurfaceId root_surface_id,
+ SurfaceId target_surface_id,
+ const RenderPassId& render_pass_id,
+ std::set<const RenderPass*>* referenced_passes,
+ gfx::Transform* out_transform);
+
const RenderPass* GetRenderPassForSurfaceById(
SurfaceId surface_id,
const RenderPassId& render_pass_id);
diff --git a/cc/surfaces/surface_hittest_unittest.cc b/cc/surfaces/surface_hittest_unittest.cc
index a7f373f..ac9e3bc 100644
--- a/cc/surfaces/surface_hittest_unittest.cc
+++ b/cc/surfaces/surface_hittest_unittest.cc
@@ -23,6 +23,35 @@ namespace cc {
namespace {
+struct TestCase {
+ SurfaceId input_surface_id;
+ gfx::Point input_point;
+ SurfaceId expected_output_surface_id;
+ gfx::Point expected_output_point;
+};
+
+void RunTests(SurfaceManager* manager, TestCase* tests, size_t test_count) {
+ SurfaceHittest hittest(manager);
+ 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_output_surface_id,
+ hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point,
+ &transform));
+ transform.TransformPoint(&point);
+ EXPECT_EQ(test.expected_output_point, point);
+
+ // 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_output_surface_id,
+ &target_transform));
+ EXPECT_EQ(transform, target_transform);
+ }
+}
+
class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
public:
void ReturnResources(const ReturnedResourceArray& resources) override {}
@@ -178,16 +207,16 @@ TEST(SurfaceHittestTest, Hittest_SingleSurface) {
factory.Create(root_surface_id);
factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(),
SurfaceFactory::DrawCallback());
+ TestCase tests[] = {
+ {
+ root_surface_id,
+ gfx::Point(100, 100),
+ root_surface_id,
+ gfx::Point(100, 100)
+ },
+ };
- {
- SurfaceHittest hittest(&manager);
- gfx::Point point(100, 100);
- gfx::Transform transform;
- EXPECT_EQ(root_surface_id, hittest.GetTargetSurfaceAtPoint(
- root_surface_id, point, &transform));
- transform.TransformPoint(&point);
- EXPECT_EQ(gfx::Point(100, 100), point);
- }
+ RunTests(&manager, tests, sizeof(tests) / sizeof(*tests));
factory.Destroy(root_surface_id);
}
@@ -209,9 +238,9 @@ TEST(SurfaceHittestTest, Hittest_ChildSurface) {
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),
+ 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);
@@ -232,8 +261,10 @@ TEST(SurfaceHittestTest, Hittest_ChildSurface) {
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),
+ 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.
@@ -241,33 +272,80 @@ TEST(SurfaceHittestTest, Hittest_ChildSurface) {
factory.SubmitCompositorFrame(child_surface_id, child_frame.Pass(),
SurfaceFactory::DrawCallback());
- struct Test {
- SurfaceId input_surface_id;
- gfx::Point input_point;
- SurfaceId expected_output_surface_id;
- gfx::Point expected_output_point;
- } tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
- gfx::Point(10, 10)},
- {root_surface_id, gfx::Point(99, 99), root_surface_id,
- gfx::Point(99, 99)},
- {root_surface_id, gfx::Point(100, 100), child_surface_id,
- gfx::Point(50, 50)},
- {root_surface_id, gfx::Point(199, 199), child_surface_id,
- gfx::Point(149, 149)},
- {root_surface_id, gfx::Point(200, 200), root_surface_id,
- gfx::Point(200, 200)},
- {root_surface_id, gfx::Point(290, 290), root_surface_id,
- gfx::Point(290, 290)}};
-
- SurfaceHittest hittest(&manager);
- for (const auto& test : tests) {
- gfx::Point point(test.input_point);
+ TestCase tests[] = {
+ {
+ root_surface_id,
+ gfx::Point(10, 10),
+ root_surface_id,
+ gfx::Point(10, 10)
+ },
+ {
+ root_surface_id,
+ gfx::Point(99, 99),
+ root_surface_id,
+ gfx::Point(99, 99)
+ },
+ {
+ root_surface_id,
+ gfx::Point(100, 100),
+ child_surface_id,
+ gfx::Point(50, 50)
+ },
+ {
+ root_surface_id,
+ gfx::Point(199, 199),
+ child_surface_id,
+ gfx::Point(149, 149)
+ },
+ {
+ root_surface_id,
+ gfx::Point(200, 200),
+ root_surface_id,
+ gfx::Point(200, 200)
+ },
+ {
+ root_surface_id,
+ gfx::Point(290, 290),
+ root_surface_id,
+ gfx::Point(290, 290)
+ }
+ };
+
+ RunTests(&manager, tests, sizeof(tests) / sizeof(*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);
+ factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
+
+ // 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(&manager);
+
+ gfx::Point point(100, 100);
gfx::Transform transform;
- EXPECT_EQ(test.expected_output_surface_id,
- hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point,
+ EXPECT_EQ(root_surface_id,
+ hittest.GetTargetSurfaceAtPoint(root_surface_id, point,
&transform));
transform.TransformPoint(&point);
- EXPECT_EQ(test.expected_output_point, point);
+ EXPECT_EQ(gfx::Point(100, 100), point);
+
+ 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);
}
factory.Destroy(root_surface_id);
@@ -334,34 +412,46 @@ TEST(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
factory.SubmitCompositorFrame(child_surface_id, child_frame.Pass(),
SurfaceFactory::DrawCallback());
- struct Test {
- SurfaceId input_surface_id;
- gfx::Point input_point;
- SurfaceId expected_output_surface_id;
- gfx::Point expected_output_point;
- } tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
- gfx::Point(10, 10)},
- {root_surface_id, gfx::Point(99, 99), root_surface_id,
- gfx::Point(99, 99)},
- {root_surface_id, gfx::Point(100, 100), child_surface_id,
- gfx::Point(50, 50)},
- {root_surface_id, gfx::Point(199, 199), child_surface_id,
- gfx::Point(149, 149)},
- {root_surface_id, gfx::Point(200, 200), root_surface_id,
- gfx::Point(200, 200)},
- {root_surface_id, gfx::Point(290, 290), root_surface_id,
- gfx::Point(290, 290)}};
-
- SurfaceHittest hittest(&manager);
- for (const auto& test : tests) {
- gfx::Point point(test.input_point);
- gfx::Transform transform;
- EXPECT_EQ(test.expected_output_surface_id,
- hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point,
- &transform));
- transform.TransformPoint(&point);
- EXPECT_EQ(test.expected_output_point, point);
- }
+ TestCase tests[] = {
+ {
+ root_surface_id,
+ gfx::Point(10, 10),
+ root_surface_id,
+ gfx::Point(10, 10)
+ },
+ {
+ root_surface_id,
+ gfx::Point(99, 99),
+ root_surface_id,
+ gfx::Point(99, 99)
+ },
+ {
+ root_surface_id,
+ gfx::Point(100, 100),
+ child_surface_id,
+ gfx::Point(50, 50)
+ },
+ {
+ root_surface_id,
+ gfx::Point(199, 199),
+ child_surface_id,
+ gfx::Point(149, 149)
+ },
+ {
+ root_surface_id,
+ gfx::Point(200, 200),
+ root_surface_id,
+ gfx::Point(200, 200)
+ },
+ {
+ root_surface_id,
+ gfx::Point(290, 290),
+ root_surface_id,
+ gfx::Point(290, 290)
+ }
+ };
+
+ RunTests(&manager, tests, sizeof(tests) / sizeof(*tests));
factory.Destroy(root_surface_id);
factory.Destroy(child_surface_id);
@@ -421,12 +511,7 @@ TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(),
SurfaceFactory::DrawCallback());
- struct Test {
- SurfaceId input_surface_id;
- gfx::Point input_point;
- SurfaceId expected_output_surface_id;
- gfx::Point expected_output_point;
- } tests[] = {
+ TestCase tests[] = {
// These tests just miss the RenderPassDrawQuad.
{
root_surface_id,
@@ -470,16 +555,7 @@ TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
}
};
- SurfaceHittest hittest(&manager);
- for (const auto& test : tests) {
- gfx::Point point(test.input_point);
- gfx::Transform transform;
- EXPECT_EQ(test.expected_output_surface_id,
- hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point,
- &transform));
- transform.TransformPoint(&point);
- EXPECT_EQ(test.expected_output_point, point);
- }
+ RunTests(&manager, tests, sizeof(tests) / sizeof(*tests));
factory.Destroy(root_surface_id);
}