1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/resources/picture_pile_base.h"
6
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10
11 #include "base/debug/trace_event_argument.h"
12 #include "base/logging.h"
13 #include "base/values.h"
14 #include "cc/base/math_util.h"
15 #include "cc/debug/traced_value.h"
16 #include "third_party/skia/include/core/SkColor.h"
17 #include "ui/gfx/rect_conversions.h"
18
19 namespace {
20 // Dimensions of the tiles in this picture pile as well as the dimensions of
21 // the base picture in each tile.
22 const int kBasePictureSize = 512;
23 const int kTileGridBorderPixels = 1;
24 #ifdef NDEBUG
25 const bool kDefaultClearCanvasSetting = false;
26 #else
27 const bool kDefaultClearCanvasSetting = true;
28 #endif
29
30 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
31 // between 0 and 1 meaning invalidation frequency between 0% and 100% that
32 // indicates when to stop invalidating offscreen regions.
33 // kFrequentInvalidationDistanceThreshold defines what it means to be
34 // "offscreen" in terms of distance to visible in css pixels.
35 const float kInvalidationFrequencyThreshold = 0.75f;
36 const int kFrequentInvalidationDistanceThreshold = 512;
37
38 } // namespace
39
40 namespace cc {
41
PicturePileBase()42 PicturePileBase::PicturePileBase()
43 : min_contents_scale_(0),
44 background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
45 slow_down_raster_scale_factor_for_debug_(0),
46 contents_opaque_(false),
47 contents_fill_bounds_completely_(false),
48 show_debug_picture_borders_(false),
49 clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
50 has_any_recordings_(false),
51 has_text_(false),
52 is_mask_(false),
53 is_solid_color_(false),
54 solid_color_(SK_ColorTRANSPARENT) {
55 tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
56 tile_grid_info_.fTileInterval.setEmpty();
57 tile_grid_info_.fMargin.setEmpty();
58 tile_grid_info_.fOffset.setZero();
59 }
60
PicturePileBase(const PicturePileBase * other)61 PicturePileBase::PicturePileBase(const PicturePileBase* other)
62 : picture_map_(other->picture_map_),
63 tiling_(other->tiling_),
64 recorded_viewport_(other->recorded_viewport_),
65 min_contents_scale_(other->min_contents_scale_),
66 tile_grid_info_(other->tile_grid_info_),
67 background_color_(other->background_color_),
68 slow_down_raster_scale_factor_for_debug_(
69 other->slow_down_raster_scale_factor_for_debug_),
70 contents_opaque_(other->contents_opaque_),
71 contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
72 show_debug_picture_borders_(other->show_debug_picture_borders_),
73 clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
74 has_any_recordings_(other->has_any_recordings_),
75 has_text_(other->has_text_),
76 is_mask_(other->is_mask_),
77 is_solid_color_(other->is_solid_color_),
78 solid_color_(other->solid_color_) {
79 }
80
~PicturePileBase()81 PicturePileBase::~PicturePileBase() {
82 }
83
SetMinContentsScale(float min_contents_scale)84 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
85 DCHECK(min_contents_scale);
86 if (min_contents_scale_ == min_contents_scale)
87 return;
88
89 // Picture contents are played back scaled. When the final contents scale is
90 // less than 1 (i.e. low res), then multiple recorded pixels will be used
91 // to raster one final pixel. To avoid splitting a final pixel across
92 // pictures (which would result in incorrect rasterization due to blending), a
93 // buffer margin is added so that any picture can be snapped to integral
94 // final pixels.
95 //
96 // For example, if a 1/4 contents scale is used, then that would be 3 buffer
97 // pixels, since that's the minimum number of pixels to add so that resulting
98 // content can be snapped to a four pixel aligned grid.
99 int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
100 buffer_pixels = std::max(0, buffer_pixels);
101 SetBufferPixels(buffer_pixels);
102 min_contents_scale_ = min_contents_scale;
103 }
104
105 // static
ComputeTileGridInfo(const gfx::Size & tile_grid_size,SkTileGridFactory::TileGridInfo * info)106 void PicturePileBase::ComputeTileGridInfo(
107 const gfx::Size& tile_grid_size,
108 SkTileGridFactory::TileGridInfo* info) {
109 DCHECK(info);
110 info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
111 tile_grid_size.height() - 2 * kTileGridBorderPixels);
112 DCHECK_GT(info->fTileInterval.width(), 0);
113 DCHECK_GT(info->fTileInterval.height(), 0);
114 info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
115 // Offset the tile grid coordinate space to take into account the fact
116 // that the top-most and left-most tiles do not have top and left borders
117 // respectively.
118 info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
119 }
120
SetTileGridSize(const gfx::Size & tile_grid_size)121 void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
122 ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
123 }
124
SetBufferPixels(int new_buffer_pixels)125 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
126 if (new_buffer_pixels == buffer_pixels())
127 return;
128
129 Clear();
130 tiling_.SetBorderTexels(new_buffer_pixels);
131 }
132
Clear()133 void PicturePileBase::Clear() {
134 picture_map_.clear();
135 recorded_viewport_ = gfx::Rect();
136 }
137
HasRecordingAt(int x,int y)138 bool PicturePileBase::HasRecordingAt(int x, int y) {
139 PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
140 if (found == picture_map_.end())
141 return false;
142 return !!found->second.GetPicture();
143 }
144
CanRaster(float contents_scale,const gfx::Rect & content_rect)145 bool PicturePileBase::CanRaster(float contents_scale,
146 const gfx::Rect& content_rect) {
147 if (tiling_.tiling_size().IsEmpty())
148 return false;
149 gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
150 content_rect, 1.f / contents_scale);
151 layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
152
153 // Common case inside of viewport to avoid the slower map lookups.
154 if (recorded_viewport_.Contains(layer_rect)) {
155 // Sanity check that there are no false positives in recorded_viewport_.
156 DCHECK(CanRasterSlowTileCheck(layer_rect));
157 return true;
158 }
159
160 return CanRasterSlowTileCheck(layer_rect);
161 }
162
CanRasterSlowTileCheck(const gfx::Rect & layer_rect) const163 bool PicturePileBase::CanRasterSlowTileCheck(
164 const gfx::Rect& layer_rect) const {
165 bool include_borders = false;
166 for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
167 tile_iter;
168 ++tile_iter) {
169 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
170 if (map_iter == picture_map_.end())
171 return false;
172 if (!map_iter->second.GetPicture())
173 return false;
174 }
175 return true;
176 }
177
PaddedRect(const PictureMapKey & key) const178 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const {
179 gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
180 return PadRect(tile);
181 }
182
PadRect(const gfx::Rect & rect) const183 gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const {
184 gfx::Rect padded_rect = rect;
185 padded_rect.Inset(
186 -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
187 return padded_rect;
188 }
189
AsValueInto(base::debug::TracedValue * pictures) const190 void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const {
191 gfx::Rect tiling_rect(tiling_.tiling_size());
192 std::set<const void*> appended_pictures;
193 bool include_borders = true;
194 for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
195 tile_iter;
196 ++tile_iter) {
197 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
198 if (map_iter == picture_map_.end())
199 continue;
200
201 const Picture* picture = map_iter->second.GetPicture();
202 if (picture && (appended_pictures.count(picture) == 0)) {
203 appended_pictures.insert(picture);
204 TracedValue::AppendIDRef(picture, pictures);
205 }
206 }
207 }
208
PictureInfo()209 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
210
~PictureInfo()211 PicturePileBase::PictureInfo::~PictureInfo() {}
212
AdvanceInvalidationHistory(int frame_number)213 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
214 int frame_number) {
215 DCHECK_GE(frame_number, last_frame_number_);
216 if (frame_number == last_frame_number_)
217 return;
218
219 invalidation_history_ <<= (frame_number - last_frame_number_);
220 last_frame_number_ = frame_number;
221 }
222
Invalidate(int frame_number)223 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
224 AdvanceInvalidationHistory(frame_number);
225 invalidation_history_.set(0);
226
227 bool did_invalidate = !!picture_.get();
228 picture_ = NULL;
229 return did_invalidate;
230 }
231
NeedsRecording(int frame_number,int distance_to_visible)232 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
233 int distance_to_visible) {
234 AdvanceInvalidationHistory(frame_number);
235
236 // We only need recording if we don't have a picture. Furthermore, we only
237 // need a recording if we're within frequent invalidation distance threshold
238 // or the invalidation is not frequent enough (below invalidation frequency
239 // threshold).
240 return !picture_.get() &&
241 ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
242 (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
243 }
244
SetPicture(scoped_refptr<Picture> picture)245 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
246 picture_ = picture;
247 }
248
GetPicture() const249 const Picture* PicturePileBase::PictureInfo::GetPicture() const {
250 return picture_.get();
251 }
252
GetInvalidationFrequency() const253 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
254 return invalidation_history_.count() /
255 static_cast<float>(INVALIDATION_FRAMES_TRACKED);
256 }
257
258 } // namespace cc
259