Chromium Code Reviews| 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..b6d8b1bd7c98bf03b9e0ff4e523be4b6115b2074 |
| --- /dev/null |
| +++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc |
| @@ -0,0 +1,1015 @@ |
| +// 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/service/hit_test/hit_test_aggregator.h" |
|
danakj
2017/07/14 15:27:37
add empty line below this
gklassen
2017/07/14 16:54:45
Done.
|
| +#include "components/viz/common/frame_sink_id.h" |
| +#include "components/viz/common/local_surface_id.h" |
| +#include "components/viz/common/surface_id.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace viz { |
| + |
| +namespace { |
| + |
| +constexpr FrameSinkId kDisplayFrameSink(2, 0); |
| + |
| +SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) { |
| + return SurfaceId( |
| + frame_sink_id, |
| + LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u))); |
| +} |
| + |
| +} // namespace |
| + |
| +class HitTestAggregatorTest : public testing::Test { |
| + public: |
| + HitTestAggregatorTest() {} |
| + ~HitTestAggregatorTest() override {} |
| + |
| + // testing::Test: |
| + void SetUp() override {} |
| + void TearDown() override { Reset(); } |
| + |
| + HitTestAggregator aggregator_; |
| + |
| + int count() { |
| + AggregatedHitTestRegion* start = |
| + (AggregatedHitTestRegion*)aggregator_.read_buffer_.get(); |
| + AggregatedHitTestRegion* 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(); } |
| + |
| + int GetActiveRegionCount() { return aggregator_.active_region_count_; } |
| + |
| + void CallOnSurfaceWillDraw(SurfaceId surface_id) { |
| + aggregator_.OnSurfaceWillDraw(surface_id); |
| + } |
| + |
| + void CallOnSurfaceDiscarded(SurfaceId surface_id) { |
| + aggregator_.OnSurfaceDiscarded(surface_id); |
| + } |
| + |
| + void Reset() { |
| + AggregatedHitTestRegion* regions = |
| + static_cast<AggregatedHitTestRegion*>(aggregator_.write_buffer_.get()); |
| + regions[0].child_count = kEndOfList; |
| + |
| + regions = (AggregatedHitTestRegion*)aggregator_.read_buffer_.get(); |
|
danakj
2017/07/14 15:27:37
Please look for more c-style casts
gklassen
2017/07/14 16:54:45
( thanks, and sorry - I should have already done t
|
| + regions[0].child_count = kEndOfList; |
| + |
| + aggregator_.pending_.clear(); |
| + aggregator_.active_.clear(); |
| + } |
| + |
| + int GetHitTestRegionListSize() { return aggregator_.read_size_; } |
| + |
| + AggregatedHitTestRegion* GetRegions() { |
| + return (AggregatedHitTestRegion*)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) { |
| + SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, id); |
| + id++; |
| + |
| + auto hit_test_region_list = mojom::HitTestRegionList::New(); |
| + hit_test_region_list->surface_id = surface_id; |
| + hit_test_region_list->flags = mojom::kHitTestMine; |
| + hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + for (int i = 0; i < 8; i++) { |
| + auto hit_test_region = mojom::HitTestRegion::New(); |
| + hit_test_region->rect.SetRect(100, 100, 100, 100); |
| + |
| + if (depth > 0) { |
| + hit_test_region->flags = mojom::kHitTestChildSurface; |
| + hit_test_region->surface_id = MakeSurfaceId(kDisplayFrameSink, id); |
| + id = CreateAndSubmitHitTestRegionListWith8Children(id, depth - 1); |
| + } else { |
| + hit_test_region->flags = mojom::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(0, count()); |
| + |
| + SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + |
| + auto hit_test_region_list = mojom::HitTestRegionList::New(); |
| + hit_test_region_list->surface_id = display_surface_id; |
| + hit_test_region_list->flags = mojom::kHitTestMine; |
| + hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list)); |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(1, GetPendingCount()); |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(display_surface_id); |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + aggregator_.Aggregate(display_surface_id); |
| + aggregator_.Swap(); |
| + |
| + // Expect 1 entry routing all events to the one surface (display root). |
| + EXPECT_EQ(1, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + 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); |
| +} |
| + |
| +// One opaque embedder with two regions. |
| +// |
| +// +e-------------+ |
| +// | +r1-+ +r2--+ | |
| +// | | | | | | |
| +// | | | | | | |
| +// | +---+ +----+ | |
| +// +--------------+ |
| +// |
| +TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_r1 = mojom::HitTestRegion::New(); |
| + 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->flags = mojom::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 mojom::HitTestRegionList. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + // Add Surfaces to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + EXPECT_EQ(3, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(2, region->child_count); |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(gfx::Rect(100, 100, 200, 400), region->rect); |
| + EXPECT_EQ(0, region->child_count); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(gfx::Rect(400, 100, 300, 400), region->rect); |
| + EXPECT_EQ(0, region->child_count); |
| +} |
| + |
| +// One embedder with two children. |
| +// |
| +// +e-------------+ |
| +// | +c1-+ +c2--+ | |
| +// | | | | | | |
| +// | | | | | | |
| +// | +---+ +----+ | |
| +// +--------------+ |
| +// |
| + |
| +TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_c1 = mojom::HitTestRegion::New(); |
| + e_hit_test_region_c1->flags = mojom::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 = mojom::HitTestRegion::New(); |
| + e_hit_test_region_c2->flags = mojom::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 = mojom::HitTestRegionList::New(); |
| + c1_hit_test_data->surface_id = c1_surface_id; |
| + |
| + auto c2_hit_test_data = mojom::HitTestRegionList::New(); |
| + c2_hit_test_data->surface_id = c2_surface_id; |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data)); |
| + EXPECT_EQ(3, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c2_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c1_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(3, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(3, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(2, region->child_count); |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(mojom::kHitTestChildSurface, region->flags); |
| + EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(100, 100, 200, 300), region->rect); |
| + EXPECT_EQ(0, region->child_count); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(mojom::kHitTestChildSurface, region->flags); |
| + 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); |
| +} |
| + |
| +// Occluded child frame (OOPIF). |
| +// |
| +// +e-----------+ |
| +// | +c--+ | |
| +// | | +div-+ | |
| +// | | | | | |
| +// | | +----+ | |
| +// | +---+ | |
| +// +------------+ |
| +// |
| + |
| +TEST_F(HitTestAggregatorTest, OccludedChildFrame) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_div = mojom::HitTestRegion::New(); |
| + e_hit_test_region_div->flags = mojom::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 = 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(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 = mojom::HitTestRegionList::New(); |
| + c_hit_test_data->surface_id = c_surface_id; |
| + c_hit_test_data->flags = mojom::kHitTestMine; |
| + c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(3, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(2, region->child_count); |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + 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); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + 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); |
| +} |
| + |
| +// Foreground child frame (OOPIF). |
| +// Same as the previous test except the child is foreground. |
| +// |
| +// +e-----------+ |
| +// | +c--+ | |
| +// | | |div-+ | |
| +// | | | | | |
| +// | | |----+ | |
| +// | +---+ | |
| +// +------------+ |
| +// |
| + |
| +TEST_F(HitTestAggregatorTest, ForegroundChildFrame) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_div = mojom::HitTestRegion::New(); |
| + e_hit_test_region_div->flags = mojom::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 = 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(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 = mojom::HitTestRegionList::New(); |
| + c_hit_test_data->surface_id = c_surface_id; |
| + c_hit_test_data->flags = mojom::kHitTestMine; |
| + c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(3, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(2, region->child_count); |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + 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); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + 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); |
| +} |
| + |
| +// 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(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + SurfaceId a_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
| + SurfaceId b_surface_id = MakeSurfaceId(kDisplayFrameSink, 4); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + 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->transform.Translate(200, 100); |
| + |
| + e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c)); |
| + |
| + auto c_hit_test_data = mojom::HitTestRegionList::New(); |
| + c_hit_test_data->surface_id = c_surface_id; |
| + c_hit_test_data->flags = mojom::kHitTestIgnore; |
| + c_hit_test_data->bounds.SetRect(0, 0, 1600, 800); |
| + |
| + auto c_hit_test_region_a = mojom::HitTestRegion::New(); |
| + c_hit_test_region_a->flags = mojom::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 = mojom::HitTestRegion::New(); |
| + c_hit_test_region_b->flags = mojom::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 = mojom::HitTestRegionList::New(); |
| + a_hit_test_data->surface_id = a_surface_id; |
| + a_hit_test_data->flags = mojom::kHitTestMine; |
| + a_hit_test_data->bounds.SetRect(0, 0, 200, 100); |
| + |
| + auto b_hit_test_data = mojom::HitTestRegionList::New(); |
| + b_hit_test_data->surface_id = b_surface_id; |
| + b_hit_test_data->flags = mojom::kHitTestMine; |
| + b_hit_test_data->bounds.SetRect(0, 100, 800, 600); |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(a_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(b_hit_test_data)); |
| + EXPECT_EQ(3, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(4, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(b_surface_id); |
| + EXPECT_EQ(3, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(a_surface_id); |
| + EXPECT_EQ(4, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(4, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(3, region->child_count); |
| + |
| + 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(2, region->child_count); |
| + |
| + gfx::Point point(300, 300); |
| + region->transform.TransformPointReverse(&point); |
| + EXPECT_TRUE(point == gfx::Point(100, 200)); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + EXPECT_EQ(a_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 200, 100), region->rect); |
| + EXPECT_EQ(0, region->child_count); |
| + |
| + region = ®ions[3]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + 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); |
| +} |
| + |
| +// Three children deep. |
| +// |
| +// +e------------+ |
| +// | +c1-------+ | |
| +// | | +c2---+ | | |
| +// | | | +c3-| | | |
| +// | | | | | | | |
| +// | | | +---| | | |
| +// | | +-----+ | | |
| +// | +---------+ | |
| +// +-------------+ |
| +// |
| + |
| +TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3); |
| + SurfaceId c3_surface_id = MakeSurfaceId(kDisplayFrameSink, 4); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_c1 = mojom::HitTestRegion::New(); |
| + e_hit_test_region_c1->flags = mojom::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 = mojom::HitTestRegionList::New(); |
| + c1_hit_test_data->surface_id = c1_surface_id; |
| + c1_hit_test_data->flags = mojom::kHitTestMine; |
| + c1_hit_test_data->bounds.SetRect(0, 0, 600, 600); |
| + |
| + auto c1_hit_test_region_c2 = mojom::HitTestRegion::New(); |
| + c1_hit_test_region_c2->flags = mojom::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 = mojom::HitTestRegionList::New(); |
| + c2_hit_test_data->surface_id = c2_surface_id; |
| + c2_hit_test_data->flags = mojom::kHitTestMine; |
| + c2_hit_test_data->bounds.SetRect(0, 0, 400, 400); |
| + |
| + auto c2_hit_test_region_c3 = mojom::HitTestRegion::New(); |
| + c2_hit_test_region_c3->flags = mojom::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 = mojom::HitTestRegionList::New(); |
| + c3_hit_test_data->surface_id = c3_surface_id; |
| + c3_hit_test_data->flags = mojom::kHitTestMine; |
| + c3_hit_test_data->bounds.SetRect(0, 0, 200, 200); |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c3_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(3, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data)); |
| + EXPECT_EQ(4, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c2_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c1_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(3, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(c3_surface_id); |
| + EXPECT_EQ(4, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(4, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(3, region->child_count); |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(100, 100, 700, 700), region->rect); |
| + EXPECT_EQ(2, region->child_count); |
| + |
| + region = ®ions[2]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(100, 100, 500, 500), region->rect); |
| + EXPECT_EQ(1, region->child_count); |
| + |
| + region = ®ions[3]; |
| + EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine); |
| + 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); |
| +} |
| + |
| +// Missing / late child. |
| +// |
| +// +e-----------+ |
| +// | +c--+ | |
| +// | | |div-+ | |
| +// | | | | | |
| +// | | |----+ | |
| +// | +---+ | |
| +// +------------+ |
| +// |
| + |
| +TEST_F(HitTestAggregatorTest, MissingChildFrame) { |
| + EXPECT_EQ(0, count()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_div = mojom::HitTestRegion::New(); |
| + e_hit_test_region_div->flags = mojom::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 = 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(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 = mojom::HitTestRegionList::New(); |
| + c_hit_test_data->surface_id = c_surface_id; |
| + c_hit_test_data->flags = mojom::kHitTestMine; |
| + c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
| + |
| + // Submit in unexpected order, but not the child. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(2, count()); |
| + |
| + AggregatedHitTestRegion* regions = GetRegions(); |
| + |
| + AggregatedHitTestRegion* region = nullptr; |
| + |
| + region = ®ions[0]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id); |
| + EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect); |
| + EXPECT_EQ(1, region->child_count); |
| + |
| + // Child would exist here but it was not included in the Display Frame. |
| + |
| + region = ®ions[1]; |
| + EXPECT_EQ(mojom::kHitTestMine, region->flags); |
| + 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); |
| +} |
| + |
| +// 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(0, count()); |
| + |
| + EXPECT_LT(GetHitTestRegionListSize(), 4096); |
| + |
| + SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + |
| + int next_surface_id = CreateAndSubmitHitTestRegionListWith8Children(1, 3); |
| + int surface_count = next_surface_id - 1; |
| + |
| + EXPECT_EQ(surface_count, GetPendingCount()); |
| + |
| + // Mark Surfaces as added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + for (int i = 1; i <= surface_count; i++) { |
| + SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, i); |
| + CallOnSurfaceWillDraw(surface_id); |
| + } |
| + |
| + EXPECT_EQ(surface_count, GetActiveCount()); |
| + |
| + // Aggregate and swap. |
| + aggregator_.Aggregate(display_surface_id); |
| + EXPECT_EQ(0, count()); |
| + |
| + 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(4681, count()); |
| + |
| + EXPECT_GE(GetHitTestRegionListSize(), 4681); |
| +} |
| + |
| +TEST_F(HitTestAggregatorTest, ActiveRegionCount) { |
| + EXPECT_EQ(0, GetActiveRegionCount()); |
| + |
| + SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); |
| + SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2); |
| + |
| + auto e_hit_test_data = mojom::HitTestRegionList::New(); |
| + e_hit_test_data->surface_id = e_surface_id; |
| + e_hit_test_data->flags = mojom::kHitTestMine; |
| + e_hit_test_data->bounds.SetRect(0, 0, 1024, 768); |
| + |
| + auto e_hit_test_region_div = mojom::HitTestRegion::New(); |
| + e_hit_test_region_div->flags = mojom::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 = 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(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 = mojom::HitTestRegionList::New(); |
| + c_hit_test_data->surface_id = c_surface_id; |
| + c_hit_test_data->flags = mojom::kHitTestMine; |
| + c_hit_test_data->bounds.SetRect(0, 0, 200, 500); |
| + |
| + EXPECT_EQ(0, GetActiveRegionCount()); |
| + |
| + // Submit in unexpected order. |
| + |
| + EXPECT_EQ(0, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data)); |
| + EXPECT_EQ(1, GetPendingCount()); |
| + |
| + aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data)); |
| + EXPECT_EQ(2, GetPendingCount()); |
| + |
| + EXPECT_EQ(0, GetActiveRegionCount()); |
| + |
| + // Surfaces added to DisplayFrame in unexpected order. |
| + |
| + EXPECT_EQ(0, count()); |
| + EXPECT_EQ(0, GetActiveCount()); |
| + |
| + CallOnSurfaceWillDraw(e_surface_id); |
| + EXPECT_EQ(1, GetActiveCount()); |
| + EXPECT_EQ(2, GetActiveRegionCount()); |
| + |
| + CallOnSurfaceWillDraw(c_surface_id); |
| + EXPECT_EQ(2, GetActiveCount()); |
| + EXPECT_EQ(2, GetActiveRegionCount()); |
| + |
| + // Aggregate and swap. |
| + |
| + aggregator_.Aggregate(e_surface_id); |
| + EXPECT_EQ(0, count()); |
| + EXPECT_EQ(2, GetActiveRegionCount()); |
| + |
| + aggregator_.Swap(); |
| + |
| + EXPECT_EQ(3, count()); |
| + EXPECT_EQ(2, GetActiveRegionCount()); |
| + |
| + // Discard Surface and ensure active count goes down. |
| + |
| + CallOnSurfaceDiscarded(c_surface_id); |
| + EXPECT_EQ(2, GetActiveRegionCount()); |
| + |
| + CallOnSurfaceDiscarded(e_surface_id); |
| + EXPECT_EQ(0, GetActiveRegionCount()); |
| +} |
| + |
| +} // namespace viz |