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_
;
149 if (hi_x
> total_size_x
)
152 int hi_y
= max_texture_size_y
* (j
+ 1) + border_texels_
;
153 if (j
+ 1 == num_tiles_y_
)
154 hi_y
+= border_texels_
;
155 if (hi_y
> total_size_y
)
160 int width
= hi_x
- lo_x
;
161 int height
= hi_y
- lo_y
;
165 DCHECK_GE(height
, 0);
166 DCHECK_LE(x
, total_size_
.width());
167 DCHECK_LE(y
, total_size_
.height());
168 return gfx::Rect(x
, y
, width
, height
);
171 gfx::Rect
TilingData::TileBoundsWithBorder(int i
, int j
) const {
172 gfx::Rect bounds
= TileBounds(i
, j
);
174 if (border_texels_
) {
176 int x2
= bounds
.right();
178 int y2
= bounds
.bottom();
182 if (i
< (num_tiles_x_
- 1))
186 if (j
< (num_tiles_y_
- 1))
189 bounds
= gfx::Rect(x1
, y1
, x2
- x1
, y2
- y1
);
195 int TilingData::TilePositionX(int x_index
) const {
196 DCHECK_GE(x_index
, 0);
197 DCHECK_LT(x_index
, num_tiles_x_
);
199 int pos
= (max_texture_size_
.width() - 2 * border_texels_
) * x_index
;
201 pos
+= border_texels_
;
206 int TilingData::TilePositionY(int y_index
) const {
207 DCHECK_GE(y_index
, 0);
208 DCHECK_LT(y_index
, num_tiles_y_
);
210 int pos
= (max_texture_size_
.height() - 2 * border_texels_
) * y_index
;
212 pos
+= border_texels_
;
217 int TilingData::TileSizeX(int x_index
) const {
218 DCHECK_GE(x_index
, 0);
219 DCHECK_LT(x_index
, num_tiles_x_
);
221 if (!x_index
&& num_tiles_x_
== 1)
222 return total_size_
.width();
223 if (!x_index
&& num_tiles_x_
> 1)
224 return max_texture_size_
.width() - border_texels_
;
225 if (x_index
< num_tiles_x_
- 1)
226 return max_texture_size_
.width() - 2 * border_texels_
;
227 if (x_index
== num_tiles_x_
- 1)
228 return total_size_
.width() - TilePositionX(x_index
);
234 int TilingData::TileSizeY(int y_index
) const {
235 DCHECK_GE(y_index
, 0);
236 DCHECK_LT(y_index
, num_tiles_y_
);
238 if (!y_index
&& num_tiles_y_
== 1)
239 return total_size_
.height();
240 if (!y_index
&& num_tiles_y_
> 1)
241 return max_texture_size_
.height() - border_texels_
;
242 if (y_index
< num_tiles_y_
- 1)
243 return max_texture_size_
.height() - 2 * border_texels_
;
244 if (y_index
== num_tiles_y_
- 1)
245 return total_size_
.height() - TilePositionY(y_index
);
251 gfx::Vector2d
TilingData::TextureOffset(int x_index
, int y_index
) const {
252 int left
= (!x_index
|| num_tiles_x_
== 1) ? 0 : border_texels_
;
253 int top
= (!y_index
|| num_tiles_y_
== 1) ? 0 : border_texels_
;
255 return gfx::Vector2d(left
, top
);
258 void TilingData::RecomputeNumTiles() {
259 num_tiles_x_
= ComputeNumTiles(
260 max_texture_size_
.width(), total_size_
.width(), border_texels_
);
261 num_tiles_y_
= ComputeNumTiles(
262 max_texture_size_
.height(), total_size_
.height(), border_texels_
);
265 TilingData::BaseIterator::BaseIterator(const TilingData
* tiling_data
)
266 : tiling_data_(tiling_data
),
271 TilingData::Iterator::Iterator(const TilingData
* tiling_data
, gfx::Rect rect
)
272 : BaseIterator(tiling_data
),
276 if (tiling_data_
->num_tiles_x() <= 0 || tiling_data_
->num_tiles_y() <= 0) {
281 rect
.Intersect(gfx::Rect(tiling_data_
->total_size()));
282 index_x_
= tiling_data_
->FirstBorderTileXIndexFromSrcCoord(rect
.x());
283 index_y_
= tiling_data_
->FirstBorderTileYIndexFromSrcCoord(rect
.y());
285 right_
= tiling_data_
->LastBorderTileXIndexFromSrcCoord(rect
.right() - 1);
286 bottom_
= tiling_data_
->LastBorderTileYIndexFromSrcCoord(rect
.bottom() - 1);
288 // Index functions always return valid indices, so explicitly check
289 // for non-intersecting rects.
290 gfx::Rect new_rect
= tiling_data_
->TileBoundsWithBorder(index_x_
, index_y_
);
291 if (!new_rect
.Intersects(rect
))
295 TilingData::Iterator
& TilingData::Iterator::operator++() {
300 if (index_x_
> right_
) {
303 if (index_y_
> bottom_
)
310 TilingData::DifferenceIterator::DifferenceIterator(
311 const TilingData
* tiling_data
,
314 : BaseIterator(tiling_data
),
318 consider_bottom_(-1),
323 if (tiling_data_
->num_tiles_x() <= 0 || tiling_data_
->num_tiles_y() <= 0) {
328 gfx::Rect
bounds(tiling_data_
->total_size());
329 consider
.Intersect(bounds
);
330 ignore
.Intersect(bounds
);
331 if (consider
.IsEmpty()) {
337 tiling_data_
->FirstBorderTileXIndexFromSrcCoord(consider
.x());
339 tiling_data_
->FirstBorderTileYIndexFromSrcCoord(consider
.y());
341 tiling_data_
->LastBorderTileXIndexFromSrcCoord(consider
.right() - 1);
343 tiling_data_
->LastBorderTileYIndexFromSrcCoord(consider
.bottom() - 1);
345 if (!ignore
.IsEmpty()) {
347 tiling_data_
->FirstBorderTileXIndexFromSrcCoord(ignore
.x());
349 tiling_data_
->FirstBorderTileYIndexFromSrcCoord(ignore
.y());
351 tiling_data_
->LastBorderTileXIndexFromSrcCoord(ignore
.right() - 1);
353 tiling_data_
->LastBorderTileYIndexFromSrcCoord(ignore
.bottom() - 1);
355 // Clamp ignore indices to consider indices.
356 ignore_left_
= std::max(ignore_left_
, consider_left_
);
357 ignore_top_
= std::max(ignore_top_
, consider_top_
);
358 ignore_right_
= std::min(ignore_right_
, consider_right_
);
359 ignore_bottom_
= std::min(ignore_bottom_
, consider_bottom_
);
362 if (ignore_left_
== consider_left_
&& ignore_right_
== consider_right_
&&
363 ignore_top_
== consider_top_
&& ignore_bottom_
== consider_bottom_
) {
368 index_x_
= consider_left_
;
369 index_y_
= consider_top_
;
371 if (in_ignore_rect())
375 TilingData::DifferenceIterator
& TilingData::DifferenceIterator::operator++() {
380 if (in_ignore_rect())
381 index_x_
= ignore_right_
+ 1;
383 if (index_x_
> consider_right_
) {
384 index_x_
= consider_left_
;
387 if (in_ignore_rect()) {
388 index_x_
= ignore_right_
+ 1;
389 // If the ignore rect spans the whole consider rect horizontally, then
390 // ignore_right + 1 will be out of bounds.
391 if (in_ignore_rect() || index_x_
> consider_right_
) {
392 index_y_
= ignore_bottom_
+ 1;
393 index_x_
= consider_left_
;
397 if (index_y_
> consider_bottom_
)