OLD | NEW |
| (Empty) |
1 // Copyright 2010 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/tiling_data.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ui/gfx/rect.h" | |
10 #include "ui/gfx/vector2d.h" | |
11 | |
12 namespace cc { | |
13 | |
14 static int ComputeNumTiles(int max_texture_size, int total_size, int border_texe
ls) { | |
15 if (max_texture_size - 2 * border_texels <= 0) | |
16 return total_size > 0 && max_texture_size >= total_size ? 1 : 0; | |
17 | |
18 int num_tiles = std::max(1, 1 + (total_size - 1 - 2 * border_texels) / (max_te
xture_size - 2 * border_texels)); | |
19 return total_size > 0 ? num_tiles : 0; | |
20 } | |
21 | |
22 TilingData::TilingData() | |
23 : border_texels_(0) { | |
24 RecomputeNumTiles(); | |
25 } | |
26 | |
27 TilingData::TilingData( | |
28 gfx::Size max_texture_size, | |
29 gfx::Size total_size, | |
30 bool hasBorderTexels) | |
31 : max_texture_size_(max_texture_size), | |
32 total_size_(total_size), | |
33 border_texels_(hasBorderTexels ? 1 : 0) { | |
34 RecomputeNumTiles(); | |
35 } | |
36 | |
37 TilingData::TilingData( | |
38 gfx::Size max_texture_size, | |
39 gfx::Size total_size, | |
40 int border_texels) | |
41 : max_texture_size_(max_texture_size), | |
42 total_size_(total_size), | |
43 border_texels_(border_texels) { | |
44 RecomputeNumTiles(); | |
45 } | |
46 | |
47 void TilingData::SetTotalSize(gfx::Size total_size) { | |
48 total_size_ = total_size; | |
49 RecomputeNumTiles(); | |
50 } | |
51 | |
52 void TilingData::SetMaxTextureSize(gfx::Size max_texture_size) { | |
53 max_texture_size_ = max_texture_size; | |
54 RecomputeNumTiles(); | |
55 } | |
56 | |
57 void TilingData::SetHasBorderTexels(bool has_border_texels) { | |
58 border_texels_ = has_border_texels ? 1 : 0; | |
59 RecomputeNumTiles(); | |
60 } | |
61 | |
62 void TilingData::SetBorderTexels(int border_texels) { | |
63 border_texels_ = border_texels; | |
64 RecomputeNumTiles(); | |
65 } | |
66 | |
67 int TilingData::TileXIndexFromSrcCoord(int src_position) const { | |
68 if (num_tiles_x_ <= 1) | |
69 return 0; | |
70 | |
71 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
72 int x = (src_position - border_texels_) / | |
73 (max_texture_size_.width() - 2 * border_texels_); | |
74 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
75 } | |
76 | |
77 int TilingData::TileYIndexFromSrcCoord(int src_position) const { | |
78 if (num_tiles_y_ <= 1) | |
79 return 0; | |
80 | |
81 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
82 int y = (src_position - border_texels_) / | |
83 (max_texture_size_.height() - 2 * border_texels_); | |
84 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
85 } | |
86 | |
87 int TilingData::FirstBorderTileXIndexFromSrcCoord(int src_position) const { | |
88 if (num_tiles_x_ <= 1) | |
89 return 0; | |
90 | |
91 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
92 int inner_tile_size = max_texture_size_.width() - 2 * border_texels_; | |
93 int x = (src_position - 2 * border_texels_) / inner_tile_size; | |
94 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
95 } | |
96 | |
97 int TilingData::FirstBorderTileYIndexFromSrcCoord(int src_position) const { | |
98 if (num_tiles_y_ <= 1) | |
99 return 0; | |
100 | |
101 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
102 int inner_tile_size = max_texture_size_.height() - 2 * border_texels_; | |
103 int y = (src_position - 2 * border_texels_) / inner_tile_size; | |
104 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
105 } | |
106 | |
107 int TilingData::LastBorderTileXIndexFromSrcCoord(int src_position) const { | |
108 if (num_tiles_x_ <= 1) | |
109 return 0; | |
110 | |
111 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
112 int inner_tile_size = max_texture_size_.width() - 2 * border_texels_; | |
113 int x = src_position / inner_tile_size; | |
114 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
115 } | |
116 | |
117 int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const { | |
118 if (num_tiles_y_ <= 1) | |
119 return 0; | |
120 | |
121 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
122 int inner_tile_size = max_texture_size_.height() - 2 * border_texels_; | |
123 int y = src_position / inner_tile_size; | |
124 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
125 } | |
126 | |
127 gfx::Rect TilingData::TileBounds(int i, int j) const { | |
128 AssertTile(i, j); | |
129 int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_; | |
130 int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_; | |
131 int total_size_x = total_size_.width(); | |
132 int total_size_y = total_size_.height(); | |
133 | |
134 int lo_x = max_texture_size_x * i; | |
135 if (i != 0) | |
136 lo_x += border_texels_; | |
137 | |
138 int lo_y = max_texture_size_y * j; | |
139 if (j != 0) | |
140 lo_y += border_texels_; | |
141 | |
142 int hi_x = max_texture_size_x * (i + 1) + border_texels_; | |
143 if (i + 1 == num_tiles_x_) | |
144 hi_x += border_texels_; | |
145 if (hi_x > total_size_x) | |
146 hi_x = total_size_x; | |
147 | |
148 int hi_y = max_texture_size_y * (j + 1) + border_texels_; | |
149 if (j + 1 == num_tiles_y_) | |
150 hi_y += border_texels_; | |
151 if (hi_y > total_size_y) | |
152 hi_y = total_size_y; | |
153 | |
154 int x = lo_x; | |
155 int y = lo_y; | |
156 int width = hi_x - lo_x; | |
157 int height = hi_y - lo_y; | |
158 DCHECK_GE(x, 0); | |
159 DCHECK_GE(y, 0); | |
160 DCHECK_GE(width, 0); | |
161 DCHECK_GE(height, 0); | |
162 DCHECK_LE(x, total_size_.width()); | |
163 DCHECK_LE(y, total_size_.height()); | |
164 return gfx::Rect(x, y, width, height); | |
165 } | |
166 | |
167 gfx::Rect TilingData::TileBoundsWithBorder(int i, int j) const { | |
168 gfx::Rect bounds = TileBounds(i, j); | |
169 | |
170 if (border_texels_) { | |
171 int x1 = bounds.x(); | |
172 int x2 = bounds.right(); | |
173 int y1 = bounds.y(); | |
174 int y2 = bounds.bottom(); | |
175 | |
176 if (i > 0) | |
177 x1-= border_texels_; | |
178 if (i < (num_tiles_x_ - 1)) | |
179 x2+= border_texels_; | |
180 if (j > 0) | |
181 y1-= border_texels_; | |
182 if (j < (num_tiles_y_ - 1)) | |
183 y2+= border_texels_; | |
184 | |
185 bounds = gfx::Rect(x1, y1, x2 - x1, y2 - y1); | |
186 } | |
187 | |
188 return bounds; | |
189 } | |
190 | |
191 int TilingData::TilePositionX(int x_index) const { | |
192 DCHECK_GE(x_index, 0); | |
193 DCHECK_LT(x_index, num_tiles_x_); | |
194 | |
195 int pos = (max_texture_size_.width() - 2 * border_texels_) * x_index; | |
196 if (x_index != 0) | |
197 pos += border_texels_; | |
198 | |
199 return pos; | |
200 } | |
201 | |
202 int TilingData::TilePositionY(int y_index) const { | |
203 DCHECK_GE(y_index, 0); | |
204 DCHECK_LT(y_index, num_tiles_y_); | |
205 | |
206 int pos = (max_texture_size_.height() - 2 * border_texels_) * y_index; | |
207 if (y_index != 0) | |
208 pos += border_texels_; | |
209 | |
210 return pos; | |
211 } | |
212 | |
213 int TilingData::TileSizeX(int x_index) const { | |
214 DCHECK_GE(x_index, 0); | |
215 DCHECK_LT(x_index, num_tiles_x_); | |
216 | |
217 if (!x_index && num_tiles_x_ == 1) | |
218 return total_size_.width(); | |
219 if (!x_index && num_tiles_x_ > 1) | |
220 return max_texture_size_.width() - border_texels_; | |
221 if (x_index < num_tiles_x_ - 1) | |
222 return max_texture_size_.width() - 2 * border_texels_; | |
223 if (x_index == num_tiles_x_ - 1) | |
224 return total_size_.width() - TilePositionX(x_index); | |
225 | |
226 NOTREACHED(); | |
227 return 0; | |
228 } | |
229 | |
230 int TilingData::TileSizeY(int y_index) const { | |
231 DCHECK_GE(y_index, 0); | |
232 DCHECK_LT(y_index, num_tiles_y_); | |
233 | |
234 if (!y_index && num_tiles_y_ == 1) | |
235 return total_size_.height(); | |
236 if (!y_index && num_tiles_y_ > 1) | |
237 return max_texture_size_.height() - border_texels_; | |
238 if (y_index < num_tiles_y_ - 1) | |
239 return max_texture_size_.height() - 2 * border_texels_; | |
240 if (y_index == num_tiles_y_ - 1) | |
241 return total_size_.height() - TilePositionY(y_index); | |
242 | |
243 NOTREACHED(); | |
244 return 0; | |
245 } | |
246 | |
247 gfx::Vector2d TilingData::TextureOffset(int x_index, int y_index) const { | |
248 int left = (!x_index || num_tiles_x_ == 1) ? 0 : border_texels_; | |
249 int top = (!y_index || num_tiles_y_ == 1) ? 0 : border_texels_; | |
250 | |
251 return gfx::Vector2d(left, top); | |
252 } | |
253 | |
254 void TilingData::RecomputeNumTiles() { | |
255 num_tiles_x_ = ComputeNumTiles(max_texture_size_.width(), total_size_.width(),
border_texels_); | |
256 num_tiles_y_ = ComputeNumTiles(max_texture_size_.height(), total_size_.height(
), border_texels_); | |
257 } | |
258 | |
259 TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data) | |
260 : tiling_data_(tiling_data), | |
261 index_x_(-1), | |
262 index_y_(-1) { | |
263 } | |
264 | |
265 TilingData::Iterator::Iterator(const TilingData* tiling_data, gfx::Rect rect) | |
266 : BaseIterator(tiling_data), | |
267 left_(-1), | |
268 right_(-1), | |
269 bottom_(-1) { | |
270 if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) { | |
271 done(); | |
272 return; | |
273 } | |
274 | |
275 rect.Intersect(gfx::Rect(tiling_data_->total_size())); | |
276 index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x()); | |
277 index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y()); | |
278 left_ = index_x_; | |
279 right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1); | |
280 bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1); | |
281 | |
282 // Index functions always return valid indices, so explicitly check | |
283 // for non-intersecting rects. | |
284 gfx::Rect new_rect = tiling_data_->TileBoundsWithBorder(index_x_, index_y_); | |
285 if (!new_rect.Intersects(rect)) | |
286 done(); | |
287 } | |
288 | |
289 TilingData::Iterator& TilingData::Iterator::operator++() { | |
290 if (!*this) | |
291 return *this; | |
292 | |
293 index_x_++; | |
294 if (index_x_ > right_) { | |
295 index_x_ = left_; | |
296 index_y_++; | |
297 if (index_y_ > bottom_) | |
298 done(); | |
299 } | |
300 | |
301 return *this; | |
302 } | |
303 | |
304 TilingData::DifferenceIterator::DifferenceIterator( | |
305 const TilingData* tiling_data, | |
306 gfx::Rect consider, | |
307 gfx::Rect ignore) | |
308 : BaseIterator(tiling_data), | |
309 consider_left_(-1), | |
310 consider_top_(-1), | |
311 consider_right_(-1), | |
312 consider_bottom_(-1), | |
313 ignore_left_(-1), | |
314 ignore_top_(-1), | |
315 ignore_right_(-1), | |
316 ignore_bottom_(-1) { | |
317 if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) { | |
318 done(); | |
319 return; | |
320 } | |
321 | |
322 gfx::Rect bounds(tiling_data_->total_size()); | |
323 consider.Intersect(bounds); | |
324 ignore.Intersect(bounds); | |
325 if (consider.IsEmpty()) { | |
326 done(); | |
327 return; | |
328 } | |
329 | |
330 consider_left_ = | |
331 tiling_data_->FirstBorderTileXIndexFromSrcCoord(consider.x()); | |
332 consider_top_ = | |
333 tiling_data_->FirstBorderTileYIndexFromSrcCoord(consider.y()); | |
334 consider_right_ = | |
335 tiling_data_->LastBorderTileXIndexFromSrcCoord(consider.right() - 1); | |
336 consider_bottom_ = | |
337 tiling_data_->LastBorderTileYIndexFromSrcCoord(consider.bottom() - 1); | |
338 | |
339 if (!ignore.IsEmpty()) { | |
340 ignore_left_ = | |
341 tiling_data_->FirstBorderTileXIndexFromSrcCoord(ignore.x()); | |
342 ignore_top_ = | |
343 tiling_data_->FirstBorderTileYIndexFromSrcCoord(ignore.y()); | |
344 ignore_right_ = | |
345 tiling_data_->LastBorderTileXIndexFromSrcCoord(ignore.right() - 1); | |
346 ignore_bottom_ = | |
347 tiling_data_->LastBorderTileYIndexFromSrcCoord(ignore.bottom() - 1); | |
348 | |
349 // Clamp ignore indices to consider indices. | |
350 ignore_left_ = std::max(ignore_left_, consider_left_); | |
351 ignore_top_ = std::max(ignore_top_, consider_top_); | |
352 ignore_right_ = std::min(ignore_right_, consider_right_); | |
353 ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_); | |
354 } | |
355 | |
356 if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ && | |
357 ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) { | |
358 done(); | |
359 return; | |
360 } | |
361 | |
362 index_x_ = consider_left_; | |
363 index_y_ = consider_top_; | |
364 | |
365 if (in_ignore_rect()) | |
366 ++(*this); | |
367 } | |
368 | |
369 TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() { | |
370 if (!*this) | |
371 return *this; | |
372 | |
373 index_x_++; | |
374 if (in_ignore_rect()) | |
375 index_x_ = ignore_right_ + 1; | |
376 | |
377 if (index_x_ > consider_right_) { | |
378 index_x_ = consider_left_; | |
379 index_y_++; | |
380 | |
381 if (in_ignore_rect()) { | |
382 index_x_ = ignore_right_ + 1; | |
383 // If the ignore rect spans the whole consider rect horizontally, then | |
384 // ignore_right + 1 will be out of bounds. | |
385 if (in_ignore_rect() || index_x_ > consider_right_) { | |
386 index_y_ = ignore_bottom_ + 1; | |
387 index_x_ = consider_left_; | |
388 } | |
389 } | |
390 | |
391 if (index_y_ > consider_bottom_) | |
392 done(); | |
393 } | |
394 | |
395 return *this; | |
396 } | |
397 | |
398 } // namespace cc | |
OLD | NEW |