diff options
-rw-r--r-- | cc/cc_tests.gyp | 1 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling.cc | 6 | ||||
-rw-r--r-- | cc/resources/picture_pile.cc | 26 | ||||
-rw-r--r-- | cc/resources/picture_pile.h | 4 | ||||
-rw-r--r-- | cc/resources/picture_pile_impl.cc | 4 | ||||
-rw-r--r-- | cc/resources/picture_pile_unittest.cc | 201 |
6 files changed, 227 insertions, 15 deletions
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 4828854..85e5f10 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -50,6 +50,7 @@ 'resources/picture_layer_tiling_set_unittest.cc', 'resources/picture_layer_tiling_unittest.cc', 'resources/picture_pile_impl_unittest.cc', + 'resources/picture_pile_unittest.cc', 'resources/picture_unittest.cc', 'resources/prioritized_resource_unittest.cc', 'resources/resource_provider_unittest.cc', diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc index 85249e2..678a0fa 100644 --- a/cc/resources/picture_layer_tiling.cc +++ b/cc/resources/picture_layer_tiling.cc @@ -42,6 +42,12 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale, gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)); gfx::Size tile_size = client_->CalculateTileSize(content_bounds); + DCHECK(!gfx::ToFlooredSize( + gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) << + "Tiling created with scale too small as contents become empty. " << + "Layer bounds: " << layer_bounds.ToString() << + "Contents scale: " << contents_scale; + tiling_data_.SetTotalSize(content_bounds); tiling_data_.SetMaxTextureSize(tile_size); } diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc index 8f8bada..9fe76db 100644 --- a/cc/resources/picture_pile.cc +++ b/cc/resources/picture_pile.cc @@ -46,18 +46,10 @@ void PicturePile::Update( -kPixelDistanceToRecord, -kPixelDistanceToRecord); for (Region::Iterator i(invalidation); i.has_rect(); i.next()) { - // Inflate all recordings from invalidations with a margin so that when - // scaled down to at least min_contents_scale, any final pixel touched by an - // invalidation can be fully rasterized by this picture. - gfx::Rect inflated_invalidation = i.rect(); - inflated_invalidation.Inset( - -buffer_pixels(), - -buffer_pixels(), - -buffer_pixels(), - -buffer_pixels()); + gfx::Rect invalidation = i.rect(); // Split this inflated invalidation across tile boundaries and apply it // to all tiles that it touches. - for (TilingData::Iterator iter(&tiling_, inflated_invalidation); + for (TilingData::Iterator iter(&tiling_, invalidation); iter; ++iter) { gfx::Rect tile = tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y()); @@ -68,8 +60,7 @@ void PicturePile::Update( continue; } - gfx::Rect tile_invalidation = - gfx::IntersectRects(inflated_invalidation, tile); + gfx::Rect tile_invalidation = gfx::IntersectRects(invalidation, tile); if (tile_invalidation.IsEmpty()) continue; PictureListMap::iterator find = picture_list_map_.find(iter.index()); @@ -77,8 +68,17 @@ void PicturePile::Update( continue; PictureList& pic_list = find->second; // Leave empty pic_lists empty in case there are multiple invalidations. - if (!pic_list.empty()) + if (!pic_list.empty()) { + // Inflate all recordings from invalidations with a margin so that when + // scaled down to at least min_contents_scale, any final pixel touched + // by an invalidation can be fully rasterized by this picture. + tile_invalidation.Inset(-buffer_pixels(), -buffer_pixels()); + + DCHECK_GE(tile_invalidation.width(), buffer_pixels() * 2 + 1); + DCHECK_GE(tile_invalidation.height(), buffer_pixels() * 2 + 1); + InvalidateRect(pic_list, tile_invalidation); + } } } diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h index fb5ce29..af44cef 100644 --- a/cc/resources/picture_pile.h +++ b/cc/resources/picture_pile.h @@ -38,8 +38,10 @@ class CC_EXPORT PicturePile : public PicturePileBase { show_debug_picture_borders_ = show; } - private: + protected: virtual ~PicturePile(); + + private: friend class PicturePileImpl; // Add an invalidation to this picture list. If the list needs to be diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc index 978b87d..8f2ef54 100644 --- a/cc/resources/picture_pile_impl.cc +++ b/cc/resources/picture_pile_impl.cc @@ -146,7 +146,9 @@ void PicturePileImpl::Raster( // encompasses all invalidated pixels at any larger scale level. gfx::Rect content_clip = gfx::ToEnclosedRect( gfx::ScaleRect((*i)->LayerRect(), contents_scale)); - DCHECK(!content_clip.IsEmpty()); + DCHECK(!content_clip.IsEmpty()) << + "Layer rect: " << (*i)->LayerRect().ToString() << + "Contents scale: " << contents_scale; if (!unclipped.Intersects(content_clip)) continue; diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc new file mode 100644 index 0000000..f8e1a63 --- /dev/null +++ b/cc/resources/picture_pile_unittest.cc @@ -0,0 +1,201 @@ +// Copyright 2013 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_pile.h" +#include "cc/test/fake_content_layer_client.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/size_conversions.h" + +namespace cc { +namespace { + +class TestPicturePile : public PicturePile { + public: + using PicturePile::buffer_pixels; + + PictureListMap& picture_list_map() { return picture_list_map_; } + + typedef PicturePile::PictureList PictureList; + typedef PicturePile::PictureListMapKey PictureListMapKey; + typedef PicturePile::PictureListMap PictureListMap; + + protected: + virtual ~TestPicturePile() {} +}; + +TEST(PicturePileTest, SmallInvalidateInflated) { + FakeContentLayerClient client; + scoped_refptr<TestPicturePile> pile = new TestPicturePile; + SkColor background_color = SK_ColorBLUE; + + float min_scale = 0.125; + gfx::Size base_picture_size = pile->tiling().max_texture_size(); + + gfx::Size layer_size = base_picture_size; + pile->Resize(layer_size); + pile->SetTileGridSize(gfx::Size(1000, 1000)); + pile->SetMinContentsScale(min_scale); + + // Update the whole layer. + pile->Update(&client, + background_color, + gfx::Rect(layer_size), + gfx::Rect(layer_size), + NULL); + + // Invalidate something inside a tile. + gfx::Rect invalidate_rect(50, 50, 1, 1); + pile->Update(&client, + background_color, + invalidate_rect, + gfx::Rect(layer_size), + NULL); + + EXPECT_EQ(1, pile->tiling().num_tiles_x()); + EXPECT_EQ(1, pile->tiling().num_tiles_y()); + + TestPicturePile::PictureList& picture_list = + pile->picture_list_map().find( + TestPicturePile::PictureListMapKey(0, 0))->second; + EXPECT_EQ(2u, picture_list.size()); + for (TestPicturePile::PictureList::iterator it = picture_list.begin(); + it != picture_list.end(); + ++it) { + scoped_refptr<Picture> picture = *it; + gfx::Rect picture_rect = gfx::ToEnclosedRect( + gfx::ScaleRect(picture->LayerRect(), min_scale)); + + // The invalidation in each tile should have been made large enough + // that scaling it never makes a rect smaller than 1 px wide or tall. + EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << + picture_rect.ToString(); + } +} + +TEST(PicturePileTest, LargeInvalidateInflated) { + FakeContentLayerClient client; + scoped_refptr<TestPicturePile> pile = new TestPicturePile; + SkColor background_color = SK_ColorBLUE; + + float min_scale = 0.125; + gfx::Size base_picture_size = pile->tiling().max_texture_size(); + + gfx::Size layer_size = base_picture_size; + pile->Resize(layer_size); + pile->SetTileGridSize(gfx::Size(1000, 1000)); + pile->SetMinContentsScale(min_scale); + + // Update the whole layer. + pile->Update(&client, + background_color, + gfx::Rect(layer_size), + gfx::Rect(layer_size), + NULL); + + // Invalidate something inside a tile. + gfx::Rect invalidate_rect(50, 50, 100, 100); + pile->Update(&client, + background_color, + invalidate_rect, + gfx::Rect(layer_size), + NULL); + + EXPECT_EQ(1, pile->tiling().num_tiles_x()); + EXPECT_EQ(1, pile->tiling().num_tiles_y()); + + TestPicturePile::PictureList& picture_list = + pile->picture_list_map().find( + TestPicturePile::PictureListMapKey(0, 0))->second; + EXPECT_EQ(2u, picture_list.size()); + + int expected_inflation = pile->buffer_pixels(); + + scoped_refptr<Picture> base_picture = *picture_list.begin(); + gfx::Rect base_picture_rect(layer_size); + base_picture_rect.Inset(-expected_inflation, -expected_inflation); + EXPECT_EQ(base_picture_rect.ToString(), + base_picture->LayerRect().ToString()); + + scoped_refptr<Picture> picture = *(++picture_list.begin()); + gfx::Rect picture_rect(invalidate_rect); + picture_rect.Inset(-expected_inflation, -expected_inflation); + EXPECT_EQ(picture_rect.ToString(), + picture->LayerRect().ToString()); +} + +TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) { + FakeContentLayerClient client; + scoped_refptr<TestPicturePile> pile = new TestPicturePile; + SkColor background_color = SK_ColorBLUE; + + float min_scale = 0.125; + gfx::Size base_picture_size = pile->tiling().max_texture_size(); + + gfx::Size layer_size = + gfx::ToFlooredSize(gfx::ScaleSize(base_picture_size, 2.f)); + pile->Resize(layer_size); + pile->SetTileGridSize(gfx::Size(1000, 1000)); + pile->SetMinContentsScale(min_scale); + + // Due to border pixels, we should have 3 tiles. + EXPECT_EQ(3, pile->tiling().num_tiles_x()); + EXPECT_EQ(3, pile->tiling().num_tiles_y()); + + // We should have 1/.125 - 1 = 7 border pixels. + EXPECT_EQ(7, pile->buffer_pixels()); + EXPECT_EQ(7, pile->tiling().border_texels()); + + // Update the whole layer. + pile->Update(&client, + background_color, + gfx::Rect(layer_size), + gfx::Rect(layer_size), + NULL); + + // Invalidate something just over a tile boundary by a single pixel. + // This will invalidate the tile (1, 1), as well as 1 row of pixels in (1, 0). + gfx::Rect invalidate_rect( + pile->tiling().TileBoundsWithBorder(0, 0).right(), + pile->tiling().TileBoundsWithBorder(0, 0).bottom() - 1, + 50, + 50); + pile->Update(&client, + background_color, + invalidate_rect, + gfx::Rect(layer_size), + NULL); + + for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) { + for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) { + // (1, 0) and (1, 1) should be invalidated partially. + bool expect_invalidated = i == 1 && (j == 0 || j == 1); + + TestPicturePile::PictureList& picture_list = + pile->picture_list_map().find( + TestPicturePile::PictureListMapKey(i, j))->second; + if (!expect_invalidated) { + EXPECT_EQ(1u, picture_list.size()) << "For i,j " << i << "," << j; + continue; + } + + EXPECT_EQ(2u, picture_list.size()) << "For i,j " << i << "," << j; + for (TestPicturePile::PictureList::iterator it = picture_list.begin(); + it != picture_list.end(); + ++it) { + scoped_refptr<Picture> picture = *it; + gfx::Rect picture_rect = gfx::ToEnclosedRect( + gfx::ScaleRect(picture->LayerRect(), min_scale)); + + // The invalidation in each tile should have been made large enough + // that scaling it never makes a rect smaller than 1 px wide or tall. + EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " << + picture_rect.ToString(); + } + } + } +} + +} // namespace +} // namespace cc |