summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/cc_tests.gyp1
-rw-r--r--cc/resources/picture_layer_tiling.cc6
-rw-r--r--cc/resources/picture_pile.cc26
-rw-r--r--cc/resources/picture_pile.h4
-rw-r--r--cc/resources/picture_pile_impl.cc4
-rw-r--r--cc/resources/picture_pile_unittest.cc201
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