summaryrefslogtreecommitdiff
path: root/chromium/cc/resources/picture_pile.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/resources/picture_pile.cc')
-rw-r--r--chromium/cc/resources/picture_pile.cc177
1 files changed, 177 insertions, 0 deletions
diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/resources/picture_pile.cc
new file mode 100644
index 00000000000..17283ddd263
--- /dev/null
+++ b/chromium/cc/resources/picture_pile.cc
@@ -0,0 +1,177 @@
+// 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_pile.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "cc/base/region.h"
+#include "cc/debug/benchmark_instrumentation.h"
+#include "cc/resources/picture_pile_impl.h"
+
+namespace {
+// Maximum number of pictures that can overlap before we collapse them into
+// a larger one.
+const size_t kMaxOverlapping = 2;
+// Maximum percentage area of the base picture another picture in the picture
+// list can be. If higher, we destroy the list and recreate from scratch.
+const float kResetThreshold = 0.7f;
+// Layout pixel buffer around the visible layer rect to record. Any base
+// picture that intersects the visible layer rect expanded by this distance
+// will be recorded.
+const int kPixelDistanceToRecord = 8000;
+} // namespace
+
+namespace cc {
+
+PicturePile::PicturePile() {
+}
+
+PicturePile::~PicturePile() {
+}
+
+bool PicturePile::Update(
+ ContentLayerClient* painter,
+ SkColor background_color,
+ bool contents_opaque,
+ const Region& invalidation,
+ gfx::Rect visible_layer_rect,
+ RenderingStatsInstrumentation* stats_instrumentation) {
+ background_color_ = background_color;
+ contents_opaque_ = contents_opaque;
+
+ gfx::Rect interest_rect = visible_layer_rect;
+ interest_rect.Inset(
+ -kPixelDistanceToRecord,
+ -kPixelDistanceToRecord,
+ -kPixelDistanceToRecord,
+ -kPixelDistanceToRecord);
+ bool modified_pile = false;
+ for (Region::Iterator i(invalidation); i.has_rect(); i.next()) {
+ 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_, invalidation);
+ iter; ++iter) {
+ gfx::Rect tile =
+ tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y());
+ if (!tile.Intersects(interest_rect)) {
+ // This invalidation touches a tile outside the interest rect, so
+ // just remove the entire picture list.
+ picture_list_map_.erase(iter.index());
+ modified_pile = true;
+ continue;
+ }
+
+ gfx::Rect tile_invalidation = gfx::IntersectRects(invalidation, tile);
+ if (tile_invalidation.IsEmpty())
+ continue;
+ PictureListMap::iterator find = picture_list_map_.find(iter.index());
+ if (find == picture_list_map_.end())
+ continue;
+ PictureList& pic_list = find->second;
+ // Leave empty pic_lists empty in case there are multiple invalidations.
+ 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);
+ modified_pile = true;
+ }
+ }
+ }
+
+ int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
+
+ // Walk through all pictures in the rect of interest and record.
+ for (TilingData::Iterator iter(&tiling_, interest_rect); iter; ++iter) {
+ // Create a picture in this list if it doesn't exist.
+ PictureList& pic_list = picture_list_map_[iter.index()];
+ if (pic_list.empty()) {
+ // Inflate the base picture with a margin, similar to invalidations, so
+ // that when scaled down to at least min_contents_scale, the enclosed
+ // rect still includes content all the way to the edge of the layer.
+ gfx::Rect tile = tiling_.TileBounds(iter.index_x(), iter.index_y());
+ tile.Inset(
+ -buffer_pixels(),
+ -buffer_pixels(),
+ -buffer_pixels(),
+ -buffer_pixels());
+ scoped_refptr<Picture> base_picture = Picture::Create(tile);
+ pic_list.push_back(base_picture);
+ }
+
+ for (PictureList::iterator pic = pic_list.begin();
+ pic != pic_list.end(); ++pic) {
+ if (!(*pic)->HasRecording()) {
+ modified_pile = true;
+ TRACE_EVENT0(benchmark_instrumentation::kCategory,
+ benchmark_instrumentation::kRecordLoop);
+ for (int i = 0; i < repeat_count; i++)
+ (*pic)->Record(painter, tile_grid_info_, stats_instrumentation);
+ (*pic)->GatherPixelRefs(tile_grid_info_, stats_instrumentation);
+ (*pic)->CloneForDrawing(num_raster_threads_);
+ }
+ }
+ }
+
+ UpdateRecordedRegion();
+
+ return modified_pile;
+}
+
+class FullyContainedPredicate {
+ public:
+ explicit FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) {}
+ bool operator()(const scoped_refptr<Picture>& picture) {
+ return picture->LayerRect().IsEmpty() ||
+ layer_rect_.Contains(picture->LayerRect());
+ }
+ gfx::Rect layer_rect_;
+};
+
+void PicturePile::InvalidateRect(
+ PictureList& picture_list,
+ gfx::Rect invalidation) {
+ DCHECK(!picture_list.empty());
+ DCHECK(!invalidation.IsEmpty());
+
+ std::vector<PictureList::iterator> overlaps;
+ for (PictureList::iterator i = picture_list.begin();
+ i != picture_list.end(); ++i) {
+ if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording())
+ return;
+ if ((*i)->LayerRect().Intersects(invalidation) && i != picture_list.begin())
+ overlaps.push_back(i);
+ }
+
+ gfx::Rect picture_rect = invalidation;
+ if (overlaps.size() >= kMaxOverlapping) {
+ for (size_t j = 0; j < overlaps.size(); j++)
+ picture_rect.Union((*overlaps[j])->LayerRect());
+ }
+
+ Picture* base_picture = picture_list.front().get();
+ int max_pixels = kResetThreshold * base_picture->LayerRect().size().GetArea();
+ if (picture_rect.size().GetArea() > max_pixels) {
+ // This picture list will be entirely recreated, so clear it.
+ picture_list.clear();
+ return;
+ }
+
+ FullyContainedPredicate pred(picture_rect);
+ picture_list.erase(std::remove_if(picture_list.begin(),
+ picture_list.end(),
+ pred),
+ picture_list.end());
+ picture_list.push_back(Picture::Create(picture_rect));
+}
+
+} // namespace cc