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.
5 #include "cc/base/tiling_data.h"
9 #include "ui/gfx/rect.h"
10 #include "ui/gfx/vector2d.h"
14 static int ComputeNumTiles(int max_texture_size
,
17 if (max_texture_size
- 2 * border_texels
<= 0)
18 return total_size
> 0 && max_texture_size
>= total_size
? 1 : 0;
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;
26 TilingData::TilingData()
31 TilingData::TilingData(
32 gfx::Size max_texture_size
,
34 bool has_border_texels
)
35 : max_texture_size_(max_texture_size
),
36 total_size_(total_size
),
37 border_texels_(has_border_texels
? 1 : 0) {
41 TilingData::TilingData(
42 gfx::Size max_texture_size
,
45 : max_texture_size_(max_texture_size
),
46 total_size_(total_size
),
47 border_texels_(border_texels
) {
51 void TilingData::SetTotalSize(gfx::Size total_size
) {
52 total_size_
= total_size
;
56 void TilingData::SetMaxTextureSize(gfx::Size max_texture_size
) {
57 max_texture_size_
= max_texture_size
;
61 void TilingData::SetHasBorderTexels(bool has_border_texels
) {
62 border_texels_
= has_border_texels
? 1 : 0;
66 void TilingData::SetBorderTexels(int border_texels
) {
67 border_texels_
= border_texels
;
71 int TilingData::TileXIndexFromSrcCoord(int src_position
) const {
72 if (num_tiles_x_
<= 1)
75 DCHECK_GT(max_texture_size_
.width() - 2 * border_texels_
, 0);
76 int x
= (src_position
- border_texels_
) /
77 (max_texture_size_
.width() - 2 * border_texels_
);
78 return std::min(std::max(x
, 0), num_tiles_x_
- 1);
81 int TilingData::TileYIndexFromSrcCoord(int src_position
) const {
82 if (num_tiles_y_
<= 1)
85 DCHECK_GT(max_texture_size_
.height() - 2 * border_texels_
, 0);
86 int y
= (src_position
- border_texels_
) /
87 (max_texture_size_
.height() - 2 * border_texels_
);
88 return std::min(std::max(y
, 0), num_tiles_y_
- 1);
91 int TilingData::FirstBorderTileXIndexFromSrcCoord(int src_position
) const {
92 if (num_tiles_x_
<= 1)
95 DCHECK_GT(max_texture_size_
.width() - 2 * border_texels_
, 0);
96 int inner_tile_size
= max_texture_size_
.width() - 2 * border_texels_
;
97 int x
= (src_position
- 2 * border_texels_
) / inner_tile_size
;
98 return std::min(std::max(x
, 0), num_tiles_x_
- 1);
101 int TilingData::FirstBorderTileYIndexFromSrcCoord(int src_position
) const {
102 if (num_tiles_y_
<= 1)
105 DCHECK_GT(max_texture_size_
.height() - 2 * border_texels_
, 0);
106 int inner_tile_size
= max_texture_size_
.height() - 2 * border_texels_
;
107 int y
= (src_position
- 2 * border_texels_
) / inner_tile_size
;
108 return std::min(std::max(y
, 0), num_tiles_y_
- 1);
111 int TilingData::LastBorderTileXIndexFromSrcCoord(int src_position
) const {
112 if (num_tiles_x_
<= 1)
115 DCHECK_GT(max_texture_size_
.width() - 2 * border_texels_
, 0);
116 int inner_tile_size
= max_texture_size_
.width() - 2 * border_texels_
;
117 int x
= src_position
/ inner_tile_size
;
118 return std::min(std::max(x
, 0), num_tiles_x_
- 1);
121 int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position
) const {
122 if (num_tiles_y_
<= 1)
125 DCHECK_GT(max_texture_size_
.height() - 2 * border_texels_
, 0);
126 int inner_tile_size
= max_texture_size_
.height() - 2 * border_texels_
;
127 int y
= src_position
/ inner_tile_size
;
128 return std::min(std::max(y
, 0), num_tiles_y_
- 1);
131 gfx::Rect
TilingData::TileBounds(int i
, int j
) const {
133 int max_texture_size_x
= max_texture_size_
.width() - 2 * border_texels_
;
134 int max_texture_size_y
= max_texture_size_
.height() - 2 * border_texels_
;
135 int total_size_x
= total_size_
.width();
136 int total_size_y
= total_size_
.height();
138 int lo_x
= max_texture_size_x
* i
;
140 lo_x
+= border_texels_
;
142 int lo_y
= max_texture_size_y
* j
;
144 lo_y
+= border_texels_
;
146 int hi_x
= max_texture_size_x
* (i
+ 1) + border_texels_
;
147 if (i
+ 1 == num_tiles_x_
)
148 hi_x
+= border_texels_
;
150 int hi_y
= max_texture_size_y
* (j
+ 1) + border_texels_
;
151 if (j
+ 1 == num_tiles_y_
)
152 hi_y
+= border_texels_
;
154 hi_x
= std::min(hi_x
, total_size_x
);
155 hi_y
= std::min(hi_y
, total_size_y
);
159 int width
= hi_x
- lo_x
;
160 int height
= hi_y
- lo_y
;
164 DCHECK_GE(height
, 0);
165 DCHECK_LE(x
, total_size_
.width());
166 DCHECK_LE(y
, total_size_
.height());
167 return gfx::Rect(x
, y
, width
, height
);
170 gfx::Rect
TilingData::TileBoundsWithBorder(int i
, int j
) const {
172 int max_texture_size_x
= max_texture_size_
.width() - 2 * border_texels_
;
173 int max_texture_size_y
= max_texture_size_
.height() - 2 * border_texels_
;
174 int total_size_x
= total_size_
.width();
175 int total_size_y
= total_size_
.height();
177 int lo_x
= max_texture_size_x
* i
;
178 int lo_y
= max_texture_size_y
* j
;
180 int hi_x
= lo_x
+ max_texture_size_x
+ 2 * border_texels_
;
181 int hi_y
= lo_y
+ max_texture_size_y
+ 2 * border_texels_
;
183 hi_x
= std::min(hi_x
, total_size_x
);
184 hi_y
= std::min(hi_y
, total_size_y
);
188 int width
= hi_x
- lo_x
;
189 int height
= hi_y
- lo_y
;
193 DCHECK_GE(height
, 0);
194 DCHECK_LE(x
, total_size_
.width());
195 DCHECK_LE(y
, total_size_
.height());
196 return gfx::Rect(x
, y
, width
, height
);
199 int TilingData::TilePositionX(int x_index
) const {
200 DCHECK_GE(x_index
, 0);
201 DCHECK_LT(x_index
, num_tiles_x_
);
203 int pos
= (max_texture_size_
.width() - 2 * border_texels_
) * x_index
;
205 pos
+= border_texels_
;
210 int TilingData::TilePositionY(int y_index
) const {
211 DCHECK_GE(y_index
, 0);
212 DCHECK_LT(y_index
, num_tiles_y_
);
214 int pos
= (max_texture_size_
.height() - 2 * border_texels_
) * y_index
;
216 pos
+= border_texels_
;
221 int TilingData::TileSizeX(int x_index
) const {
222 DCHECK_GE(x_index
, 0);
223 DCHECK_LT(x_index
, num_tiles_x_
);
225 if (!x_index
&& num_tiles_x_
== 1)
226 return total_size_
.width();
227 if (!x_index
&& num_tiles_x_
> 1)
228 return max_texture_size_
.width() - border_texels_
;
229 if (x_index
< num_tiles_x_
- 1)
230 return max_texture_size_
.width() - 2 * border_texels_
;
231 if (x_index
== num_tiles_x_
- 1)
232 return total_size_
.width() - TilePositionX(x_index
);
238 int TilingData::TileSizeY(int y_index
) const {
239 DCHECK_GE(y_index
, 0);
240 DCHECK_LT(y_index
, num_tiles_y_
);
242 if (!y_index
&& num_tiles_y_
== 1)
243 return total_size_
.height();
244 if (!y_index
&& num_tiles_y_
> 1)
245 return max_texture_size_
.height() - border_texels_
;
246 if (y_index
< num_tiles_y_
- 1)
247 return max_texture_size_
.height() - 2 * border_texels_
;
248 if (y_index
== num_tiles_y_
- 1)
249 return total_size_
.height() - TilePositionY(y_index
);
255 gfx::Vector2d
TilingData::TextureOffset(int x_index
, int y_index
) const {
256 int left
= (!x_index
|| num_tiles_x_
== 1) ? 0 : border_texels_
;
257 int top
= (!y_index
|| num_tiles_y_
== 1) ? 0 : border_texels_
;
259 return gfx::Vector2d(left
, top
);
262 void TilingData::RecomputeNumTiles() {
263 num_tiles_x_
= ComputeNumTiles(
264 max_texture_size_
.width(), total_size_
.width(), border_texels_
);
265 num_tiles_y_
= ComputeNumTiles(
266 max_texture_size_
.height(), total_size_
.height(), border_texels_
);
269 TilingData::BaseIterator::BaseIterator(const TilingData
* tiling_data
)
270 : tiling_data_(tiling_data
),
275 TilingData::Iterator::Iterator(const TilingData
* tiling_data
, gfx::Rect rect
)
276 : BaseIterator(tiling_data
),
280 if (tiling_data_
->num_tiles_x() <= 0 || tiling_data_
->num_tiles_y() <= 0) {
285 rect
.Intersect(gfx::Rect(tiling_data_
->total_size()));
286 index_x_
= tiling_data_
->FirstBorderTileXIndexFromSrcCoord(rect
.x());
287 index_y_
= tiling_data_
->FirstBorderTileYIndexFromSrcCoord(rect
.y());
289 right_
= tiling_data_
->LastBorderTileXIndexFromSrcCoord(rect
.right() - 1);
290 bottom_
= tiling_data_
->LastBorderTileYIndexFromSrcCoord(rect
.bottom() - 1);
292 // Index functions always return valid indices, so explicitly check
293 // for non-intersecting rects.
294 gfx::Rect new_rect
= tiling_data_
->TileBoundsWithBorder(index_x_
, index_y_
);
295 if (!new_rect
.Intersects(rect
))
299 TilingData::Iterator
& TilingData::Iterator::operator++() {
304 if (index_x_
> right_
) {
307 if (index_y_
> bottom_
)
314 TilingData::DifferenceIterator::DifferenceIterator(
315 const TilingData
* tiling_data
,
318 : BaseIterator(tiling_data
),
322 consider_bottom_(-1),
327 if (tiling_data_
->num_tiles_x() <= 0 || tiling_data_
->num_tiles_y() <= 0) {
332 gfx::Rect
bounds(tiling_data_
->total_size());
333 consider
.Intersect(bounds
);
334 ignore
.Intersect(bounds
);
335 if (consider
.IsEmpty()) {
341 tiling_data_
->FirstBorderTileXIndexFromSrcCoord(consider
.x());
343 tiling_data_
->FirstBorderTileYIndexFromSrcCoord(consider
.y());
345 tiling_data_
->LastBorderTileXIndexFromSrcCoord(consider
.right() - 1);
347 tiling_data_
->LastBorderTileYIndexFromSrcCoord(consider
.bottom() - 1);
349 if (!ignore
.IsEmpty()) {
351 tiling_data_
->FirstBorderTileXIndexFromSrcCoord(ignore
.x());
353 tiling_data_
->FirstBorderTileYIndexFromSrcCoord(ignore
.y());
355 tiling_data_
->LastBorderTileXIndexFromSrcCoord(ignore
.right() - 1);
357 tiling_data_
->LastBorderTileYIndexFromSrcCoord(ignore
.bottom() - 1);
359 // Clamp ignore indices to consider indices.
360 ignore_left_
= std::max(ignore_left_
, consider_left_
);
361 ignore_top_
= std::max(ignore_top_
, consider_top_
);
362 ignore_right_
= std::min(ignore_right_
, consider_right_
);
363 ignore_bottom_
= std::min(ignore_bottom_
, consider_bottom_
);
366 if (ignore_left_
== consider_left_
&& ignore_right_
== consider_right_
&&
367 ignore_top_
== consider_top_
&& ignore_bottom_
== consider_bottom_
) {
372 index_x_
= consider_left_
;
373 index_y_
= consider_top_
;
375 if (in_ignore_rect())
379 TilingData::DifferenceIterator
& TilingData::DifferenceIterator::operator++() {
384 if (in_ignore_rect())
385 index_x_
= ignore_right_
+ 1;
387 if (index_x_
> consider_right_
) {
388 index_x_
= consider_left_
;
391 if (in_ignore_rect()) {
392 index_x_
= ignore_right_
+ 1;
393 // If the ignore rect spans the whole consider rect horizontally, then
394 // ignore_right + 1 will be out of bounds.
395 if (in_ignore_rect() || index_x_
> consider_right_
) {
396 index_y_
= ignore_bottom_
+ 1;
397 index_x_
= consider_left_
;
401 if (index_y_
> consider_bottom_
)