Mailbox support for texture layers.
[chromium-blink-merge.git] / cc / picture_layer_tiling.cc
blob7ea16fd47e6211154fba2603ed6c279ae373b367
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"
11 namespace cc {
13 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
14 float contents_scale,
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,
24 gfx::Size tile_size)
25 : client_(NULL),
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_;
37 return *this;
40 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
41 client_ = 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())
53 return NULL;
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());
60 TileMapKey key(i, j);
61 DCHECK(!tiles_[key]);
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 {
73 Region opaque_region;
74 // TODO(enne): implement me
75 return opaque_region;
78 void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) {
79 if (layer_bounds_ == layer_bounds)
80 return;
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()) {
88 tiles_.clear();
89 return;
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())
99 CreateTile(i, j);
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()) {
120 gfx::Rect rect =
121 gfx::ToEnclosingRect(ScaleRect(region_iter.rect(), contents_scale_));
122 rect.Intersect(ContentRect());
124 for (PictureLayerTiling::Iterator tile_iter(this, contents_scale_, rect);
125 tile_iter;
126 ++tile_iter) {
127 TileMapKey key(tile_iter.tile_i_, tile_iter.tile_j_);
128 if (!tiles_[key])
129 continue;
131 tiles_[key] = NULL;
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()
142 : tiling_(NULL),
143 current_tile_(NULL),
144 tile_i_(0),
145 tile_j_(0),
146 left_(0),
147 top_(0),
148 right_(0),
149 bottom_(0) {
152 PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling,
153 float dest_scale,
154 gfx::Rect dest_rect)
155 : tiling_(tiling),
156 dest_rect_(dest_rect),
157 dest_to_content_scale_(tiling_->contents_scale_ / dest_scale),
158 current_tile_(NULL),
159 tile_i_(0),
160 tile_j_(0),
161 left_(0),
162 top_(0),
163 right_(0),
164 bottom_(0) {
165 DCHECK(tiling_);
166 if (dest_rect_.IsEmpty())
167 return;
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);
179 tile_i_ = left_ - 1;
180 tile_j_ = top_;
181 ++(*this);
184 PictureLayerTiling::Iterator::~Iterator() {
187 PictureLayerTiling::Iterator& PictureLayerTiling::Iterator::operator++() {
188 if (tile_j_ > bottom_)
189 return *this;
191 bool first_time = tile_i_ < left_;
192 bool new_row = false;
193 tile_i_++;
194 if (tile_i_ > right_) {
195 tile_i_ = left_;
196 tile_j_++;
197 new_row = true;
198 if (tile_j_ > bottom_) {
199 current_tile_ = NULL;
200 return *this;
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
208 // edges.
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_);
216 if (first_time)
217 return *this;
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.
222 int min_left;
223 int min_top;
224 if (new_row) {
225 min_left = dest_rect_.x();
226 min_top = last_geometry_rect.bottom();
227 } else {
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);
236 if (!new_row) {
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());
242 return *this;
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_,
251 tile_j_);
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());
264 return texture_rect;
267 gfx::Size PictureLayerTiling::Iterator::texture_size() const {
268 return tiling_->tiling_data_.max_texture_size();
271 void PictureLayerTiling::UpdateTilePriorities(
272 WhichTree tree,
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,
278 double time_delta) {
279 gfx::Rect content_rect = ContentRect();
280 if (content_rect.IsEmpty())
281 return;
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);
295 continue;
298 gfx::Rect tile_bound = tiling_data_.TileBounds(key.first, key.second);
299 gfx::RectF layer_content_rect = gfx::ScaleRect(
300 tile_bound,
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);
319 } // namespace cc