OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/picture_layer_tiling.h" | 5 #include "cc/picture_layer_tiling.h" |
| 6 #include "ui/gfx/rect_conversions.h" |
| 7 #include "ui/gfx/size_conversions.h" |
6 | 8 |
7 namespace cc { | 9 namespace cc { |
8 | 10 |
9 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( | 11 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( |
| 12 float contents_scale, |
10 gfx::Size tile_size) { | 13 gfx::Size tile_size) { |
11 return make_scoped_ptr(new PictureLayerTiling(tile_size)); | 14 return make_scoped_ptr(new PictureLayerTiling(contents_scale, tile_size)); |
12 } | 15 } |
13 | 16 |
14 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Clone() const { | 17 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Clone() const { |
15 return make_scoped_ptr(new PictureLayerTiling(*this)); | 18 return make_scoped_ptr(new PictureLayerTiling(*this)); |
16 } | 19 } |
17 | 20 |
18 PictureLayerTiling::PictureLayerTiling(gfx::Size tile_size) | 21 PictureLayerTiling::PictureLayerTiling(float contents_scale, |
| 22 gfx::Size tile_size) |
19 : client_(NULL), | 23 : client_(NULL), |
| 24 contents_scale_(contents_scale), |
20 tiling_data_(tile_size, gfx::Size(), true) { | 25 tiling_data_(tile_size, gfx::Size(), true) { |
21 } | 26 } |
22 | 27 |
23 PictureLayerTiling::~PictureLayerTiling() { | 28 PictureLayerTiling::~PictureLayerTiling() { |
24 } | 29 } |
25 | 30 |
26 const PictureLayerTiling& PictureLayerTiling::operator=( | 31 const PictureLayerTiling& PictureLayerTiling::operator=( |
27 const PictureLayerTiling& tiler) { | 32 const PictureLayerTiling& tiler) { |
28 tiling_data_ = tiler.tiling_data_; | 33 tiling_data_ = tiler.tiling_data_; |
29 tiles_ = tiler.tiles_; | 34 tiles_ = tiler.tiles_; |
30 return *this; | 35 return *this; |
31 } | 36 } |
32 | 37 |
33 void PictureLayerTiling::create_tiles(gfx::Rect rect) { | 38 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) { |
34 for (Iterator iter(this, rect); iter; ++iter) { | |
35 if (*iter) | |
36 continue; | |
37 tiles_[std::make_pair(iter.tile_i_, iter.tile_j_)] = | |
38 client_->CreateTile(this, iter.full_tile_rect()); | |
39 } | |
40 } | |
41 | |
42 void PictureLayerTiling::set_client(PictureLayerTilingClient* client) { | |
43 client_ = client; | 39 client_ = client; |
44 } | 40 } |
45 | 41 |
| 42 gfx::Rect PictureLayerTiling::ContentRect() const { |
| 43 gfx::Size content_bounds = |
| 44 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); |
| 45 return gfx::Rect(gfx::Point(), content_bounds); |
| 46 } |
| 47 |
46 Tile* PictureLayerTiling::TileAt(int i, int j) const { | 48 Tile* PictureLayerTiling::TileAt(int i, int j) const { |
47 TileMap::const_iterator iter = tiles_.find(std::make_pair(i, j)); | 49 TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j)); |
48 if (iter == tiles_.end()) | 50 if (iter == tiles_.end()) |
49 return NULL; | 51 return NULL; |
50 return iter->second.get(); | 52 return iter->second.get(); |
51 } | 53 } |
52 | 54 |
| 55 void PictureLayerTiling::CreateTile(int i, int j) { |
| 56 gfx::Rect tile_rect = tiling_data_.TileBoundsWithBorder(i, j); |
| 57 tile_rect.set_size(tiling_data_.max_texture_size()); |
| 58 TileMapKey key(i, j); |
| 59 DCHECK(!tiles_[key]); |
| 60 tiles_[key] = client_->CreateTile(this, tile_rect); |
| 61 } |
| 62 |
53 Region PictureLayerTiling::OpaqueRegionInContentRect( | 63 Region PictureLayerTiling::OpaqueRegionInContentRect( |
54 const gfx::Rect& content_rect) const { | 64 const gfx::Rect& content_rect) const { |
55 Region opaque_region; | 65 Region opaque_region; |
56 // TODO(enne): implement me | 66 // TODO(enne): implement me |
57 return opaque_region; | 67 return opaque_region; |
58 } | 68 } |
59 | 69 |
60 void PictureLayerTiling::SetBounds(gfx::Size size) { | 70 void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) { |
61 tiling_data_.SetTotalSize(size); | 71 if (layer_bounds_ == layer_bounds) |
62 if (size.IsEmpty()) { | 72 return; |
| 73 |
| 74 layer_bounds_ = layer_bounds; |
| 75 gfx::Size content_bounds = |
| 76 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); |
| 77 |
| 78 tiling_data_.SetTotalSize(content_bounds); |
| 79 if (layer_bounds_.IsEmpty()) { |
63 tiles_.clear(); | 80 tiles_.clear(); |
64 return; | 81 return; |
65 } | 82 } |
66 | 83 |
| 84 int right = tiling_data_.TileXIndexFromSrcCoord(content_bounds.width() - 1); |
| 85 int bottom = tiling_data_.TileYIndexFromSrcCoord(content_bounds.height() - 1); |
| 86 |
| 87 // TODO(enne): Be more efficient about what tiles are created. |
| 88 for (int j = 0; j <= bottom; ++j) { |
| 89 for (int i = 0; i <= right; ++i) { |
| 90 if (tiles_.find(TileMapKey(i, j)) == tiles_.end()) |
| 91 CreateTile(i, j); |
| 92 } |
| 93 } |
| 94 |
67 // Any tiles outside our new bounds are invalid and should be dropped. | 95 // Any tiles outside our new bounds are invalid and should be dropped. |
68 int right = tiling_data_.TileXIndexFromSrcCoord(size.width() - 1); | |
69 int bottom = tiling_data_.TileYIndexFromSrcCoord(size.height() - 1); | |
70 std::vector<TileMapKey> invalid_tile_keys; | 96 std::vector<TileMapKey> invalid_tile_keys; |
71 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | 97 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
72 if (it->first.first > right || it->first.second > bottom) | 98 if (it->first.first > right || it->first.second > bottom) |
73 invalid_tile_keys.push_back(it->first); | 99 invalid_tile_keys.push_back(it->first); |
74 } | 100 } |
75 for (size_t i = 0; i < invalid_tile_keys.size(); ++i) | 101 for (size_t i = 0; i < invalid_tile_keys.size(); ++i) |
76 tiles_.erase(invalid_tile_keys[i]); | 102 tiles_.erase(invalid_tile_keys[i]); |
77 } | 103 } |
78 | 104 |
79 PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling, | 105 void PictureLayerTiling::Invalidate(const Region& layer_invalidation) { |
80 gfx::Rect content_rect) | 106 std::vector<TileMapKey> new_tiles; |
81 : tiling_(tiling), | 107 |
82 content_rect_(content_rect), | 108 for (Region::Iterator region_iter(layer_invalidation); |
| 109 region_iter.has_rect(); |
| 110 region_iter.next()) { |
| 111 |
| 112 gfx::Rect rect = |
| 113 gfx::ToEnclosingRect(ScaleRect(region_iter.rect(), contents_scale_)); |
| 114 rect.Intersect(ContentRect()); |
| 115 |
| 116 for (PictureLayerTiling::Iterator tile_iter(this, contents_scale_, rect); |
| 117 tile_iter; |
| 118 ++tile_iter) { |
| 119 TileMapKey key(tile_iter.tile_i_, tile_iter.tile_j_); |
| 120 if (!tiles_[key]) |
| 121 continue; |
| 122 |
| 123 tiles_[key] = NULL; |
| 124 new_tiles.push_back(key); |
| 125 } |
| 126 } |
| 127 |
| 128 for (size_t i = 0; i < new_tiles.size(); ++i) { |
| 129 CreateTile(new_tiles[i].first, new_tiles[i].second); |
| 130 } |
| 131 } |
| 132 |
| 133 PictureLayerTiling::Iterator::Iterator() |
| 134 : tiling_(NULL), |
83 current_tile_(NULL), | 135 current_tile_(NULL), |
84 tile_i_(0), | 136 tile_i_(0), |
85 tile_j_(0), | 137 tile_j_(0), |
| 138 left_(0), |
| 139 top_(0), |
| 140 right_(0), |
| 141 bottom_(0) { |
| 142 } |
| 143 |
| 144 PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling, |
| 145 float dest_scale, |
| 146 gfx::Rect dest_rect) |
| 147 : tiling_(tiling), |
| 148 dest_rect_(dest_rect), |
| 149 dest_to_content_scale_(tiling_->contents_scale_ / dest_scale), |
| 150 current_tile_(NULL), |
| 151 tile_i_(0), |
| 152 tile_j_(0), |
86 left_(0), | 153 left_(0), |
87 top_(0), | 154 top_(0), |
88 right_(0), | 155 right_(0), |
89 bottom_(0) { | 156 bottom_(0) { |
90 DCHECK(tiling_); | 157 DCHECK(tiling_); |
91 if (content_rect_.IsEmpty()) | 158 if (dest_rect_.IsEmpty()) |
92 return; | 159 return; |
93 | 160 |
| 161 gfx::Rect content_rect = |
| 162 gfx::ToEnclosingRect(gfx::ScaleRect(dest_rect_, dest_to_content_scale_)); |
| 163 |
94 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); | 164 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); |
95 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); | 165 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); |
96 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( | 166 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( |
97 content_rect.right() - 1); | 167 content_rect.right() - 1); |
98 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( | 168 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( |
99 content_rect.bottom() - 1); | 169 content_rect.bottom() - 1); |
100 | 170 |
101 tile_i_ = left_; | 171 tile_i_ = left_ - 1; |
102 tile_j_ = top_; | 172 tile_j_ = top_; |
103 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); | 173 ++(*this); |
104 } | 174 } |
105 | 175 |
106 PictureLayerTiling::Iterator::~Iterator() { | 176 PictureLayerTiling::Iterator::~Iterator() { |
107 } | 177 } |
108 | 178 |
109 PictureLayerTiling::Iterator& PictureLayerTiling::Iterator::operator++() { | 179 PictureLayerTiling::Iterator& PictureLayerTiling::Iterator::operator++() { |
110 if (!current_tile_) | 180 if (tile_j_ > bottom_) |
111 return *this; | 181 return *this; |
112 | 182 |
113 do { | 183 bool first_time = tile_i_ < left_; |
114 tile_i_++; | 184 bool new_row = false; |
115 if (tile_i_ > right_) { | 185 tile_i_++; |
116 tile_i_ = left_; | 186 if (tile_i_ > right_) { |
117 tile_j_++; | 187 tile_i_ = left_; |
118 if (tile_j_ > top_) | 188 tile_j_++; |
119 current_tile_ = NULL; | 189 new_row = true; |
120 return *this; | 190 if (tile_j_ > bottom_) { |
| 191 current_tile_ = NULL; |
| 192 return *this; |
121 } | 193 } |
122 } while (!geometry_rect().IsEmpty()); | 194 } |
123 | 195 |
124 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); | 196 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); |
| 197 |
| 198 // Calculate the current geometry rect. Due to floating point rounding |
| 199 // and ToEnclosedRect, tiles might overlap in destination space on the |
| 200 // edges. |
| 201 gfx::Rect last_geometry_rect = current_geometry_rect_; |
| 202 |
| 203 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); |
| 204 current_geometry_rect_ = gfx::ToEnclosingRect( |
| 205 gfx::ScaleRect(content_rect, 1 / dest_to_content_scale_)); |
| 206 current_geometry_rect_.Intersect(dest_rect_); |
| 207 |
| 208 if (first_time) |
| 209 return *this; |
| 210 |
| 211 // Iteration happens left->right, top->bottom. Running off the bottom-right |
| 212 // edge is handled by the intersection above with dest_rect_. Here we make |
| 213 // sure that the new current geometry rect doesn't overlap with the last. |
| 214 int min_left; |
| 215 int min_top; |
| 216 if (new_row) { |
| 217 min_left = dest_rect_.x(); |
| 218 min_top = last_geometry_rect.bottom(); |
| 219 } else { |
| 220 min_left = last_geometry_rect.right(); |
| 221 min_top = last_geometry_rect.y(); |
| 222 } |
| 223 |
| 224 int inset_left = std::max(0, min_left - current_geometry_rect_.x()); |
| 225 int inset_top = std::max(0, min_top - current_geometry_rect_.y()); |
| 226 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0); |
| 227 |
| 228 if (!new_row) { |
| 229 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x()); |
| 230 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom()); |
| 231 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y()); |
| 232 } |
| 233 |
125 return *this; | 234 return *this; |
126 } | 235 } |
127 | 236 |
128 gfx::Rect PictureLayerTiling::Iterator::geometry_rect() const { | 237 gfx::Rect PictureLayerTiling::Iterator::geometry_rect() const { |
129 gfx::Rect geometry_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); | 238 return current_geometry_rect_; |
130 geometry_rect.Intersect(content_rect_); | |
131 return geometry_rect; | |
132 } | 239 } |
133 | 240 |
134 gfx::Rect PictureLayerTiling::Iterator::full_tile_rect() const { | 241 gfx::RectF PictureLayerTiling::Iterator::texture_rect() const { |
135 gfx::Rect tile_rect = | 242 gfx::Rect full_bounds = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, |
136 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_); | 243 tile_j_); |
137 tile_rect.set_size(texture_size()); | 244 full_bounds.set_size(texture_size()); |
138 return tile_rect; | |
139 } | |
140 | 245 |
141 gfx::Rect PictureLayerTiling::Iterator::texture_rect() const { | 246 // Convert from dest space => content space => texture space. |
142 gfx::Rect full_bounds = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); | 247 gfx::RectF texture_rect = gfx::ScaleRect(current_geometry_rect_, |
143 gfx::Rect visible = geometry_rect(); | 248 dest_to_content_scale_); |
144 gfx::Vector2d display_offset = visible.origin() - full_bounds.origin(); | 249 texture_rect.Offset(-full_bounds.OffsetFromOrigin()); |
145 gfx::Vector2d offset = visible.origin() - full_bounds.origin(); | |
146 offset += tiling_->tiling_data_.TextureOffset(tile_i_, tile_j_); | |
147 | 250 |
148 return gfx::Rect(gfx::PointAtOffsetFromOrigin(offset), visible.size()); | 251 DCHECK_GE(texture_rect.x(), 0); |
149 } | 252 DCHECK_GE(texture_rect.y(), 0); |
| 253 DCHECK_LE(texture_rect.right(), texture_size().width()); |
| 254 DCHECK_LE(texture_rect.bottom(), texture_size().height()); |
150 | 255 |
151 gfx::Rect PictureLayerTiling::Iterator::opaque_rect() const { | 256 return texture_rect; |
152 gfx::Rect opaque_rect; | |
153 opaque_rect = current_tile_->opaque_rect(); | |
154 opaque_rect.Intersect(content_rect_); | |
155 return opaque_rect; | |
156 } | 257 } |
157 | 258 |
158 gfx::Size PictureLayerTiling::Iterator::texture_size() const { | 259 gfx::Size PictureLayerTiling::Iterator::texture_size() const { |
159 return tiling_->tiling_data_.max_texture_size(); | 260 return tiling_->tiling_data_.max_texture_size(); |
160 } | 261 } |
161 | 262 |
162 bool PictureLayerTiling::Iterator::operator==(const Iterator& other) const { | |
163 return tiling_ == other.tiling_ && current_tile_ == other.current_tile_; | |
164 } | |
165 | |
166 bool PictureLayerTiling::Iterator::operator!=(const Iterator& other) const { | |
167 return !(*this == other); | |
168 } | |
169 | |
170 } // namespace cc | 263 } // namespace cc |
OLD | NEW |