Index: components/viz/service/hit_test/hit_test_aggregator_unittest.cc |
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d7e0959926c31b80db3a1ff453f40bf3659e2ab0 |
--- /dev/null |
+++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc |
@@ -0,0 +1,940 @@ |
+// 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 "hit_test_aggregator.h" |
+#include "cc/surfaces/frame_sink_id.h" |
+#include "cc/surfaces/local_surface_id.h" |
+#include "cc/surfaces/surface_id.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace viz { |
+namespace hit_test { |
+namespace test { |
+ |
+namespace { |
+ |
+constexpr cc::FrameSinkId kDisplayFrameSink(2, 0); |
+ |
+cc::SurfaceId MakeSurfaceId(const cc::FrameSinkId& frame_sink_id, |
+ uint32_t local_id) { |
+ return cc::SurfaceId( |
+ frame_sink_id, |
+ cc::LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u))); |
+} |
+ |
+} // namespace |
+ |
+using namespace hit_test::mojom; |
+ |
+class HitTestAggregatorTest : public testing::Test { |
+ public: |
+ HitTestAggregatorTest() {} |
+ ~HitTestAggregatorTest() override {} |
+ |
+ // testing::Test: |
+ void SetUp() override {} |
+ void TearDown() override { Reset(); } |
+ |
+ HitTestAggregator aggregator_; |
+ |
+ int count() { |
+ DisplayHitTestRegion* start = |
+ (DisplayHitTestRegion*)aggregator_.read_buffer_.get(); |
+ DisplayHitTestRegion* end = start; |
+ while (end->child_count != kEndOfList) |
+ end++; |
+ |
+ int count = end - start; |
+ return count; |
+ } |
+ |
+ int GetPendingCount() { return aggregator_.pending_.size(); } |
+ int GetActiveCount() { return aggregator_.active_.size(); } |
+ |
+ void CallOnSurfaceWillDraw(cc::SurfaceId surface_id) { |
+ aggregator_.OnSurfaceWillDraw(surface_id); |
+ } |
+ |
+ void Reset() { |
+ DisplayHitTestRegion* regions = |
+ (DisplayHitTestRegion*)aggregator_.write_buffer_.get(); |
+ regions[0].child_count = kEndOfList; |
+ |
+ regions = (DisplayHitTestRegion*)aggregator_.read_buffer_.get(); |
+ regions[0].child_count = kEndOfList; |
+ |
+ aggregator_.pending_.clear(); |
+ aggregator_.active_.clear(); |
+ } |
+ |
+ int GetDisplayHitTestRegionListSize() { return aggregator_.read_size_; } |
+ |
+ DisplayHitTestRegion* GetRegions() { |
+ return (DisplayHitTestRegion*)aggregator_.read_buffer_.get(); |
+ } |
+ |
+ // 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. |
+ int CreateAndSubmitHitTestRegionListWith8Children(int id, int depth) { |
+ cc::SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, id); |
+ id++; |
+ |
+ auto hit_test_region_list = HitTestRegionList::New(); |
+ hit_test_region_list->surface_id = surface_id; |
+ hit_test_region_list->flags = kHitTestMine; |
+ hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ for (int i = 0; i < 8; i++) { |
+ auto hit_test_region = HitTestRegion::New(); |
+ hit_test_region->rect.SetRect(100, 100, 100, 100); |
+ |
+ if (depth > 0) { |
+ hit_test_region->flags = kHitTestChildSurface; |
+ hit_test_region->surface_id = MakeSurfaceId(kDisplayFrameSink, id); |
+ id = CreateAndSubmitHitTestRegionListWith8Children(id, depth - 1); |
+ } else { |
+ hit_test_region->flags = kHitTestMine; |
+ } |
+ hit_test_region_list->regions.push_back(std::move(hit_test_region)); |
+ } |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list)); |
+ return id; |
+ } |
+}; |
+ |
+// TODO(gklassen): Add tests for 3D use cases as suggested by and with |
+// input from rjkroege. |
+ |
+// One surface. |
+// |
+// +----------+ |
+// | | |
+// | | |
+// | | |
+// +----------+ |
+// |
+TEST_F(HitTestAggregatorTest, OneSurface) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ |
+ auto hit_test_region_list = HitTestRegionList::New(); |
+ hit_test_region_list->surface_id = display_surface_id; |
+ hit_test_region_list->flags = kHitTestMine; |
+ hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list)); |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(display_surface_id); |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ aggregator_.Aggregate(display_surface_id); |
+ aggregator_.Swap(); |
+ |
+ // Expect 1 entry routing all events to the one surface (display root). |
+ EXPECT_EQ(count(), 1); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, display_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// One opaque embedder with two regions. |
+// |
+// +e-------------+ |
+// | +r1-+ +r2--+ | |
+// | | | | | | |
+// | | | | | | |
+// | +---+ +----+ | |
+// +--------------+ |
+// |
+TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_r1 = HitTestRegion::New(); |
+ e_hit_test_region_r1->flags = kHitTestMine; |
+ e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400); |
+ |
+ auto e_hit_test_region_r2 = HitTestRegion::New(); |
+ e_hit_test_region_r2->flags = kHitTestMine; |
+ e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r1)); |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r2)); |
+ |
+ // Submit HitTestRegionList. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ // Add Surfaces to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ EXPECT_EQ(count(), 3); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 400)); |
+ EXPECT_EQ(region->child_count, 0); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->rect, gfx::Rect(400, 100, 300, 400)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// One embedder with two children. |
+// |
+// +e-------------+ |
+// | +c1-+ +c2--+ | |
+// | | | | | | |
+// | | | | | | |
+// | +---+ +----+ | |
+// +--------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ cc::SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_c1 = HitTestRegion::New(); |
+ e_hit_test_region_c1->flags = kHitTestChildSurface; |
+ e_hit_test_region_c1->surface_id = c1_surface_id; |
+ e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300); |
+ |
+ auto e_hit_test_region_c2 = HitTestRegion::New(); |
+ e_hit_test_region_c2->flags = kHitTestChildSurface; |
+ e_hit_test_region_c2->surface_id = c2_surface_id; |
+ e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1)); |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c2)); |
+ |
+ auto c1_hit_test_data = HitTestRegionList::New(); |
+ c1_hit_test_data->surface_id = c1_surface_id; |
+ |
+ auto c2_hit_test_data = HitTestRegionList::New(); |
+ c2_hit_test_data->surface_id = c2_surface_id; |
+ |
+ // Submit in unexpected order. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 2); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 3); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(c2_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ CallOnSurfaceWillDraw(c1_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 2); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 3); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 3); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface); |
+ EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 300)); |
+ EXPECT_EQ(region->child_count, 0); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface); |
+ EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(400, 100, 400, 300)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// Occluded child frame (OOPIF). |
+// |
+// +e-----------+ |
+// | +c--+ | |
+// | | +div-+ | |
+// | | | | | |
+// | | +----+ | |
+// | +---+ | |
+// +------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, OccludedChildFrame) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_div = HitTestRegion::New(); |
+ e_hit_test_region_div->flags = kHitTestMine; |
+ e_hit_test_region_div->surface_id = e_surface_id; |
+ e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); |
+ |
+ auto e_hit_test_region_c = HitTestRegion::New(); |
+ e_hit_test_region_c->flags = kHitTestChildSurface; |
+ e_hit_test_region_c->surface_id = c_surface_id; |
+ e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div)); |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c)); |
+ |
+ auto c_hit_test_data = HitTestRegionList::New(); |
+ c_hit_test_data->surface_id = c_surface_id; |
+ c_hit_test_data->flags = kHitTestMine; |
+ c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
+ |
+ // Submit in unexpected order. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 2); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ CallOnSurfaceWillDraw(c_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 2); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 3); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); |
+ EXPECT_EQ(region->child_count, 0); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// Foreground child frame (OOPIF). |
+// Same as the previous test except the child is foreground. |
+// |
+// +e-----------+ |
+// | +c--+ | |
+// | | |div-+ | |
+// | | | | | |
+// | | |----+ | |
+// | +---+ | |
+// +------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, ForegroundChildFrame) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_div = HitTestRegion::New(); |
+ e_hit_test_region_div->flags = kHitTestMine; |
+ e_hit_test_region_div->surface_id = e_surface_id; |
+ e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); |
+ |
+ auto e_hit_test_region_c = HitTestRegion::New(); |
+ e_hit_test_region_c->flags = kHitTestChildSurface; |
+ e_hit_test_region_c->surface_id = c_surface_id; |
+ e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c)); |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div)); |
+ |
+ auto c_hit_test_data = HitTestRegionList::New(); |
+ c_hit_test_data->surface_id = c_surface_id; |
+ c_hit_test_data->flags = kHitTestMine; |
+ c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
+ |
+ // Submit in unexpected order. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 2); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ CallOnSurfaceWillDraw(c_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 2); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 3); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500)); |
+ EXPECT_EQ(region->child_count, 0); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// 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(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ cc::SurfaceId a_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
+ cc::SurfaceId b_surface_id = MakeSurfaceId(kDisplayFrameSink, 4); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_c = HitTestRegion::New(); |
+ e_hit_test_region_c->flags = 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->transform.Translate(200, 100); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c)); |
+ |
+ auto c_hit_test_data = HitTestRegionList::New(); |
+ c_hit_test_data->surface_id = c_surface_id; |
+ c_hit_test_data->flags = kHitTestIgnore; |
+ c_hit_test_data->bounds.SetRect(0, 0, 1600, 800); |
+ |
+ auto c_hit_test_region_a = HitTestRegion::New(); |
+ c_hit_test_region_a->flags = kHitTestChildSurface; |
+ c_hit_test_region_a->surface_id = a_surface_id; |
+ c_hit_test_region_a->rect.SetRect(0, 0, 200, 100); |
+ |
+ auto c_hit_test_region_b = HitTestRegion::New(); |
+ c_hit_test_region_b->flags = kHitTestChildSurface; |
+ c_hit_test_region_b->surface_id = b_surface_id; |
+ c_hit_test_region_b->rect.SetRect(0, 100, 800, 600); |
+ |
+ c_hit_test_data->regions.push_back(std::move(c_hit_test_region_a)); |
+ c_hit_test_data->regions.push_back(std::move(c_hit_test_region_b)); |
+ |
+ auto a_hit_test_data = HitTestRegionList::New(); |
+ a_hit_test_data->surface_id = a_surface_id; |
+ a_hit_test_data->flags = kHitTestMine; |
+ a_hit_test_data->bounds.SetRect(0, 0, 200, 100); |
+ |
+ auto b_hit_test_data = HitTestRegionList::New(); |
+ b_hit_test_data->surface_id = b_surface_id; |
+ b_hit_test_data->flags = kHitTestMine; |
+ b_hit_test_data->bounds.SetRect(0, 100, 800, 600); |
+ |
+ // Submit in unexpected order. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(a_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 2); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(b_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 3); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 4); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(c_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 2); |
+ |
+ CallOnSurfaceWillDraw(b_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 3); |
+ |
+ CallOnSurfaceWillDraw(a_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 4); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 4); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 3); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestIgnore); |
+ EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(200, 100, 1600, 800)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ gfx::Point point(300, 300); |
+ region->transform.TransformPointReverse(&point); |
+ EXPECT_TRUE(point == gfx::Point(100, 200)); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, a_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 200, 100)); |
+ EXPECT_EQ(region->child_count, 0); |
+ |
+ region = ®ions[3]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, b_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 100, 800, 600)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// Three children deep. |
+// |
+// +e------------+ |
+// | +c1-------+ | |
+// | | +c2---+ | | |
+// | | | +c3-| | | |
+// | | | | | | | |
+// | | | +---| | | |
+// | | +-----+ | | |
+// | +---------+ | |
+// +-------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ cc::SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
+ cc::SurfaceId c3_surface_id = MakeSurfaceId(kDisplayFrameSink, 4); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_c1 = HitTestRegion::New(); |
+ e_hit_test_region_c1->flags = kHitTestChildSurface; |
+ e_hit_test_region_c1->surface_id = c1_surface_id; |
+ e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1)); |
+ |
+ auto c1_hit_test_data = HitTestRegionList::New(); |
+ c1_hit_test_data->surface_id = c1_surface_id; |
+ c1_hit_test_data->flags = kHitTestMine; |
+ c1_hit_test_data->bounds.SetRect(0, 0, 600, 600); |
+ |
+ auto c1_hit_test_region_c2 = HitTestRegion::New(); |
+ c1_hit_test_region_c2->flags = kHitTestChildSurface; |
+ c1_hit_test_region_c2->surface_id = c2_surface_id; |
+ c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500); |
+ |
+ c1_hit_test_data->regions.push_back(std::move(c1_hit_test_region_c2)); |
+ |
+ auto c2_hit_test_data = HitTestRegionList::New(); |
+ c2_hit_test_data->surface_id = c2_surface_id; |
+ c2_hit_test_data->flags = kHitTestMine; |
+ c2_hit_test_data->bounds.SetRect(0, 0, 400, 400); |
+ |
+ auto c2_hit_test_region_c3 = HitTestRegion::New(); |
+ c2_hit_test_region_c3->flags = kHitTestChildSurface; |
+ c2_hit_test_region_c3->surface_id = c3_surface_id; |
+ c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300); |
+ |
+ c2_hit_test_data->regions.push_back(std::move(c2_hit_test_region_c3)); |
+ |
+ auto c3_hit_test_data = HitTestRegionList::New(); |
+ c3_hit_test_data->surface_id = c3_surface_id; |
+ c3_hit_test_data->flags = kHitTestMine; |
+ c3_hit_test_data->bounds.SetRect(0, 0, 200, 200); |
+ |
+ // Submit in unexpected order. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c3_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 2); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 3); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 4); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(c2_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ CallOnSurfaceWillDraw(c1_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 2); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 3); |
+ |
+ CallOnSurfaceWillDraw(c3_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 4); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 4); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 3); |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 700, 700)); |
+ EXPECT_EQ(region->child_count, 2); |
+ |
+ region = ®ions[2]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 500, 500)); |
+ EXPECT_EQ(region->child_count, 1); |
+ |
+ region = ®ions[3]; |
+ EXPECT_EQ(region->flags, kHitTestChildSurface | kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, c3_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(100, 100, 300, 300)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// Missing / late child. |
+// |
+// +e-----------+ |
+// | +c--+ | |
+// | | |div-+ | |
+// | | | | | |
+// | | |----+ | |
+// | +---+ | |
+// +------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, MissingChildFrame) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ cc::SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ cc::SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
+ |
+ auto e_hit_test_data = HitTestRegionList::New(); |
+ e_hit_test_data->surface_id = e_surface_id; |
+ e_hit_test_data->flags = kHitTestMine; |
+ e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
+ |
+ auto e_hit_test_region_div = HitTestRegion::New(); |
+ e_hit_test_region_div->flags = kHitTestMine; |
+ e_hit_test_region_div->surface_id = e_surface_id; |
+ e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); |
+ |
+ auto e_hit_test_region_c = HitTestRegion::New(); |
+ e_hit_test_region_c->flags = kHitTestChildSurface; |
+ e_hit_test_region_c->surface_id = c_surface_id; |
+ e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); |
+ |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c)); |
+ e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div)); |
+ |
+ auto c_hit_test_data = HitTestRegionList::New(); |
+ c_hit_test_data->surface_id = c_surface_id; |
+ c_hit_test_data->flags = kHitTestMine; |
+ c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
+ |
+ // Submit in unexpected order, but not the child. |
+ |
+ EXPECT_EQ(GetPendingCount(), 0); |
+ |
+ aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
+ EXPECT_EQ(GetPendingCount(), 1); |
+ |
+ // Surfaces added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ CallOnSurfaceWillDraw(e_surface_id); |
+ EXPECT_EQ(GetActiveCount(), 1); |
+ |
+ // Aggregate and swap. |
+ |
+ aggregator_.Aggregate(e_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ EXPECT_EQ(count(), 2); |
+ |
+ DisplayHitTestRegion* regions = GetRegions(); |
+ |
+ DisplayHitTestRegion* region = nullptr; |
+ |
+ region = ®ions[0]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); |
+ EXPECT_EQ(region->child_count, 1); |
+ |
+ // Child would exist here but it was not included in the Display Frame. |
+ |
+ region = ®ions[1]; |
+ EXPECT_EQ(region->flags, kHitTestMine); |
+ EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); |
+ EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); |
+ EXPECT_EQ(region->child_count, 0); |
+} |
+ |
+// Exceed limits to ensure that bounds and resize work. |
+// |
+// A tree of embedders each with 8 children and 4 levels deep = 4096 regions. |
+// This will exceed initial allocation and force a resize. |
+// |
+// +e--------------------------------------------------------+ |
+// | +c1----------++c2----------++c3----------++c4----------+| |
+// | | +c1--------|| +c1--------|| +c1--------|| +c1--------|| |
+// | | | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| |
+// | | | | || || | | || || | | || || | | || || |
+// | | | +---++---|| | +---++---|| | +---++---|| | +---++---|| |
+// | +------------++------------++------------++------------+| |
+// | +c5----------++c6----------++c7----------++c8----------+| |
+// | | +c1--------|| +c1--------|| +c1--------|| +c1--------|| |
+// | | | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| |
+// | | | | || || | | || || | | || || | | || || |
+// | | | +---++---|| | +---++---|| | +---++---|| | +---++---|| |
+// | +------------++------------++------------++------------+| |
+// +---------------------------------------------------------+ |
+// |
+ |
+TEST_F(HitTestAggregatorTest, ExceedLimits) { |
+ EXPECT_EQ(count(), 0); |
+ |
+ EXPECT_LT(GetDisplayHitTestRegionListSize(), 4096); |
+ |
+ cc::SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+ |
+ int next_surface_id = CreateAndSubmitHitTestRegionListWith8Children(1, 3); |
+ int surface_count = next_surface_id - 1; |
+ |
+ EXPECT_EQ(GetPendingCount(), surface_count); |
+ |
+ // Mark Surfaces as added to DisplayFrame in unexpected order. |
+ |
+ EXPECT_EQ(count(), 0); |
+ EXPECT_EQ(GetActiveCount(), 0); |
+ |
+ for (int i = 1; i <= surface_count; i++) { |
+ cc::SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, i); |
+ CallOnSurfaceWillDraw(surface_id); |
+ } |
+ |
+ EXPECT_EQ(GetActiveCount(), surface_count); |
+ |
+ // Aggregate and swap. |
+ aggregator_.Aggregate(display_surface_id); |
+ EXPECT_EQ(count(), 0); |
+ |
+ aggregator_.Swap(); |
+ |
+ // Expect 4680 regions: |
+ // 8 children 4 levels deep 8*8*8*8 is 4096 |
+ // 1 region for each embedder/surface + 584 |
+ // 1 root + 1 |
+ // ----- |
+ // 4681. |
+ EXPECT_EQ(count(), 4681); |
+ |
+ EXPECT_GE(GetDisplayHitTestRegionListSize(), 4681); |
+} |
+ |
+} // namespace test |
+} // namespace hit_test |
+} // namespace viz |