1 // Copyright 2012 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.
5 #include "cc/picture_layer_tiling.h"
7 #include "cc/math_util.h"
8 #include "ui/gfx/rect_conversions.h"
9 #include "ui/gfx/size_conversions.h"
13 scoped_ptr
<PictureLayerTiling
> PictureLayerTiling::Create(
15 gfx::Size tile_size
) {
16 return make_scoped_ptr(new PictureLayerTiling(contents_scale
, tile_size
));
19 scoped_ptr
<PictureLayerTiling
> PictureLayerTiling::Clone() const {
20 return make_scoped_ptr(new PictureLayerTiling(*this));
23 PictureLayerTiling::PictureLayerTiling(float contents_scale
,
26 contents_scale_(contents_scale
),
27 tiling_data_(tile_size
, gfx::Size(), true) {
30 PictureLayerTiling::~PictureLayerTiling() {
33 const PictureLayerTiling
& PictureLayerTiling::operator=(
34 const PictureLayerTiling
& tiler
) {
35 tiling_data_
= tiler
.tiling_data_
;
36 tiles_
= tiler
.tiles_
;
40 void PictureLayerTiling::SetClient(PictureLayerTilingClient
* client
) {
44 gfx::Rect
PictureLayerTiling::ContentRect() const {
45 gfx::Size content_bounds
=
46 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_
, contents_scale_
));
47 return gfx::Rect(gfx::Point(), content_bounds
);
50 Tile
* PictureLayerTiling::TileAt(int i
, int j
) const {
51 TileMap::const_iterator iter
= tiles_
.find(TileMapKey(i
, j
));
52 if (iter
== tiles_
.end())
54 return iter
->second
.get();
57 void PictureLayerTiling::CreateTile(int i
, int j
) {
58 gfx::Rect tile_rect
= tiling_data_
.TileBoundsWithBorder(i
, j
);
59 tile_rect
.set_size(tiling_data_
.max_texture_size());
62 tiles_
[key
] = client_
->CreateTile(this, tile_rect
);
64 // TODO(enne): Remove this when we start setting priorities correctly.
65 TilePriority priority
;
66 priority
.resolution
= HIGH_RESOLUTION
;
67 priority
.time_to_visible_in_seconds
= 1000;
68 tiles_
[key
]->set_priority(ACTIVE_TREE
, priority
);
71 Region
PictureLayerTiling::OpaqueRegionInContentRect(
72 const gfx::Rect
& content_rect
) const {
74 // TODO(enne): implement me
78 void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds
) {
79 if (layer_bounds_
== layer_bounds
)
82 layer_bounds_
= layer_bounds
;
83 gfx::Size content_bounds
=
84 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_
, contents_scale_
));
86 tiling_data_
.SetTotalSize(content_bounds
);
87 if (layer_bounds_
.IsEmpty()) {
92 int right
= tiling_data_
.TileXIndexFromSrcCoord(content_bounds
.width() - 1);
93 int bottom
= tiling_data_
.TileYIndexFromSrcCoord(content_bounds
.height() - 1);
95 // TODO(enne): Be more efficient about what tiles are created.
96 for (int j
= 0; j
<= bottom
; ++j
) {
97 for (int i
= 0; i
<= right
; ++i
) {
98 if (tiles_
.find(TileMapKey(i
, j
)) == tiles_
.end())
103 // Any tiles outside our new bounds are invalid and should be dropped.
104 std::vector
<TileMapKey
> invalid_tile_keys
;
105 for (TileMap::const_iterator it
= tiles_
.begin(); it
!= tiles_
.end(); ++it
) {
106 if (it
->first
.first
> right
|| it
->first
.second
> bottom
)
107 invalid_tile_keys
.push_back(it
->first
);
109 for (size_t i
= 0; i
< invalid_tile_keys
.size(); ++i
)
110 tiles_
.erase(invalid_tile_keys
[i
]);
113 void PictureLayerTiling::Invalidate(const Region
& layer_invalidation
) {
114 std::vector
<TileMapKey
> new_tiles
;
116 for (Region::Iterator
region_iter(layer_invalidation
);
117 region_iter
.has_rect();
118 region_iter
.next()) {
121 gfx::ToEnclosingRect(ScaleRect(region_iter
.rect(), contents_scale_
));
122 rect
.Intersect(ContentRect());
124 for (PictureLayerTiling::Iterator
tile_iter(this, contents_scale_
, rect
);
127 TileMapKey
key(tile_iter
.tile_i_
, tile_iter
.tile_j_
);
132 new_tiles
.push_back(key
);
136 for (size_t i
= 0; i
< new_tiles
.size(); ++i
) {
137 CreateTile(new_tiles
[i
].first
, new_tiles
[i
].second
);
141 PictureLayerTiling::Iterator::Iterator()
152 PictureLayerTiling::Iterator::Iterator(PictureLayerTiling
* tiling
,
156 dest_rect_(dest_rect
),
157 dest_to_content_scale_(tiling_
->contents_scale_
/ dest_scale
),
166 if (dest_rect_
.IsEmpty())
169 gfx::Rect content_rect
=
170 gfx::ToEnclosingRect(gfx::ScaleRect(dest_rect_
, dest_to_content_scale_
));
172 left_
= tiling_
->tiling_data_
.TileXIndexFromSrcCoord(content_rect
.x());
173 top_
= tiling_
->tiling_data_
.TileYIndexFromSrcCoord(content_rect
.y());
174 right_
= tiling_
->tiling_data_
.TileXIndexFromSrcCoord(
175 content_rect
.right() - 1);
176 bottom_
= tiling_
->tiling_data_
.TileYIndexFromSrcCoord(
177 content_rect
.bottom() - 1);
184 PictureLayerTiling::Iterator::~Iterator() {
187 PictureLayerTiling::Iterator
& PictureLayerTiling::Iterator::operator++() {
188 if (tile_j_
> bottom_
)
191 bool first_time
= tile_i_
< left_
;
192 bool new_row
= false;
194 if (tile_i_
> right_
) {
198 if (tile_j_
> bottom_
) {
199 current_tile_
= NULL
;
204 current_tile_
= tiling_
->TileAt(tile_i_
, tile_j_
);
206 // Calculate the current geometry rect. Due to floating point rounding
207 // and ToEnclosedRect, tiles might overlap in destination space on the
209 gfx::Rect last_geometry_rect
= current_geometry_rect_
;
211 gfx::Rect content_rect
= tiling_
->tiling_data_
.TileBounds(tile_i_
, tile_j_
);
212 current_geometry_rect_
= gfx::ToEnclosingRect(
213 gfx::ScaleRect(content_rect
, 1 / dest_to_content_scale_
));
214 current_geometry_rect_
.Intersect(dest_rect_
);
219 // Iteration happens left->right, top->bottom. Running off the bottom-right
220 // edge is handled by the intersection above with dest_rect_. Here we make
221 // sure that the new current geometry rect doesn't overlap with the last.
225 min_left
= dest_rect_
.x();
226 min_top
= last_geometry_rect
.bottom();
228 min_left
= last_geometry_rect
.right();
229 min_top
= last_geometry_rect
.y();
232 int inset_left
= std::max(0, min_left
- current_geometry_rect_
.x());
233 int inset_top
= std::max(0, min_top
- current_geometry_rect_
.y());
234 current_geometry_rect_
.Inset(inset_left
, inset_top
, 0, 0);
237 DCHECK_EQ(last_geometry_rect
.right(), current_geometry_rect_
.x());
238 DCHECK_EQ(last_geometry_rect
.bottom(), current_geometry_rect_
.bottom());
239 DCHECK_EQ(last_geometry_rect
.y(), current_geometry_rect_
.y());
245 gfx::Rect
PictureLayerTiling::Iterator::geometry_rect() const {
246 return current_geometry_rect_
;
249 gfx::RectF
PictureLayerTiling::Iterator::texture_rect() const {
250 gfx::Rect full_bounds
= tiling_
->tiling_data_
.TileBoundsWithBorder(tile_i_
,
252 full_bounds
.set_size(texture_size());
254 // Convert from dest space => content space => texture space.
255 gfx::RectF texture_rect
= gfx::ScaleRect(current_geometry_rect_
,
256 dest_to_content_scale_
);
257 texture_rect
.Offset(-full_bounds
.OffsetFromOrigin());
259 DCHECK_GE(texture_rect
.x(), 0);
260 DCHECK_GE(texture_rect
.y(), 0);
261 DCHECK_LE(texture_rect
.right(), texture_size().width());
262 DCHECK_LE(texture_rect
.bottom(), texture_size().height());
267 gfx::Size
PictureLayerTiling::Iterator::texture_size() const {
268 return tiling_
->tiling_data_
.max_texture_size();
271 void PictureLayerTiling::UpdateTilePriorities(
273 const gfx::Size
& device_viewport
,
274 float layer_content_scale_x
,
275 float layer_content_scale_y
,
276 const gfx::Transform
& last_screen_transform
,
277 const gfx::Transform
& current_screen_transform
,
279 gfx::Rect content_rect
= ContentRect();
280 if (content_rect
.IsEmpty())
283 gfx::Rect
view_rect(gfx::Point(), device_viewport
);
284 int right
= tiling_data_
.TileXIndexFromSrcCoord(content_rect
.width() - 1);
285 int bottom
= tiling_data_
.TileYIndexFromSrcCoord(content_rect
.height() - 1);
287 for (TileMap::const_iterator it
= tiles_
.begin(); it
!= tiles_
.end(); ++it
) {
288 TileMapKey key
= it
->first
;
289 TilePriority priority
;
290 if (key
.first
> right
|| key
.second
> bottom
) {
291 priority
.distance_to_visible_in_pixels
= std::numeric_limits
<int>::max();
292 priority
.time_to_visible_in_seconds
=
293 TilePriority::kMaxTimeToVisibleInSeconds
;
294 it
->second
->set_priority(tree
, priority
);
298 gfx::Rect tile_bound
= tiling_data_
.TileBounds(key
.first
, key
.second
);
299 gfx::RectF layer_content_rect
= gfx::ScaleRect(
301 layer_content_scale_x
/ contents_scale_
,
302 layer_content_scale_y
/ contents_scale_
);
303 gfx::RectF screen_rect
= MathUtil::mapClippedRect(
304 current_screen_transform
, layer_content_rect
);
305 gfx::RectF previous_rect
= MathUtil::mapClippedRect(
306 last_screen_transform
, layer_content_rect
);
308 priority
.resolution
= HIGH_RESOLUTION
;
309 priority
.time_to_visible_in_seconds
=
310 TilePriority::TimeForBoundsToIntersect(
311 previous_rect
, screen_rect
, time_delta
, view_rect
);
313 priority
.distance_to_visible_in_pixels
=
314 TilePriority::manhattanDistance(screen_rect
, view_rect
);
315 it
->second
->set_priority(tree
, priority
);