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/base/tiling_data.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ui/gfx/geometry/rect.h" | |
10 #include "ui/gfx/geometry/vector2d.h" | |
11 | |
12 namespace cc { | |
13 | |
14 static int ComputeNumTiles(int max_texture_size, | |
15 int total_size, | |
16 int border_texels) { | |
17 if (max_texture_size - 2 * border_texels <= 0) | |
18 return total_size > 0 && max_texture_size >= total_size ? 1 : 0; | |
19 | |
20 int num_tiles = std::max(1, | |
21 1 + (total_size - 1 - 2 * border_texels) / | |
22 (max_texture_size - 2 * border_texels)); | |
23 return total_size > 0 ? num_tiles : 0; | |
24 } | |
25 | |
26 TilingData::TilingData() | |
27 : border_texels_(0) { | |
28 RecomputeNumTiles(); | |
29 } | |
30 | |
31 TilingData::TilingData(const gfx::Size& max_texture_size, | |
32 const gfx::Size& tiling_size, | |
33 bool has_border_texels) | |
34 : max_texture_size_(max_texture_size), | |
35 tiling_size_(tiling_size), | |
36 border_texels_(has_border_texels ? 1 : 0) { | |
37 RecomputeNumTiles(); | |
38 } | |
39 | |
40 TilingData::TilingData(const gfx::Size& max_texture_size, | |
41 const gfx::Size& tiling_size, | |
42 int border_texels) | |
43 : max_texture_size_(max_texture_size), | |
44 tiling_size_(tiling_size), | |
45 border_texels_(border_texels) { | |
46 RecomputeNumTiles(); | |
47 } | |
48 | |
49 void TilingData::SetTilingSize(const gfx::Size& tiling_size) { | |
50 tiling_size_ = tiling_size; | |
51 RecomputeNumTiles(); | |
52 } | |
53 | |
54 void TilingData::SetMaxTextureSize(const gfx::Size& max_texture_size) { | |
55 max_texture_size_ = max_texture_size; | |
56 RecomputeNumTiles(); | |
57 } | |
58 | |
59 void TilingData::SetHasBorderTexels(bool has_border_texels) { | |
60 border_texels_ = has_border_texels ? 1 : 0; | |
61 RecomputeNumTiles(); | |
62 } | |
63 | |
64 void TilingData::SetBorderTexels(int border_texels) { | |
65 border_texels_ = border_texels; | |
66 RecomputeNumTiles(); | |
67 } | |
68 | |
69 int TilingData::TileXIndexFromSrcCoord(int src_position) const { | |
70 if (num_tiles_x_ <= 1) | |
71 return 0; | |
72 | |
73 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
74 int x = (src_position - border_texels_) / | |
75 (max_texture_size_.width() - 2 * border_texels_); | |
76 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
77 } | |
78 | |
79 int TilingData::TileYIndexFromSrcCoord(int src_position) const { | |
80 if (num_tiles_y_ <= 1) | |
81 return 0; | |
82 | |
83 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
84 int y = (src_position - border_texels_) / | |
85 (max_texture_size_.height() - 2 * border_texels_); | |
86 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
87 } | |
88 | |
89 int TilingData::FirstBorderTileXIndexFromSrcCoord(int src_position) const { | |
90 if (num_tiles_x_ <= 1) | |
91 return 0; | |
92 | |
93 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
94 int inner_tile_size = max_texture_size_.width() - 2 * border_texels_; | |
95 int x = (src_position - 2 * border_texels_) / inner_tile_size; | |
96 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
97 } | |
98 | |
99 int TilingData::FirstBorderTileYIndexFromSrcCoord(int src_position) const { | |
100 if (num_tiles_y_ <= 1) | |
101 return 0; | |
102 | |
103 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
104 int inner_tile_size = max_texture_size_.height() - 2 * border_texels_; | |
105 int y = (src_position - 2 * border_texels_) / inner_tile_size; | |
106 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
107 } | |
108 | |
109 int TilingData::LastBorderTileXIndexFromSrcCoord(int src_position) const { | |
110 if (num_tiles_x_ <= 1) | |
111 return 0; | |
112 | |
113 DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0); | |
114 int inner_tile_size = max_texture_size_.width() - 2 * border_texels_; | |
115 int x = src_position / inner_tile_size; | |
116 return std::min(std::max(x, 0), num_tiles_x_ - 1); | |
117 } | |
118 | |
119 int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const { | |
120 if (num_tiles_y_ <= 1) | |
121 return 0; | |
122 | |
123 DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0); | |
124 int inner_tile_size = max_texture_size_.height() - 2 * border_texels_; | |
125 int y = src_position / inner_tile_size; | |
126 return std::min(std::max(y, 0), num_tiles_y_ - 1); | |
127 } | |
128 | |
129 gfx::Rect TilingData::ExpandRectIgnoringBordersToTileBounds( | |
130 const gfx::Rect& rect) const { | |
131 if (rect.IsEmpty() || has_empty_bounds()) | |
132 return gfx::Rect(); | |
133 if (rect.x() > tiling_size_.width() || rect.y() > tiling_size_.height()) | |
134 return gfx::Rect(); | |
135 int index_x = TileXIndexFromSrcCoord(rect.x()); | |
136 int index_y = TileYIndexFromSrcCoord(rect.y()); | |
137 int index_right = TileXIndexFromSrcCoord(rect.right() - 1); | |
138 int index_bottom = TileYIndexFromSrcCoord(rect.bottom() - 1); | |
139 | |
140 gfx::Rect rect_top_left(TileBounds(index_x, index_y)); | |
141 gfx::Rect rect_bottom_right(TileBounds(index_right, index_bottom)); | |
142 | |
143 return gfx::UnionRects(rect_top_left, rect_bottom_right); | |
144 } | |
145 | |
146 gfx::Rect TilingData::ExpandRectToTileBounds(const gfx::Rect& rect) const { | |
147 if (rect.IsEmpty() || has_empty_bounds()) | |
148 return gfx::Rect(); | |
149 if (rect.x() > tiling_size_.width() || rect.y() > tiling_size_.height()) | |
150 return gfx::Rect(); | |
151 int index_x = FirstBorderTileXIndexFromSrcCoord(rect.x()); | |
152 int index_y = FirstBorderTileYIndexFromSrcCoord(rect.y()); | |
153 int index_right = LastBorderTileXIndexFromSrcCoord(rect.right() - 1); | |
154 int index_bottom = LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1); | |
155 | |
156 gfx::Rect rect_top_left(TileBounds(index_x, index_y)); | |
157 gfx::Rect rect_bottom_right(TileBounds(index_right, index_bottom)); | |
158 | |
159 return gfx::UnionRects(rect_top_left, rect_bottom_right); | |
160 } | |
161 | |
162 gfx::Rect TilingData::TileBounds(int i, int j) const { | |
163 AssertTile(i, j); | |
164 int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_; | |
165 int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_; | |
166 | |
167 int lo_x = max_texture_size_x * i; | |
168 if (i != 0) | |
169 lo_x += border_texels_; | |
170 | |
171 int lo_y = max_texture_size_y * j; | |
172 if (j != 0) | |
173 lo_y += border_texels_; | |
174 | |
175 int hi_x = max_texture_size_x * (i + 1) + border_texels_; | |
176 if (i + 1 == num_tiles_x_) | |
177 hi_x += border_texels_; | |
178 | |
179 int hi_y = max_texture_size_y * (j + 1) + border_texels_; | |
180 if (j + 1 == num_tiles_y_) | |
181 hi_y += border_texels_; | |
182 | |
183 hi_x = std::min(hi_x, tiling_size_.width()); | |
184 hi_y = std::min(hi_y, tiling_size_.height()); | |
185 | |
186 int x = lo_x; | |
187 int y = lo_y; | |
188 int width = hi_x - lo_x; | |
189 int height = hi_y - lo_y; | |
190 DCHECK_GE(x, 0); | |
191 DCHECK_GE(y, 0); | |
192 DCHECK_GE(width, 0); | |
193 DCHECK_GE(height, 0); | |
194 DCHECK_LE(x, tiling_size_.width()); | |
195 DCHECK_LE(y, tiling_size_.height()); | |
196 return gfx::Rect(x, y, width, height); | |
197 } | |
198 | |
199 gfx::Rect TilingData::TileBoundsWithBorder(int i, int j) const { | |
200 AssertTile(i, j); | |
201 int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_; | |
202 int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_; | |
203 | |
204 int lo_x = max_texture_size_x * i; | |
205 int lo_y = max_texture_size_y * j; | |
206 | |
207 int hi_x = lo_x + max_texture_size_x + 2 * border_texels_; | |
208 int hi_y = lo_y + max_texture_size_y + 2 * border_texels_; | |
209 | |
210 hi_x = std::min(hi_x, tiling_size_.width()); | |
211 hi_y = std::min(hi_y, tiling_size_.height()); | |
212 | |
213 int x = lo_x; | |
214 int y = lo_y; | |
215 int width = hi_x - lo_x; | |
216 int height = hi_y - lo_y; | |
217 DCHECK_GE(x, 0); | |
218 DCHECK_GE(y, 0); | |
219 DCHECK_GE(width, 0); | |
220 DCHECK_GE(height, 0); | |
221 DCHECK_LE(x, tiling_size_.width()); | |
222 DCHECK_LE(y, tiling_size_.height()); | |
223 return gfx::Rect(x, y, width, height); | |
224 } | |
225 | |
226 int TilingData::TilePositionX(int x_index) const { | |
227 DCHECK_GE(x_index, 0); | |
228 DCHECK_LT(x_index, num_tiles_x_); | |
229 | |
230 int pos = (max_texture_size_.width() - 2 * border_texels_) * x_index; | |
231 if (x_index != 0) | |
232 pos += border_texels_; | |
233 | |
234 return pos; | |
235 } | |
236 | |
237 int TilingData::TilePositionY(int y_index) const { | |
238 DCHECK_GE(y_index, 0); | |
239 DCHECK_LT(y_index, num_tiles_y_); | |
240 | |
241 int pos = (max_texture_size_.height() - 2 * border_texels_) * y_index; | |
242 if (y_index != 0) | |
243 pos += border_texels_; | |
244 | |
245 return pos; | |
246 } | |
247 | |
248 int TilingData::TileSizeX(int x_index) const { | |
249 DCHECK_GE(x_index, 0); | |
250 DCHECK_LT(x_index, num_tiles_x_); | |
251 | |
252 if (!x_index && num_tiles_x_ == 1) | |
253 return tiling_size_.width(); | |
254 if (!x_index && num_tiles_x_ > 1) | |
255 return max_texture_size_.width() - border_texels_; | |
256 if (x_index < num_tiles_x_ - 1) | |
257 return max_texture_size_.width() - 2 * border_texels_; | |
258 if (x_index == num_tiles_x_ - 1) | |
259 return tiling_size_.width() - TilePositionX(x_index); | |
260 | |
261 NOTREACHED(); | |
262 return 0; | |
263 } | |
264 | |
265 int TilingData::TileSizeY(int y_index) const { | |
266 DCHECK_GE(y_index, 0); | |
267 DCHECK_LT(y_index, num_tiles_y_); | |
268 | |
269 if (!y_index && num_tiles_y_ == 1) | |
270 return tiling_size_.height(); | |
271 if (!y_index && num_tiles_y_ > 1) | |
272 return max_texture_size_.height() - border_texels_; | |
273 if (y_index < num_tiles_y_ - 1) | |
274 return max_texture_size_.height() - 2 * border_texels_; | |
275 if (y_index == num_tiles_y_ - 1) | |
276 return tiling_size_.height() - TilePositionY(y_index); | |
277 | |
278 NOTREACHED(); | |
279 return 0; | |
280 } | |
281 | |
282 gfx::Vector2d TilingData::TextureOffset(int x_index, int y_index) const { | |
283 int left = (!x_index || num_tiles_x_ == 1) ? 0 : border_texels_; | |
284 int top = (!y_index || num_tiles_y_ == 1) ? 0 : border_texels_; | |
285 | |
286 return gfx::Vector2d(left, top); | |
287 } | |
288 | |
289 void TilingData::RecomputeNumTiles() { | |
290 num_tiles_x_ = ComputeNumTiles( | |
291 max_texture_size_.width(), tiling_size_.width(), border_texels_); | |
292 num_tiles_y_ = ComputeNumTiles( | |
293 max_texture_size_.height(), tiling_size_.height(), border_texels_); | |
294 } | |
295 | |
296 TilingData::BaseIterator::BaseIterator() : index_x_(-1), index_y_(-1) { | |
297 } | |
298 | |
299 TilingData::Iterator::Iterator() { | |
300 done(); | |
301 } | |
302 | |
303 TilingData::Iterator::Iterator(const TilingData* tiling_data, | |
304 const gfx::Rect& consider_rect, | |
305 bool include_borders) | |
306 : left_(-1), right_(-1), bottom_(-1) { | |
307 if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) { | |
308 done(); | |
309 return; | |
310 } | |
311 | |
312 gfx::Rect tiling_bounds_rect(tiling_data->tiling_size()); | |
313 gfx::Rect rect(consider_rect); | |
314 rect.Intersect(tiling_bounds_rect); | |
315 | |
316 gfx::Rect top_left_tile; | |
317 if (include_borders) { | |
318 index_x_ = tiling_data->FirstBorderTileXIndexFromSrcCoord(rect.x()); | |
319 index_y_ = tiling_data->FirstBorderTileYIndexFromSrcCoord(rect.y()); | |
320 right_ = tiling_data->LastBorderTileXIndexFromSrcCoord(rect.right() - 1); | |
321 bottom_ = tiling_data->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1); | |
322 top_left_tile = tiling_data->TileBoundsWithBorder(index_x_, index_y_); | |
323 } else { | |
324 index_x_ = tiling_data->TileXIndexFromSrcCoord(rect.x()); | |
325 index_y_ = tiling_data->TileYIndexFromSrcCoord(rect.y()); | |
326 right_ = tiling_data->TileXIndexFromSrcCoord(rect.right() - 1); | |
327 bottom_ = tiling_data->TileYIndexFromSrcCoord(rect.bottom() - 1); | |
328 top_left_tile = tiling_data->TileBounds(index_x_, index_y_); | |
329 } | |
330 left_ = index_x_; | |
331 | |
332 // Index functions always return valid indices, so explicitly check | |
333 // for non-intersecting rects. | |
334 if (!top_left_tile.Intersects(rect)) | |
335 done(); | |
336 } | |
337 | |
338 TilingData::Iterator& TilingData::Iterator::operator++() { | |
339 if (!*this) | |
340 return *this; | |
341 | |
342 index_x_++; | |
343 if (index_x_ > right_) { | |
344 index_x_ = left_; | |
345 index_y_++; | |
346 if (index_y_ > bottom_) | |
347 done(); | |
348 } | |
349 | |
350 return *this; | |
351 } | |
352 | |
353 TilingData::BaseDifferenceIterator::BaseDifferenceIterator() { | |
354 done(); | |
355 } | |
356 | |
357 TilingData::BaseDifferenceIterator::BaseDifferenceIterator( | |
358 const TilingData* tiling_data, | |
359 const gfx::Rect& consider_rect, | |
360 const gfx::Rect& ignore_rect) | |
361 : consider_left_(-1), | |
362 consider_top_(-1), | |
363 consider_right_(-1), | |
364 consider_bottom_(-1), | |
365 ignore_left_(-1), | |
366 ignore_top_(-1), | |
367 ignore_right_(-1), | |
368 ignore_bottom_(-1) { | |
369 if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) { | |
370 done(); | |
371 return; | |
372 } | |
373 | |
374 gfx::Rect tiling_bounds_rect(tiling_data->tiling_size()); | |
375 gfx::Rect consider(consider_rect); | |
376 consider.Intersect(tiling_bounds_rect); | |
377 | |
378 if (consider.IsEmpty()) { | |
379 done(); | |
380 return; | |
381 } | |
382 | |
383 consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x()); | |
384 consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y()); | |
385 consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1); | |
386 consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1); | |
387 | |
388 gfx::Rect ignore(ignore_rect); | |
389 ignore.Intersect(tiling_bounds_rect); | |
390 | |
391 if (!ignore.IsEmpty()) { | |
392 ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x()); | |
393 ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y()); | |
394 ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1); | |
395 ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1); | |
396 | |
397 // Clamp ignore indices to consider indices. | |
398 ignore_left_ = std::max(ignore_left_, consider_left_); | |
399 ignore_top_ = std::max(ignore_top_, consider_top_); | |
400 ignore_right_ = std::min(ignore_right_, consider_right_); | |
401 ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_); | |
402 | |
403 if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ && | |
404 ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) { | |
405 consider_left_ = consider_top_ = consider_right_ = consider_bottom_ = -1; | |
406 done(); | |
407 return; | |
408 } | |
409 } | |
410 } | |
411 | |
412 bool TilingData::BaseDifferenceIterator::HasConsiderRect() const { | |
413 // Consider indices are either all valid or all equal to -1. | |
414 DCHECK((0 <= consider_left_ && consider_left_ <= consider_right_ && | |
415 0 <= consider_top_ && consider_top_ <= consider_bottom_) || | |
416 (consider_left_ == -1 && consider_top_ == -1 && | |
417 consider_right_ == -1 && consider_bottom_ == -1)); | |
418 return consider_left_ != -1; | |
419 } | |
420 | |
421 TilingData::DifferenceIterator::DifferenceIterator( | |
422 const TilingData* tiling_data, | |
423 const gfx::Rect& consider_rect, | |
424 const gfx::Rect& ignore_rect) | |
425 : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect) { | |
426 if (!HasConsiderRect()) { | |
427 done(); | |
428 return; | |
429 } | |
430 | |
431 index_x_ = consider_left_; | |
432 index_y_ = consider_top_; | |
433 | |
434 if (in_ignore_rect()) | |
435 ++(*this); | |
436 } | |
437 | |
438 TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() { | |
439 if (!*this) | |
440 return *this; | |
441 | |
442 index_x_++; | |
443 if (in_ignore_rect()) | |
444 index_x_ = ignore_right_ + 1; | |
445 | |
446 if (index_x_ > consider_right_) { | |
447 index_x_ = consider_left_; | |
448 index_y_++; | |
449 | |
450 if (in_ignore_rect()) { | |
451 index_x_ = ignore_right_ + 1; | |
452 // If the ignore rect spans the whole consider rect horizontally, then | |
453 // ignore_right + 1 will be out of bounds. | |
454 if (in_ignore_rect() || index_x_ > consider_right_) { | |
455 index_y_ = ignore_bottom_ + 1; | |
456 index_x_ = consider_left_; | |
457 } | |
458 } | |
459 | |
460 if (index_y_ > consider_bottom_) | |
461 done(); | |
462 } | |
463 | |
464 return *this; | |
465 } | |
466 | |
467 TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator() { | |
468 done(); | |
469 } | |
470 | |
471 TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator( | |
472 const TilingData* tiling_data, | |
473 const gfx::Rect& consider_rect, | |
474 const gfx::Rect& ignore_rect, | |
475 const gfx::Rect& center_rect) | |
476 : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect), | |
477 direction_(RIGHT), | |
478 delta_x_(1), | |
479 delta_y_(0), | |
480 current_step_(0), | |
481 horizontal_step_count_(0), | |
482 vertical_step_count_(0) { | |
483 if (!HasConsiderRect()) { | |
484 done(); | |
485 return; | |
486 } | |
487 | |
488 // Determine around left, such that it is between -1 and num_tiles_x. | |
489 int around_left = 0; | |
490 if (center_rect.x() < 0 || center_rect.IsEmpty()) | |
491 around_left = -1; | |
492 else if (center_rect.x() >= tiling_data->tiling_size().width()) | |
493 around_left = tiling_data->num_tiles_x(); | |
494 else | |
495 around_left = tiling_data->TileXIndexFromSrcCoord(center_rect.x()); | |
496 | |
497 // Determine around top, such that it is between -1 and num_tiles_y. | |
498 int around_top = 0; | |
499 if (center_rect.y() < 0 || center_rect.IsEmpty()) | |
500 around_top = -1; | |
501 else if (center_rect.y() >= tiling_data->tiling_size().height()) | |
502 around_top = tiling_data->num_tiles_y(); | |
503 else | |
504 around_top = tiling_data->TileYIndexFromSrcCoord(center_rect.y()); | |
505 | |
506 // Determine around right, such that it is between -1 and num_tiles_x. | |
507 int right_src_coord = center_rect.right() - 1; | |
508 int around_right = 0; | |
509 if (right_src_coord < 0 || center_rect.IsEmpty()) { | |
510 around_right = -1; | |
511 } else if (right_src_coord >= tiling_data->tiling_size().width()) { | |
512 around_right = tiling_data->num_tiles_x(); | |
513 } else { | |
514 around_right = tiling_data->TileXIndexFromSrcCoord(right_src_coord); | |
515 } | |
516 | |
517 // Determine around bottom, such that it is between -1 and num_tiles_y. | |
518 int bottom_src_coord = center_rect.bottom() - 1; | |
519 int around_bottom = 0; | |
520 if (bottom_src_coord < 0 || center_rect.IsEmpty()) { | |
521 around_bottom = -1; | |
522 } else if (bottom_src_coord >= tiling_data->tiling_size().height()) { | |
523 around_bottom = tiling_data->num_tiles_y(); | |
524 } else { | |
525 around_bottom = tiling_data->TileYIndexFromSrcCoord(bottom_src_coord); | |
526 } | |
527 | |
528 vertical_step_count_ = around_bottom - around_top + 1; | |
529 horizontal_step_count_ = around_right - around_left + 1; | |
530 current_step_ = horizontal_step_count_ - 1; | |
531 | |
532 index_x_ = around_right; | |
533 index_y_ = around_bottom; | |
534 | |
535 // The current index is the bottom right of the around rect, which is also | |
536 // ignored. So we have to advance. | |
537 ++(*this); | |
538 } | |
539 | |
540 TilingData::SpiralDifferenceIterator& TilingData::SpiralDifferenceIterator:: | |
541 operator++() { | |
542 int cannot_hit_consider_count = 0; | |
543 while (cannot_hit_consider_count < 4) { | |
544 if (needs_direction_switch()) | |
545 switch_direction(); | |
546 | |
547 index_x_ += delta_x_; | |
548 index_y_ += delta_y_; | |
549 ++current_step_; | |
550 | |
551 if (in_consider_rect()) { | |
552 cannot_hit_consider_count = 0; | |
553 | |
554 if (!in_ignore_rect()) | |
555 break; | |
556 | |
557 // Steps needed to reach the very edge of the ignore rect, while remaining | |
558 // inside (so that the continue would take us outside). | |
559 int steps_to_edge = 0; | |
560 switch (direction_) { | |
561 case UP: | |
562 steps_to_edge = index_y_ - ignore_top_; | |
563 break; | |
564 case LEFT: | |
565 steps_to_edge = index_x_ - ignore_left_; | |
566 break; | |
567 case DOWN: | |
568 steps_to_edge = ignore_bottom_ - index_y_; | |
569 break; | |
570 case RIGHT: | |
571 steps_to_edge = ignore_right_ - index_x_; | |
572 break; | |
573 } | |
574 | |
575 // We need to switch directions in |max_steps|. | |
576 int max_steps = current_step_count() - current_step_; | |
577 | |
578 int steps_to_take = std::min(steps_to_edge, max_steps); | |
579 DCHECK_GE(steps_to_take, 0); | |
580 | |
581 index_x_ += steps_to_take * delta_x_; | |
582 index_y_ += steps_to_take * delta_y_; | |
583 current_step_ += steps_to_take; | |
584 } else { | |
585 int max_steps = current_step_count() - current_step_; | |
586 int steps_to_take = max_steps; | |
587 bool can_hit_consider_rect = false; | |
588 switch (direction_) { | |
589 case UP: | |
590 if (valid_column() && consider_bottom_ < index_y_) | |
591 steps_to_take = index_y_ - consider_bottom_ - 1; | |
592 can_hit_consider_rect |= consider_right_ >= index_x_; | |
593 break; | |
594 case LEFT: | |
595 if (valid_row() && consider_right_ < index_x_) | |
596 steps_to_take = index_x_ - consider_right_ - 1; | |
597 can_hit_consider_rect |= consider_top_ <= index_y_; | |
598 break; | |
599 case DOWN: | |
600 if (valid_column() && consider_top_ > index_y_) | |
601 steps_to_take = consider_top_ - index_y_ - 1; | |
602 can_hit_consider_rect |= consider_left_ <= index_x_; | |
603 break; | |
604 case RIGHT: | |
605 if (valid_row() && consider_left_ > index_x_) | |
606 steps_to_take = consider_left_ - index_x_ - 1; | |
607 can_hit_consider_rect |= consider_bottom_ >= index_y_; | |
608 break; | |
609 } | |
610 steps_to_take = std::min(steps_to_take, max_steps); | |
611 DCHECK_GE(steps_to_take, 0); | |
612 | |
613 index_x_ += steps_to_take * delta_x_; | |
614 index_y_ += steps_to_take * delta_y_; | |
615 current_step_ += steps_to_take; | |
616 | |
617 if (can_hit_consider_rect) | |
618 cannot_hit_consider_count = 0; | |
619 else | |
620 ++cannot_hit_consider_count; | |
621 } | |
622 } | |
623 | |
624 if (cannot_hit_consider_count >= 4) | |
625 done(); | |
626 return *this; | |
627 } | |
628 | |
629 bool TilingData::SpiralDifferenceIterator::needs_direction_switch() const { | |
630 return current_step_ >= current_step_count(); | |
631 } | |
632 | |
633 void TilingData::SpiralDifferenceIterator::switch_direction() { | |
634 // Note that delta_x_ and delta_y_ always remain between -1 and 1. | |
635 int new_delta_x_ = delta_y_; | |
636 delta_y_ = -delta_x_; | |
637 delta_x_ = new_delta_x_; | |
638 | |
639 current_step_ = 0; | |
640 direction_ = static_cast<Direction>((direction_ + 1) % 4); | |
641 | |
642 if (direction_ == RIGHT || direction_ == LEFT) { | |
643 ++vertical_step_count_; | |
644 ++horizontal_step_count_; | |
645 } | |
646 } | |
647 | |
648 TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator() { | |
649 done(); | |
650 } | |
651 | |
652 TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator( | |
653 const TilingData* tiling_data, | |
654 const gfx::Rect& consider_rect, | |
655 const gfx::Rect& ignore_rect, | |
656 const gfx::Rect& center_rect) | |
657 : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect), | |
658 around_left_(-1), | |
659 around_top_(-1), | |
660 around_right_(-1), | |
661 around_bottom_(-1), | |
662 direction_(LEFT), | |
663 delta_x_(-1), | |
664 delta_y_(0), | |
665 current_step_(0), | |
666 horizontal_step_count_(0), | |
667 vertical_step_count_(0) { | |
668 if (!HasConsiderRect()) { | |
669 done(); | |
670 return; | |
671 } | |
672 | |
673 // Determine around left, such that it is between -1 and num_tiles_x. | |
674 if (center_rect.x() < 0 || center_rect.IsEmpty()) | |
675 around_left_ = -1; | |
676 else if (center_rect.x() >= tiling_data->tiling_size().width()) | |
677 around_left_ = tiling_data->num_tiles_x(); | |
678 else | |
679 around_left_ = tiling_data->TileXIndexFromSrcCoord(center_rect.x()); | |
680 | |
681 // Determine around top, such that it is between -1 and num_tiles_y. | |
682 if (center_rect.y() < 0 || center_rect.IsEmpty()) | |
683 around_top_ = -1; | |
684 else if (center_rect.y() >= tiling_data->tiling_size().height()) | |
685 around_top_ = tiling_data->num_tiles_y(); | |
686 else | |
687 around_top_ = tiling_data->TileYIndexFromSrcCoord(center_rect.y()); | |
688 | |
689 // Determine around right, such that it is between -1 and num_tiles_x. | |
690 int right_src_coord = center_rect.right() - 1; | |
691 if (right_src_coord < 0 || center_rect.IsEmpty()) { | |
692 around_right_ = -1; | |
693 } else if (right_src_coord >= tiling_data->tiling_size().width()) { | |
694 around_right_ = tiling_data->num_tiles_x(); | |
695 } else { | |
696 around_right_ = tiling_data->TileXIndexFromSrcCoord(right_src_coord); | |
697 } | |
698 | |
699 // Determine around bottom, such that it is between -1 and num_tiles_y. | |
700 int bottom_src_coord = center_rect.bottom() - 1; | |
701 if (bottom_src_coord < 0 || center_rect.IsEmpty()) { | |
702 around_bottom_ = -1; | |
703 } else if (bottom_src_coord >= tiling_data->tiling_size().height()) { | |
704 around_bottom_ = tiling_data->num_tiles_y(); | |
705 } else { | |
706 around_bottom_ = tiling_data->TileYIndexFromSrcCoord(bottom_src_coord); | |
707 } | |
708 | |
709 // Figure out the maximum distance from the around edge to consider edge. | |
710 int max_distance = 0; | |
711 max_distance = std::max(max_distance, around_top_ - consider_top_); | |
712 max_distance = std::max(max_distance, around_left_ - consider_left_); | |
713 max_distance = std::max(max_distance, consider_bottom_ - around_bottom_); | |
714 max_distance = std::max(max_distance, consider_right_ - around_right_); | |
715 | |
716 // The step count is the length of the edge (around_right_ - around_left_ + 1) | |
717 // plus twice the max distance to pad (to the right and to the left). This way | |
718 // the initial rect is the size proportional to the center, but big enough | |
719 // to cover the consider rect. | |
720 // | |
721 // C = consider rect | |
722 // A = around rect | |
723 // . = area of the padded around rect | |
724 // md = max distance (note in the picture below, there's md written vertically | |
725 // as well). | |
726 // I = initial starting position | |
727 // | |
728 // |md| |md| | |
729 // | |
730 // - .......... | |
731 // m .......... | |
732 // d .......... | |
733 // - CCCCCCC... | |
734 // CCCCAAC... | |
735 // CCCCAAC... | |
736 // - .......... | |
737 // m .......... | |
738 // d .......... | |
739 // - ..........I | |
740 vertical_step_count_ = around_bottom_ - around_top_ + 1 + 2 * max_distance; | |
741 horizontal_step_count_ = around_right_ - around_left_ + 1 + 2 * max_distance; | |
742 | |
743 // Start with one to the right of the padded around rect. | |
744 index_x_ = around_right_ + max_distance + 1; | |
745 index_y_ = around_bottom_ + max_distance; | |
746 | |
747 // The current index is outside a valid tile, so advance immediately. | |
748 ++(*this); | |
749 } | |
750 | |
751 TilingData::ReverseSpiralDifferenceIterator& | |
752 TilingData::ReverseSpiralDifferenceIterator:: | |
753 operator++() { | |
754 while (!in_around_rect()) { | |
755 if (needs_direction_switch()) | |
756 switch_direction(); | |
757 | |
758 index_x_ += delta_x_; | |
759 index_y_ += delta_y_; | |
760 ++current_step_; | |
761 | |
762 if (in_around_rect()) { | |
763 break; | |
764 } else if (in_consider_rect()) { | |
765 // If the tile is in the consider rect but not in ignore rect, then it's a | |
766 // valid tile to visit. | |
767 if (!in_ignore_rect()) | |
768 break; | |
769 | |
770 // Steps needed to reach the very edge of the ignore rect, while remaining | |
771 // inside it (so that the continue would take us outside). | |
772 int steps_to_edge = 0; | |
773 switch (direction_) { | |
774 case UP: | |
775 steps_to_edge = index_y_ - ignore_top_; | |
776 break; | |
777 case LEFT: | |
778 steps_to_edge = index_x_ - ignore_left_; | |
779 break; | |
780 case DOWN: | |
781 steps_to_edge = ignore_bottom_ - index_y_; | |
782 break; | |
783 case RIGHT: | |
784 steps_to_edge = ignore_right_ - index_x_; | |
785 break; | |
786 } | |
787 | |
788 // We need to switch directions in |max_steps|. | |
789 int max_steps = current_step_count() - current_step_; | |
790 | |
791 int steps_to_take = std::min(steps_to_edge, max_steps); | |
792 DCHECK_GE(steps_to_take, 0); | |
793 | |
794 index_x_ += steps_to_take * delta_x_; | |
795 index_y_ += steps_to_take * delta_y_; | |
796 current_step_ += steps_to_take; | |
797 } else { | |
798 // We're not in the consider rect. | |
799 | |
800 int max_steps = current_step_count() - current_step_; | |
801 int steps_to_take = max_steps; | |
802 | |
803 // We might hit the consider rect before needing to switch directions: | |
804 // update steps to take. | |
805 switch (direction_) { | |
806 case UP: | |
807 if (valid_column() && consider_bottom_ < index_y_) | |
808 steps_to_take = index_y_ - consider_bottom_ - 1; | |
809 break; | |
810 case LEFT: | |
811 if (valid_row() && consider_right_ < index_x_) | |
812 steps_to_take = index_x_ - consider_right_ - 1; | |
813 break; | |
814 case DOWN: | |
815 if (valid_column() && consider_top_ > index_y_) | |
816 steps_to_take = consider_top_ - index_y_ - 1; | |
817 break; | |
818 case RIGHT: | |
819 if (valid_row() && consider_left_ > index_x_) | |
820 steps_to_take = consider_left_ - index_x_ - 1; | |
821 break; | |
822 } | |
823 steps_to_take = std::min(steps_to_take, max_steps); | |
824 DCHECK_GE(steps_to_take, 0); | |
825 | |
826 index_x_ += steps_to_take * delta_x_; | |
827 index_y_ += steps_to_take * delta_y_; | |
828 current_step_ += steps_to_take; | |
829 } | |
830 } | |
831 | |
832 // Once we enter the around rect, we're done. | |
833 if (in_around_rect()) | |
834 done(); | |
835 return *this; | |
836 } | |
837 | |
838 bool TilingData::ReverseSpiralDifferenceIterator::needs_direction_switch() | |
839 const { | |
840 return current_step_ >= current_step_count(); | |
841 } | |
842 | |
843 void TilingData::ReverseSpiralDifferenceIterator::switch_direction() { | |
844 // Note that delta_x_ and delta_y_ always remain between -1 and 1. | |
845 int new_delta_y_ = delta_x_; | |
846 delta_x_ = -delta_y_; | |
847 delta_y_ = new_delta_y_; | |
848 | |
849 current_step_ = 0; | |
850 direction_ = static_cast<Direction>((direction_ + 1) % 4); | |
851 | |
852 if (direction_ == UP || direction_ == DOWN) { | |
853 --vertical_step_count_; | |
854 --horizontal_step_count_; | |
855 | |
856 // We should always end up in an around rect at some point. | |
857 // Since the direction is now vertical, we have to ensure that we will | |
858 // advance. | |
859 DCHECK_GE(horizontal_step_count_, 1); | |
860 DCHECK_GE(vertical_step_count_, 1); | |
861 } | |
862 } | |
863 | |
864 } // namespace cc | |
OLD | NEW |