Add viz-host HitTestQuery.
HitTestQuery finds the hit test target, for a given location, in the
AggregatedHitTestRegion list received from HitTestAggregator.
BUG=732400
TEST=viz_unittests
Review-Url: https://codereview.chromium.org/2933493003
Cr-Commit-Position: refs/heads/master@{#488854}
diff --git a/components/viz/common/hit_test/aggregated_hit_test_region.h b/components/viz/common/hit_test/aggregated_hit_test_region.h
index b90bfb19..ab3997a 100644
--- a/components/viz/common/hit_test/aggregated_hit_test_region.h
+++ b/components/viz/common/hit_test/aggregated_hit_test_region.h
@@ -15,7 +15,7 @@
// A AggregatedHitTestRegion element with child_count of kEndOfList indicates
// the last element and end of the list.
-constexpr int kEndOfList = -1;
+constexpr int32_t kEndOfList = -1;
// An array of AggregatedHitTestRegion elements is used to define the
// aggregated hit-test data for the Display.
@@ -41,7 +41,7 @@
// The number of children including their children below this entry.
// If this element is not matched then child_count elements can be skipped
// to move to the next entry.
- int child_count;
+ int32_t child_count;
};
} // namespace viz
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn
index e5d833e..65beb19 100644
--- a/components/viz/host/BUILD.gn
+++ b/components/viz/host/BUILD.gn
@@ -49,6 +49,7 @@
"//base/test:test_support",
"//cc/ipc:interfaces",
"//cc/surfaces",
+ "//components/viz/host/hit_test:unit_tests",
"//gpu/ipc/host",
"//mojo/public/cpp/bindings",
"//services/ui/gpu/interfaces",
diff --git a/components/viz/host/hit_test/BUILD.gn b/components/viz/host/hit_test/BUILD.gn
new file mode 100644
index 0000000..c60ca0e
--- /dev/null
+++ b/components/viz/host/hit_test/BUILD.gn
@@ -0,0 +1,36 @@
+# 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.
+
+import("//components/viz/viz.gni")
+import("//testing/test.gni")
+
+viz_source_set("hit_test") {
+ sources = [
+ "hit_test_query.cc",
+ "hit_test_query.h",
+ ]
+
+ public_deps = [
+ "//components/viz/common",
+ "//services/viz/hit_test/public/interfaces",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
+
+viz_source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "hit_test_query_unittest.cc",
+ ]
+
+ deps = [
+ ":hit_test",
+ "//base",
+ "//base/test:test_support",
+ "//cc:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/components/viz/host/hit_test/DEPS b/components/viz/host/hit_test/DEPS
new file mode 100644
index 0000000..80523a1
--- /dev/null
+++ b/components/viz/host/hit_test/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+services/viz/hit_test/public/interfaces",
+ "+ui/gfx"
+]
diff --git a/components/viz/host/hit_test/OWNERS b/components/viz/host/hit_test/OWNERS
new file mode 100644
index 0000000..77f21b5
--- /dev/null
+++ b/components/viz/host/hit_test/OWNERS
@@ -0,0 +1 @@
+rjkroege@chromium.org
diff --git a/components/viz/host/hit_test/hit_test_query.cc b/components/viz/host/hit_test/hit_test_query.cc
new file mode 100644
index 0000000..a4bdaa6
--- /dev/null
+++ b/components/viz/host/hit_test/hit_test_query.cc
@@ -0,0 +1,68 @@
+// 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 "components/viz/host/hit_test/hit_test_query.h"
+
+#include "services/viz/hit_test/public/interfaces/hit_test_region_list.mojom.h"
+
+namespace viz {
+
+HitTestQuery::HitTestQuery() = default;
+
+HitTestQuery::~HitTestQuery() = default;
+
+Target HitTestQuery::FindTargetForLocation(
+ const gfx::Point& location_in_root) const {
+ Target target;
+ if (!aggregated_hit_test_region_list_size_)
+ return target;
+
+ FindTargetInRegionForLocation(location_in_root,
+ aggregated_hit_test_region_list_, &target);
+ return target;
+}
+
+bool HitTestQuery::FindTargetInRegionForLocation(
+ const gfx::Point& location_in_parent,
+ AggregatedHitTestRegion* region,
+ Target* target) const {
+ gfx::Point location_transformed(location_in_parent);
+ region->transform.TransformPoint(&location_transformed);
+ if (!region->rect.Contains(location_transformed))
+ return false;
+
+ if (region->child_count < 0 ||
+ region->child_count >
+ (aggregated_hit_test_region_list_ +
+ aggregated_hit_test_region_list_size_ - region - 1)) {
+ return false;
+ }
+ AggregatedHitTestRegion* child_region = region + 1;
+ AggregatedHitTestRegion* child_region_end =
+ child_region + region->child_count;
+ gfx::Point location_in_target(location_transformed);
+ location_in_target.Offset(-region->rect.x(), -region->rect.y());
+ while (child_region < child_region_end) {
+ if (FindTargetInRegionForLocation(location_in_target, child_region,
+ target)) {
+ return true;
+ }
+
+ if (child_region->child_count < 0 ||
+ child_region->child_count >= region->child_count) {
+ return false;
+ }
+ child_region = child_region + child_region->child_count + 1;
+ }
+
+ if (region->flags & mojom::kHitTestMine) {
+ target->frame_sink_id = region->frame_sink_id;
+ target->location_in_target = location_in_target;
+ target->flags = region->flags;
+ return true;
+ }
+ return false;
+}
+
+} // namespace viz
diff --git a/components/viz/host/hit_test/hit_test_query.h b/components/viz/host/hit_test/hit_test_query.h
new file mode 100644
index 0000000..3e3d322
--- /dev/null
+++ b/components/viz/host/hit_test/hit_test_query.h
@@ -0,0 +1,84 @@
+// 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.
+
+#ifndef COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
+#define COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "ui/gfx/geometry/point.h"
+
+namespace viz {
+
+struct Target {
+ FrameSinkId frame_sink_id;
+ // Coordinates in the coordinate system of the target FrameSinkId.
+ gfx::Point location_in_target;
+ // Different flags are defined in services/viz/hit_test/public/interfaces/
+ // hit_test_region_list.mojom.
+ uint32_t flags = 0;
+};
+
+// Finds the target for a given location based on the AggregatedHitTestRegion
+// list aggregated by HitTestAggregator.
+// TODO(riajiang): Handle 3d space cases correctly.
+class HitTestQuery {
+ public:
+ HitTestQuery();
+ ~HitTestQuery();
+
+ // TODO(riajiang): Read from shmem directly once it's set up and delete this
+ // function. For now, use fake data. Also need to validate the data received.
+ // http://crbug.com/746470
+ void set_aggregated_hit_test_region_list(
+ AggregatedHitTestRegion* aggregated_hit_test_region_list,
+ uint32_t aggregated_hit_test_region_list_size) {
+ aggregated_hit_test_region_list_ = aggregated_hit_test_region_list;
+ aggregated_hit_test_region_list_size_ =
+ aggregated_hit_test_region_list_size;
+ }
+
+ // Finds Target for |location_in_root|, including the FrameSinkId of the
+ // target, updated location in the coordinate system of the target and
+ // hit-test flags for the target.
+ // Assumptions about the AggregatedHitTestRegion list received.
+ // 1. The list is in ascending (front to back) z-order.
+ // 2. Children count includes children of children.
+ // 3. After applying transform to the incoming point, point is in the same
+ // coordinate system as the bounds it is comparing against.
+ // For example,
+ // +e-------------+
+ // | +c---------|
+ // | 1 |+a--+ |
+ // | || 2 | |
+ // | |+b--------|
+ // | || |
+ // | || 3 |
+ // +--------------+
+ // In this case, after applying identity transform, 1 is in the coordinate
+ // system of e; apply the transfrom-from-e-to-c and transform-from-c-to-a
+ // then we get 2 in the coordinate system of a; apply the
+ // transfrom-from-e-to-c and transform-from-c-to-b then we get 3 in the
+ // coordinate system of b.
+ Target FindTargetForLocation(const gfx::Point& location_in_root) const;
+
+ private:
+ // Helper function to find |target| for |location_in_parent| in the |region|,
+ // returns true if a target is found and false otherwise. |location_in_parent|
+ // is in the coordinate space of |region|'s parent.
+ bool FindTargetInRegionForLocation(const gfx::Point& location_in_parent,
+ AggregatedHitTestRegion* region,
+ Target* target) const;
+
+ AggregatedHitTestRegion* aggregated_hit_test_region_list_ = nullptr;
+ uint32_t aggregated_hit_test_region_list_size_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestQuery);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
diff --git a/components/viz/host/hit_test/hit_test_query_unittest.cc b/components/viz/host/hit_test/hit_test_query_unittest.cc
new file mode 100644
index 0000000..1f9eadc
--- /dev/null
+++ b/components/viz/host/hit_test/hit_test_query_unittest.cc
@@ -0,0 +1,627 @@
+// 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 "components/viz/host/hit_test/hit_test_query.h"
+
+#include <cstdint>
+
+#include "services/viz/hit_test/public/interfaces/hit_test_region_list.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace test {
+
+class HitTestQueryTest : public testing::Test {
+ public:
+ HitTestQueryTest() = default;
+ ~HitTestQueryTest() override = default;
+
+ HitTestQuery hit_test_query_;
+
+ private:
+ // testing::Test:
+ void SetUp() override {}
+ void TearDown() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestQueryTest);
+};
+
+// One surface.
+//
+// +e---------+
+// | |
+// | |
+// | |
+// +----------+
+//
+TEST_F(HitTestQueryTest, OneSurface) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ gfx::Rect e_bounds = gfx::Rect(0, 0, 600, 600);
+ gfx::Transform transform_e_to_e;
+ AggregatedHitTestRegion aggregated_hit_test_region_list[1] = {
+ {e_id, mojom::kHitTestMine, e_bounds, transform_e_to_e, 0} // e
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 1);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(600, 600);
+ gfx::Point point3(0, 0);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ // point2 is on the bounds of e so no target found.
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(FrameSinkId(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target2.location_in_target);
+ EXPECT_FALSE(target2.flags);
+
+ // There's a valid Target for point3, see Rect::Contains.
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_id, target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+}
+
+// One embedder with two children.
+//
+// +e------------+ Point maps to
+// | +c1-+ +c2---| ----- -------
+// |1| | | | 1 e
+// | | 2 | | 3 | 4 2 c1
+// | +---+ | | 3 c2
+// +-------------+ 4 none
+//
+TEST_F(HitTestQueryTest, OneEmbedderTwoChildren) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId c2_id = FrameSinkId(3, 3);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 400, 400);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_e_to_c2.Translate(-300, -300);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[3] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 2}, // e
+ {c1_id, mojom::kHitTestMine, c1_bounds_in_e, transform_e_to_c1, 0}, // c1
+ {c2_id, mojom::kHitTestMine, c2_bounds_in_e, transform_e_to_c2, 0} // c2
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 3);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(400, 400);
+ gfx::Point point4(650, 350);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(c1_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(c2_id, target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(100, 100), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(FrameSinkId(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target4.location_in_target);
+ EXPECT_FALSE(target4.flags);
+}
+
+// One embedder with a rotated child.
+TEST_F(HitTestQueryTest, OneEmbedderRotatedChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Transform transform_e_to_e, transform_e_to_c;
+ transform_e_to_c.Translate(-100, -100);
+ transform_e_to_c.Skew(2, 3);
+ transform_e_to_c.Scale(.5f, .7f);
+
+ AggregatedHitTestRegion aggregated_hit_test_region_list[2] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 1}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c_bounds_in_e,
+ transform_e_to_c, 0} // c
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 2);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(150, 120); // Point(-22, -12) after transform.
+ gfx::Point point2(550, 400); // Point(185, 194) after transform.
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(c_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(185, 194), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+}
+
+// One embedder with a clipped child with a tab and transparent background.
+//
+// +e-------------+
+// | +c---------| Point maps to
+// | 1 |+a--+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b--------| 2 a
+// | || | 3 e ( transparent area in c )
+// | || 4 | 4 b
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildWithTabAndTransparentBackground) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[4] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2}, // c
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0} // b
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 4);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(403, 103);
+ gfx::Point point4(202, 202);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(a_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_id, target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(b_id, target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
+}
+
+// One embedder with a clipped child with a tab and transparent background, and
+// a child d under that.
+//
+// +e-------------+
+// | +d------|
+// | +c-|-------| Point maps to
+// | 1 |+a|-+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b|-------| 2 a
+// | || | | 3 d
+// | || | 4 | 4 b
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildWithChildUnderneath) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId d_id = FrameSinkId(5, 5);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Rect d_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b, transform_e_to_d;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ transform_e_to_d.Translate(-400, -50);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[5] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 4}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2}, // c
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0}, // b
+ {d_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, d_bounds_in_e,
+ transform_e_to_d, 0} // d
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 5);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(450, 150);
+ gfx::Point point4(202, 202);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(a_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(d_id, target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 100), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(b_id, target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
+}
+
+// One embedder with two clipped children with a tab and transparent background.
+//
+// +e-------------+
+// | +c1--------| Point maps to
+// | 1 |+a--+ | ----- -------
+// | || 2 | 3 | 1 e
+// | |+b--------| 2 a
+// | || | 3 e ( transparent area in c1 )
+// | || 4 | 4 b
+// | +----------| 5 g
+// | +c2--------| 6 e ( transparent area in c2 )
+// | |+g--+ | 7 h
+// | || 5 | 6 |
+// | |+h--------|
+// | || |
+// | || 7 |
+// +--------------+
+//
+TEST_F(HitTestQueryTest, ClippedChildrenWithTabAndTransparentBackground) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId c2_id = FrameSinkId(5, 5);
+ FrameSinkId g_id = FrameSinkId(6, 6);
+ FrameSinkId h_id = FrameSinkId(7, 7);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 1200);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 500);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c1 = gfx::Rect(0, 0, 800, 400);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 500);
+ gfx::Rect g_bounds_in_c2 = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect h_bounds_in_c2 = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_c1_to_b, transform_e_to_c2, transform_c2_to_g,
+ transform_c2_to_h;
+ transform_e_to_c1.Translate(-200, -100);
+ transform_c1_to_b.Translate(0, -100);
+ transform_e_to_c2.Translate(-200, -700);
+ transform_c2_to_h.Translate(0, -100);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[7] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 6}, // e
+ {c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 2}, // c1
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c1,
+ transform_c1_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c1,
+ transform_c1_to_b, 0}, // b
+ {c2_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c2_bounds_in_e, transform_e_to_c2, 2}, // c2
+ {g_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, g_bounds_in_c2,
+ transform_c2_to_g, 0}, // g
+ {h_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, h_bounds_in_c2,
+ transform_c2_to_h, 0} // h
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 7);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+ gfx::Point point3(403, 103);
+ gfx::Point point4(202, 202);
+ gfx::Point point5(250, 750);
+ gfx::Point point6(450, 750);
+ gfx::Point point7(350, 1100);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(a_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_id, target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(b_id, target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(2, 2), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
+
+ Target target5 = hit_test_query_.FindTargetForLocation(point5);
+ EXPECT_EQ(g_id, target5.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target5.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target5.flags);
+
+ Target target6 = hit_test_query_.FindTargetForLocation(point6);
+ EXPECT_EQ(e_id, target6.frame_sink_id);
+ EXPECT_EQ(point6, target6.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target6.flags);
+
+ Target target7 = hit_test_query_.FindTargetForLocation(point7);
+ EXPECT_EQ(h_id, target7.frame_sink_id);
+ EXPECT_EQ(gfx::Point(150, 300), target7.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target7.flags);
+}
+
+// Children that are multiple layers deep.
+//
+// +e--------------------+
+// | +c2--------| Point maps to
+// | +c1------|----+ | ----- -------
+// |1| +a-----|---+| | 1 e
+// | | |+b----|--+|| | 2 g
+// | | ||+g--+| ||| | 3 b
+// | | ||| 2 || 3||| 4 | 4 c2
+// | | ||+---+| ||| |
+// | | |+-----|--+|| |
+// | | +------| --+| |
+// | +--------|----+ |
+// +---------------------+
+//
+TEST_F(HitTestQueryTest, MultipleLayerChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId g_id = FrameSinkId(5, 5);
+ FrameSinkId c2_id = FrameSinkId(6, 6);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 700, 700);
+ gfx::Rect b_bounds_in_a = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect g_bounds_in_b = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_a_to_b, transform_b_to_g, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_a_to_b.Translate(-50, -30);
+ transform_b_to_g.Translate(-150, -200);
+ transform_e_to_c2.Translate(-400, -50);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[6] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 5}, // e
+ {c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3}, // c1
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c1,
+ transform_c1_to_a, 2}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_a,
+ transform_a_to_b, 1}, // b
+ {g_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, g_bounds_in_b,
+ transform_b_to_g, 0}, // g
+ {c2_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c2_bounds_in_e,
+ transform_e_to_c2, 0} // c2
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 6);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(300, 350);
+ gfx::Point point3(550, 350);
+ gfx::Point point4(900, 350);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(g_id, target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(0, 20), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(b_id, target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(400, 220), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(c2_id, target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(500, 300), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
+}
+
+// Multiple layers deep of transparent children.
+//
+// +e--------------------+
+// | +c2--------| Point maps to
+// | +c1------|----+ | ----- -------
+// |1| +a-----|---+| | 1 e
+// | | |+b----|--+|| | 2 e
+// | | ||+g--+| ||| | 3 c2
+// | | ||| 2 || 3||| 4 | 4 c2
+// | | ||+---+| ||| |
+// | | |+-----|--+|| |
+// | | +------| --+| |
+// | +--------|----+ |
+// +---------------------+
+//
+TEST_F(HitTestQueryTest, MultipleLayerTransparentChild) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c1_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId g_id = FrameSinkId(5, 5);
+ FrameSinkId c2_id = FrameSinkId(6, 6);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 1000, 1000);
+ gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c1 = gfx::Rect(0, 0, 700, 700);
+ gfx::Rect b_bounds_in_a = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect g_bounds_in_b = gfx::Rect(0, 0, 200, 200);
+ gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c1, transform_c1_to_a,
+ transform_a_to_b, transform_b_to_g, transform_e_to_c2;
+ transform_e_to_c1.Translate(-100, -100);
+ transform_a_to_b.Translate(-50, -30);
+ transform_b_to_g.Translate(-150, -200);
+ transform_e_to_c2.Translate(-400, -50);
+ AggregatedHitTestRegion aggregated_hit_test_region_list[6] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 5}, // e
+ {c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3}, // c1
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
+ a_bounds_in_c1, transform_c1_to_a, 2}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, b_bounds_in_a,
+ transform_a_to_b, 1}, // b
+ {g_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, g_bounds_in_b,
+ transform_b_to_g, 0}, // g
+ {c2_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, c2_bounds_in_e,
+ transform_e_to_c2, 0} // c2
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list, 6);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(300, 350);
+ gfx::Point point3(450, 350);
+ gfx::Point point4(900, 350);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_id, target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_TRUE(target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(e_id, target2.frame_sink_id);
+ EXPECT_EQ(point2, target2.location_in_target);
+ EXPECT_TRUE(target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(c2_id, target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 300), target3.location_in_target);
+ EXPECT_TRUE(target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(c2_id, target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(500, 300), target4.location_in_target);
+ EXPECT_TRUE(target4.flags);
+}
+
+TEST_F(HitTestQueryTest, InvalidAggregatedHitTestRegionData) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 0, 800, 600);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b;
+ transform_e_to_c.Translate(-200, -100);
+ transform_c_to_b.Translate(0, -100);
+ AggregatedHitTestRegion aggregated_hit_test_region_list_min[4] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, INT32_MIN}, // c
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0} // b
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list_min, 4);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(202, 102);
+
+ // |child_count| is invalid, which is a security fault. For now, check to see
+ // if the returned Target is invalid.
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(FrameSinkId(), target1.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target1.location_in_target);
+ EXPECT_FALSE(target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(FrameSinkId(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target2.location_in_target);
+ EXPECT_FALSE(target2.flags);
+
+ AggregatedHitTestRegion aggregated_hit_test_region_list_max[4] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e,
+ INT32_MAX}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 2}, // c
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0} // b
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list_max, 4);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(FrameSinkId(), target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target3.location_in_target);
+ EXPECT_FALSE(target3.flags);
+
+ AggregatedHitTestRegion aggregated_hit_test_region_list_bigger[4] = {
+ {e_id, mojom::kHitTestMine, e_bounds_in_e, transform_e_to_e, 3}, // e
+ {c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
+ transform_e_to_c, 3}, // c
+ {a_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, a_bounds_in_c,
+ transform_c_to_a, 0}, // a
+ {b_id, mojom::kHitTestChildSurface | mojom::kHitTestMine, b_bounds_in_c,
+ transform_c_to_b, 0} // b
+ };
+ hit_test_query_.set_aggregated_hit_test_region_list(
+ aggregated_hit_test_region_list_bigger, 4);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(FrameSinkId(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target4.location_in_target);
+ EXPECT_FALSE(target4.flags);
+}
+
+} // namespace test
+} // namespace viz
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 470e09b9b..3c7c093 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -155,6 +155,7 @@
"//base/test:test_support",
"//cc:test_support",
"//components/viz/common",
+ "//components/viz/host/hit_test",
"//components/viz/test:test_support",
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_implementation",
diff --git a/components/viz/service/hit_test/DEPS b/components/viz/service/hit_test/DEPS
index e207341..76ad8ea2 100644
--- a/components/viz/service/hit_test/DEPS
+++ b/components/viz/service/hit_test/DEPS
@@ -1,5 +1,10 @@
include_rules = [
- "+components/viz/common",
"+cc/surfaces/surface_observer.h",
"+services/viz/hit_test/public/interfaces",
]
+
+specific_include_rules = {
+ "hit_test_aggregator_unittest.cc": [
+ "+components/viz/host/hit_test/hit_test_query.h",
+ ]
+}
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
index 4a23b4d..8d1cc5e 100644
--- a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
+++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -7,6 +7,7 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/host/hit_test/hit_test_query.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -75,8 +76,6 @@
void SetUp() override {}
void TearDown() override { aggregator_.Reset(); }
- TestHitTestAggregator aggregator_;
-
// Creates a hit test data element with 8 children recursively to
// the specified depth. SurfaceIds are generated in sequential order and
// the method returns the next unused id.
@@ -106,6 +105,9 @@
aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list));
return id;
}
+
+ TestHitTestAggregator aggregator_;
+ HitTestQuery hit_test_query_;
};
// TODO(gklassen): Add tests for 3D use cases as suggested by and with
@@ -155,6 +157,30 @@
EXPECT_EQ(display_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 1);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(1024, 768);
+ gfx::Point point3(0, 0);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(display_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ // point2 is on the bounds of e so no target found.
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(FrameSinkId(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target2.location_in_target);
+ EXPECT_FALSE(target2.flags);
+
+ // There's a valid Target for point3, see Rect::Contains.
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(display_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
}
// One opaque embedder with two regions.
@@ -177,10 +203,12 @@
e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
auto e_hit_test_region_r1 = mojom::HitTestRegion::New();
+ e_hit_test_region_r1->surface_id = e_surface_id;
e_hit_test_region_r1->flags = mojom::kHitTestMine;
e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400);
auto e_hit_test_region_r2 = mojom::HitTestRegion::New();
+ e_hit_test_region_r2->surface_id = e_surface_id;
e_hit_test_region_r2->flags = mojom::kHitTestMine;
e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400);
@@ -229,6 +257,34 @@
EXPECT_EQ(mojom::kHitTestMine, region->flags);
EXPECT_EQ(gfx::Rect(400, 100, 300, 400), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 3);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(400, 400);
+ gfx::Point point4(1200, 350);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(0, 300), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(FrameSinkId(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target4.location_in_target);
+ EXPECT_FALSE(target4.flags);
}
// One embedder with two children.
@@ -330,6 +386,35 @@
EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(400, 100, 400, 300), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 3);
+
+ // All points are in e's coordinate system when we reach this case.
+ // They all go to e since c1 and c2 cannot receive events.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(400, 400);
+ gfx::Point point4(1200, 350);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(point2, target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(FrameSinkId(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(), target4.location_in_target);
+ EXPECT_FALSE(target4.flags);
}
// Occluded child frame (OOPIF).
@@ -424,6 +509,28 @@
EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(100, 100, 200, 500), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 3);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(250, 250);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(c_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
}
// Foreground child frame (OOPIF).
@@ -519,6 +626,34 @@
EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 3);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(99, 200);
+ gfx::Point point2(150, 150);
+ gfx::Point point3(250, 250);
+ gfx::Point point4(350, 300);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(c_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(c_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(150, 150), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(150, 100), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target4.flags);
}
// One embedder with a clipped child with a tab and transparent background.
@@ -549,7 +684,7 @@
auto e_hit_test_region_c = mojom::HitTestRegion::New();
e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
e_hit_test_region_c->surface_id = c_surface_id;
- e_hit_test_region_c->rect.SetRect(200, 100, 1600, 800);
+ e_hit_test_region_c->rect.SetRect(300, 100, 1600, 800);
e_hit_test_region_c->transform.Translate(200, 100);
e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
@@ -638,7 +773,7 @@
region = ®ions[1];
EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestIgnore);
EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
- EXPECT_EQ(gfx::Rect(200, 100, 1600, 800), region->rect);
+ EXPECT_EQ(gfx::Rect(300, 100, 1600, 800), region->rect);
EXPECT_EQ(2, region->child_count);
gfx::Point point(300, 300);
@@ -656,6 +791,34 @@
EXPECT_EQ(b_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(0, 100, 800, 600), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 4);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(100, 50);
+ gfx::Point point3(400, 70);
+ gfx::Point point4(200, 200);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(a_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(0, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(point3, target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(b_surface_id.frame_sink_id(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(100, 100), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
}
// Three children deep.
@@ -790,6 +953,34 @@
EXPECT_EQ(c3_surface_id.frame_sink_id(), region->frame_sink_id);
EXPECT_EQ(gfx::Rect(100, 100, 300, 300), region->rect);
EXPECT_EQ(0, region->child_count);
+
+ hit_test_query_.set_aggregated_hit_test_region_list(regions, 4);
+
+ // All points are in e's coordinate system when we reach this case.
+ gfx::Point point1(1, 1);
+ gfx::Point point2(100, 150);
+ gfx::Point point3(250, 450);
+ gfx::Point point4(450, 550);
+
+ Target target1 = hit_test_query_.FindTargetForLocation(point1);
+ EXPECT_EQ(e_surface_id.frame_sink_id(), target1.frame_sink_id);
+ EXPECT_EQ(point1, target1.location_in_target);
+ EXPECT_EQ(mojom::kHitTestMine, target1.flags);
+
+ Target target2 = hit_test_query_.FindTargetForLocation(point2);
+ EXPECT_EQ(c3_surface_id.frame_sink_id(), target2.frame_sink_id);
+ EXPECT_EQ(gfx::Point(0, 50), target2.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target2.flags);
+
+ Target target3 = hit_test_query_.FindTargetForLocation(point3);
+ EXPECT_EQ(c2_surface_id.frame_sink_id(), target3.frame_sink_id);
+ EXPECT_EQ(gfx::Point(50, 250), target3.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target3.flags);
+
+ Target target4 = hit_test_query_.FindTargetForLocation(point4);
+ EXPECT_EQ(c1_surface_id.frame_sink_id(), target4.frame_sink_id);
+ EXPECT_EQ(gfx::Point(150, 250), target4.location_in_target);
+ EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, target4.flags);
}
// Missing / late child.