// Copyright 2012 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 "cc/resources/picture_layer_tiling_set.h" #include #include #include "cc/resources/resource_provider.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_picture_layer_tiling_client.h" #include "cc/test/test_shared_bitmap_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/size_conversions.h" namespace cc { namespace { TEST(PictureLayerTilingSetTest, NoResources) { FakePictureLayerTilingClient client; gfx::Size layer_bounds(1000, 800); PictureLayerTilingSet set(&client); client.SetTileSize(gfx::Size(256, 256)); set.AddTiling(1.0, layer_bounds); set.AddTiling(1.5, layer_bounds); set.AddTiling(2.0, layer_bounds); float contents_scale = 2.0; gfx::Size content_bounds( gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); gfx::Rect content_rect(content_bounds); Region remaining(content_rect); PictureLayerTilingSet::CoverageIterator iter( &set, contents_scale, content_rect, contents_scale); for (; iter; ++iter) { gfx::Rect geometry_rect = iter.geometry_rect(); EXPECT_TRUE(content_rect.Contains(geometry_rect)); ASSERT_TRUE(remaining.Contains(geometry_rect)); remaining.Subtract(geometry_rect); // No tiles have resources, so no iter represents a real tile. EXPECT_FALSE(*iter); } EXPECT_TRUE(remaining.IsEmpty()); } TEST(PictureLayerTilingSetTest, TilingRange) { FakePictureLayerTilingClient client; gfx::Size layer_bounds(10, 10); PictureLayerTilingSet::TilingRange higher_than_high_res_range(0, 0); PictureLayerTilingSet::TilingRange high_res_range(0, 0); PictureLayerTilingSet::TilingRange between_high_and_low_res_range(0, 0); PictureLayerTilingSet::TilingRange low_res_range(0, 0); PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0); PictureLayerTiling* high_res_tiling; PictureLayerTiling* low_res_tiling; PictureLayerTilingSet set(&client); set.AddTiling(2.0, layer_bounds); high_res_tiling = set.AddTiling(1.0, layer_bounds); high_res_tiling->set_resolution(HIGH_RESOLUTION); set.AddTiling(0.5, layer_bounds); low_res_tiling = set.AddTiling(0.25, layer_bounds); low_res_tiling->set_resolution(LOW_RESOLUTION); set.AddTiling(0.125, layer_bounds); higher_than_high_res_range = set.GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); EXPECT_EQ(0u, higher_than_high_res_range.start); EXPECT_EQ(1u, higher_than_high_res_range.end); high_res_range = set.GetTilingRange(PictureLayerTilingSet::HIGH_RES); EXPECT_EQ(1u, high_res_range.start); EXPECT_EQ(2u, high_res_range.end); between_high_and_low_res_range = set.GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); EXPECT_EQ(2u, between_high_and_low_res_range.start); EXPECT_EQ(3u, between_high_and_low_res_range.end); low_res_range = set.GetTilingRange(PictureLayerTilingSet::LOW_RES); EXPECT_EQ(3u, low_res_range.start); EXPECT_EQ(4u, low_res_range.end); lower_than_low_res_range = set.GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES); EXPECT_EQ(4u, lower_than_low_res_range.start); EXPECT_EQ(5u, lower_than_low_res_range.end); PictureLayerTilingSet set_without_low_res(&client); set_without_low_res.AddTiling(2.0, layer_bounds); high_res_tiling = set_without_low_res.AddTiling(1.0, layer_bounds); high_res_tiling->set_resolution(HIGH_RESOLUTION); set_without_low_res.AddTiling(0.5, layer_bounds); set_without_low_res.AddTiling(0.25, layer_bounds); higher_than_high_res_range = set_without_low_res.GetTilingRange( PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); EXPECT_EQ(0u, higher_than_high_res_range.start); EXPECT_EQ(1u, higher_than_high_res_range.end); high_res_range = set_without_low_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES); EXPECT_EQ(1u, high_res_range.start); EXPECT_EQ(2u, high_res_range.end); between_high_and_low_res_range = set_without_low_res.GetTilingRange( PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); EXPECT_EQ(2u, between_high_and_low_res_range.start); EXPECT_EQ(4u, between_high_and_low_res_range.end); low_res_range = set_without_low_res.GetTilingRange(PictureLayerTilingSet::LOW_RES); EXPECT_EQ(0u, low_res_range.end - low_res_range.start); lower_than_low_res_range = set_without_low_res.GetTilingRange( PictureLayerTilingSet::LOWER_THAN_LOW_RES); EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); PictureLayerTilingSet set_with_only_high_and_low_res(&client); high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0, layer_bounds); high_res_tiling->set_resolution(HIGH_RESOLUTION); low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5, layer_bounds); low_res_tiling->set_resolution(LOW_RESOLUTION); higher_than_high_res_range = set_with_only_high_and_low_res.GetTilingRange( PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); EXPECT_EQ(0u, higher_than_high_res_range.end - higher_than_high_res_range.start); high_res_range = set_with_only_high_and_low_res.GetTilingRange( PictureLayerTilingSet::HIGH_RES); EXPECT_EQ(0u, high_res_range.start); EXPECT_EQ(1u, high_res_range.end); between_high_and_low_res_range = set_with_only_high_and_low_res.GetTilingRange( PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); EXPECT_EQ(0u, between_high_and_low_res_range.end - between_high_and_low_res_range.start); low_res_range = set_with_only_high_and_low_res.GetTilingRange( PictureLayerTilingSet::LOW_RES); EXPECT_EQ(1u, low_res_range.start); EXPECT_EQ(2u, low_res_range.end); lower_than_low_res_range = set_with_only_high_and_low_res.GetTilingRange( PictureLayerTilingSet::LOWER_THAN_LOW_RES); EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); PictureLayerTilingSet set_with_only_high_res(&client); high_res_tiling = set_with_only_high_res.AddTiling(1.0, layer_bounds); high_res_tiling->set_resolution(HIGH_RESOLUTION); higher_than_high_res_range = set_with_only_high_res.GetTilingRange( PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); EXPECT_EQ(0u, higher_than_high_res_range.end - higher_than_high_res_range.start); high_res_range = set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES); EXPECT_EQ(0u, high_res_range.start); EXPECT_EQ(1u, high_res_range.end); between_high_and_low_res_range = set_with_only_high_res.GetTilingRange( PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES); EXPECT_EQ(0u, between_high_and_low_res_range.end - between_high_and_low_res_range.start); low_res_range = set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::LOW_RES); EXPECT_EQ(0u, low_res_range.end - low_res_range.start); lower_than_low_res_range = set_with_only_high_res.GetTilingRange( PictureLayerTilingSet::LOWER_THAN_LOW_RES); EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start); } class PictureLayerTilingSetTestWithResources : public testing::Test { public: void runTest( int num_tilings, float min_scale, float scale_increment, float ideal_contents_scale, float expected_scale) { FakeOutputSurfaceClient output_surface_client; scoped_ptr output_surface = FakeOutputSurface::Create3d(); CHECK(output_surface->BindToClient(&output_surface_client)); scoped_ptr shared_bitmap_manager( new TestSharedBitmapManager()); scoped_ptr resource_provider = ResourceProvider::Create(output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false, 1); FakePictureLayerTilingClient client(resource_provider.get()); client.SetTileSize(gfx::Size(256, 256)); client.set_tree(PENDING_TREE); gfx::Size layer_bounds(1000, 800); PictureLayerTilingSet set(&client); float scale = min_scale; for (int i = 0; i < num_tilings; ++i, scale += scale_increment) { PictureLayerTiling* tiling = set.AddTiling(scale, layer_bounds); tiling->CreateAllTilesForTesting(); std::vector tiles = tiling->AllTilesForTesting(); client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles); } float max_contents_scale = scale; gfx::Size content_bounds( gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, max_contents_scale))); gfx::Rect content_rect(content_bounds); Region remaining(content_rect); PictureLayerTilingSet::CoverageIterator iter( &set, max_contents_scale, content_rect, ideal_contents_scale); for (; iter; ++iter) { gfx::Rect geometry_rect = iter.geometry_rect(); EXPECT_TRUE(content_rect.Contains(geometry_rect)); ASSERT_TRUE(remaining.Contains(geometry_rect)); remaining.Subtract(geometry_rect); float scale = iter.CurrentTiling()->contents_scale(); EXPECT_EQ(expected_scale, scale); if (num_tilings) EXPECT_TRUE(*iter); else EXPECT_FALSE(*iter); } EXPECT_TRUE(remaining.IsEmpty()); } }; TEST_F(PictureLayerTilingSetTestWithResources, NoTilings) { runTest(0, 0.f, 0.f, 2.f, 0.f); } TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Smaller) { runTest(1, 1.f, 0.f, 2.f, 1.f); } TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Larger) { runTest(1, 3.f, 0.f, 2.f, 3.f); } TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Smaller) { runTest(2, 1.f, 1.f, 3.f, 2.f); } TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_SmallerEqual) { runTest(2, 1.f, 1.f, 2.f, 2.f); } TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_LargerEqual) { runTest(2, 1.f, 1.f, 1.f, 1.f); } TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Larger) { runTest(2, 2.f, 8.f, 1.f, 2.f); } TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_Equal) { runTest(10, 1.f, 1.f, 5.f, 5.f); } TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_NotEqual) { runTest(10, 1.f, 1.f, 4.5f, 5.f); } class PictureLayerTilingSetSyncTest : public testing::Test { public: PictureLayerTilingSetSyncTest() : tile_size_(gfx::Size(10, 10)), source_bounds_(gfx::Size(30, 20)), target_bounds_(gfx::Size(30, 30)) { source_client_.SetTileSize(tile_size_); source_client_.set_tree(PENDING_TREE); target_client_.SetTileSize(tile_size_); target_client_.set_tree(PENDING_TREE); source_.reset(new PictureLayerTilingSet(&source_client_)); target_.reset(new PictureLayerTilingSet(&target_client_)); } // Sync from source to target. void SyncTilings(const gfx::Size& new_bounds, const Region& invalidation, float minimum_scale) { for (size_t i = 0; i < source_->num_tilings(); ++i) source_->tiling_at(i)->CreateAllTilesForTesting(); for (size_t i = 0; i < target_->num_tilings(); ++i) target_->tiling_at(i)->CreateAllTilesForTesting(); target_->SyncTilings( *source_.get(), new_bounds, invalidation, minimum_scale); } void SyncTilings(const gfx::Size& new_bounds) { Region invalidation; SyncTilings(new_bounds, invalidation, 0.f); } void SyncTilings(const gfx::Size& new_bounds, const Region& invalidation) { SyncTilings(new_bounds, invalidation, 0.f); } void SyncTilings(const gfx::Size& new_bounds, float minimum_scale) { Region invalidation; SyncTilings(new_bounds, invalidation, minimum_scale); } void VerifyTargetEqualsSource(const gfx::Size& new_bounds) { ASSERT_FALSE(new_bounds.IsEmpty()); EXPECT_EQ(target_->num_tilings(), source_->num_tilings()); for (size_t i = 0; i < target_->num_tilings(); ++i) { ASSERT_GT(source_->num_tilings(), i); const PictureLayerTiling* source_tiling = source_->tiling_at(i); const PictureLayerTiling* target_tiling = target_->tiling_at(i); EXPECT_EQ(target_tiling->layer_bounds().ToString(), new_bounds.ToString()); EXPECT_EQ(source_tiling->contents_scale(), target_tiling->contents_scale()); } EXPECT_EQ(source_->client(), &source_client_); EXPECT_EQ(target_->client(), &target_client_); ValidateTargetTilingSet(); } void ValidateTargetTilingSet() { // Tilings should be sorted largest to smallest. if (target_->num_tilings() > 0) { float last_scale = target_->tiling_at(0)->contents_scale(); for (size_t i = 1; i < target_->num_tilings(); ++i) { const PictureLayerTiling* target_tiling = target_->tiling_at(i); EXPECT_LT(target_tiling->contents_scale(), last_scale); last_scale = target_tiling->contents_scale(); } } for (size_t i = 0; i < target_->num_tilings(); ++i) ValidateTiling(target_->tiling_at(i), target_client_.GetRasterSource()); } void ValidateTiling(const PictureLayerTiling* tiling, const RasterSource* raster_source) { if (tiling->tiling_size().IsEmpty()) { EXPECT_TRUE(tiling->live_tiles_rect().IsEmpty()); } else if (!tiling->live_tiles_rect().IsEmpty()) { gfx::Rect tiling_rect(tiling->tiling_size()); EXPECT_TRUE(tiling_rect.Contains(tiling->live_tiles_rect())); } std::vector tiles = tiling->AllTilesForTesting(); for (size_t i = 0; i < tiles.size(); ++i) { const Tile* tile = tiles[i]; ASSERT_TRUE(!!tile); EXPECT_EQ(tile->raster_source(), raster_source); EXPECT_TRUE(tile->content_rect().Intersects(tiling->live_tiles_rect())) << "All tiles must be inside the live tiles rect." << " Tile rect: " << tile->content_rect().ToString() << " Live rect: " << tiling->live_tiles_rect().ToString() << " Scale: " << tiling->contents_scale(); } for (PictureLayerTiling::CoverageIterator iter( tiling, tiling->contents_scale(), tiling->live_tiles_rect()); iter; ++iter) { EXPECT_TRUE(*iter) << "The live tiles rect must be full."; } } gfx::Size tile_size_; FakePictureLayerTilingClient source_client_; gfx::Size source_bounds_; scoped_ptr source_; FakePictureLayerTilingClient target_client_; gfx::Size target_bounds_; scoped_ptr target_; }; TEST_F(PictureLayerTilingSetSyncTest, EmptyBounds) { float source_scales[] = {1.f, 1.2f}; for (size_t i = 0; i < arraysize(source_scales); ++i) source_->AddTiling(source_scales[i], source_bounds_); gfx::Size empty_bounds; SyncTilings(empty_bounds); EXPECT_EQ(target_->num_tilings(), 0u); } TEST_F(PictureLayerTilingSetSyncTest, AllNew) { float source_scales[] = {0.5f, 1.f, 1.2f}; for (size_t i = 0; i < arraysize(source_scales); ++i) source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.75f, 1.4f, 3.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); VerifyTargetEqualsSource(new_bounds); } Tile* FindTileAtOrigin(PictureLayerTiling* tiling) { std::vector tiles = tiling->AllTilesForTesting(); for (size_t i = 0; i < tiles.size(); ++i) { if (tiles[i]->content_rect().origin() == gfx::Point()) return tiles[i]; } return NULL; } TEST_F(PictureLayerTilingSetSyncTest, KeepExisting) { float source_scales[] = {0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(source_scales); ++i) source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.5f, 1.f, 2.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) target_->AddTiling(target_scales[i], target_bounds_); PictureLayerTiling* tiling1 = source_->TilingAtScale(1.f); ASSERT_TRUE(tiling1); tiling1->CreateAllTilesForTesting(); EXPECT_EQ(tiling1->contents_scale(), 1.f); Tile* tile1 = FindTileAtOrigin(tiling1); ASSERT_TRUE(tile1); PictureLayerTiling* tiling2 = source_->TilingAtScale(2.f); tiling2->CreateAllTilesForTesting(); ASSERT_TRUE(tiling2); EXPECT_EQ(tiling2->contents_scale(), 2.f); Tile* tile2 = FindTileAtOrigin(tiling2); ASSERT_TRUE(tile2); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); VerifyTargetEqualsSource(new_bounds); EXPECT_EQ(tiling1, source_->TilingAtScale(1.f)); EXPECT_EQ(tile1, FindTileAtOrigin(tiling1)); EXPECT_FALSE(tiling1->live_tiles_rect().IsEmpty()); EXPECT_EQ(tiling2, source_->TilingAtScale(2.f)); EXPECT_EQ(tile2, FindTileAtOrigin(tiling2)); EXPECT_FALSE(tiling2->live_tiles_rect().IsEmpty()); } TEST_F(PictureLayerTilingSetSyncTest, EmptySet) { float target_scales[] = {0.2f, 1.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); VerifyTargetEqualsSource(new_bounds); } TEST_F(PictureLayerTilingSetSyncTest, MinimumScale) { float source_scales[] = {0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(source_scales); ++i) source_->AddTiling(source_scales[i], source_bounds_); float target_scales[] = {0.5f, 0.7f, 1.f, 1.1f, 2.f}; for (size_t i = 0; i < arraysize(target_scales); ++i) target_->AddTiling(target_scales[i], target_bounds_); gfx::Size new_bounds(15, 40); float minimum_scale = 1.5f; SyncTilings(new_bounds, minimum_scale); EXPECT_EQ(target_->num_tilings(), 1u); EXPECT_EQ(target_->tiling_at(0)->contents_scale(), 2.f); ValidateTargetTilingSet(); } TEST_F(PictureLayerTilingSetSyncTest, Invalidation) { source_->AddTiling(2.f, source_bounds_); target_->AddTiling(2.f, target_bounds_); target_->tiling_at(0)->CreateAllTilesForTesting(); Region layer_invalidation; layer_invalidation.Union(gfx::Rect(0, 0, 1, 1)); layer_invalidation.Union(gfx::Rect(0, 15, 1, 1)); // Out of bounds layer_invalidation. layer_invalidation.Union(gfx::Rect(100, 100, 1, 1)); Region content_invalidation; for (Region::Iterator iter(layer_invalidation); iter.has_rect(); iter.next()) { gfx::Rect content_rect = gfx::ScaleToEnclosingRect(iter.rect(), 2.f); content_invalidation.Union(content_rect); } std::vector old_tiles = target_->tiling_at(0)->AllTilesForTesting(); std::map> old_tile_map; for (size_t i = 0; i < old_tiles.size(); ++i) old_tile_map[old_tiles[i]->content_rect().origin()] = old_tiles[i]; SyncTilings(target_bounds_, layer_invalidation); VerifyTargetEqualsSource(target_bounds_); std::vector new_tiles = target_->tiling_at(0)->AllTilesForTesting(); for (size_t i = 0; i < new_tiles.size(); ++i) { const Tile* tile = new_tiles[i]; std::map>::iterator find = old_tile_map.find(tile->content_rect().origin()); if (content_invalidation.Intersects(tile->content_rect())) EXPECT_NE(tile, find->second.get()); else EXPECT_EQ(tile, find->second.get()); } } TEST_F(PictureLayerTilingSetSyncTest, TileSizeChange) { source_->AddTiling(1.f, source_bounds_); target_->AddTiling(1.f, target_bounds_); target_->tiling_at(0)->CreateAllTilesForTesting(); std::vector original_tiles = target_->tiling_at(0)->AllTilesForTesting(); EXPECT_GT(original_tiles.size(), 0u); gfx::Size new_tile_size(100, 100); target_client_.SetTileSize(new_tile_size); EXPECT_NE(target_->tiling_at(0)->tile_size().ToString(), new_tile_size.ToString()); gfx::Size new_bounds(15, 40); SyncTilings(new_bounds); VerifyTargetEqualsSource(new_bounds); EXPECT_EQ(target_->tiling_at(0)->tile_size().ToString(), new_tile_size.ToString()); // All old tiles should not be present in new tiles. std::vector new_tiles = target_->tiling_at(0)->AllTilesForTesting(); for (size_t i = 0; i < original_tiles.size(); ++i) { std::vector::iterator find = std::find(new_tiles.begin(), new_tiles.end(), original_tiles[i]); EXPECT_TRUE(find == new_tiles.end()); } } } // namespace } // namespace cc