Index: cc/picture_layer_tiling.cc |
diff --git a/cc/picture_layer_tiling.cc b/cc/picture_layer_tiling.cc |
index c6ecb7f62412dacb23ccfa05e4f7b870d2f7cba0..abd6347528f34c4a728ac7aa91348f6a1411f5de 100644 |
--- a/cc/picture_layer_tiling.cc |
+++ b/cc/picture_layer_tiling.cc |
@@ -3,20 +3,25 @@ |
// found in the LICENSE file. |
#include "cc/picture_layer_tiling.h" |
+#include "ui/gfx/rect_conversions.h" |
+#include "ui/gfx/size_conversions.h" |
namespace cc { |
scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( |
+ float contents_scale, |
gfx::Size tile_size) { |
- return make_scoped_ptr(new PictureLayerTiling(tile_size)); |
+ return make_scoped_ptr(new PictureLayerTiling(contents_scale, tile_size)); |
} |
scoped_ptr<PictureLayerTiling> PictureLayerTiling::Clone() const { |
return make_scoped_ptr(new PictureLayerTiling(*this)); |
} |
-PictureLayerTiling::PictureLayerTiling(gfx::Size tile_size) |
+PictureLayerTiling::PictureLayerTiling(float contents_scale, |
+ gfx::Size tile_size) |
: client_(NULL), |
+ contents_scale_(contents_scale), |
tiling_data_(tile_size, gfx::Size(), true) { |
} |
@@ -30,26 +35,31 @@ const PictureLayerTiling& PictureLayerTiling::operator=( |
return *this; |
} |
-void PictureLayerTiling::create_tiles(gfx::Rect rect) { |
- for (Iterator iter(this, rect); iter; ++iter) { |
- if (*iter) |
- continue; |
- tiles_[std::make_pair(iter.tile_i_, iter.tile_j_)] = |
- client_->CreateTile(this, iter.full_tile_rect()); |
- } |
+void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) { |
+ client_ = client; |
} |
-void PictureLayerTiling::set_client(PictureLayerTilingClient* client) { |
- client_ = client; |
+gfx::Rect PictureLayerTiling::ContentRect() const { |
+ gfx::Size content_bounds = |
+ gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); |
+ return gfx::Rect(gfx::Point(), content_bounds); |
} |
Tile* PictureLayerTiling::TileAt(int i, int j) const { |
- TileMap::const_iterator iter = tiles_.find(std::make_pair(i, j)); |
+ TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j)); |
if (iter == tiles_.end()) |
return NULL; |
return iter->second.get(); |
} |
+void PictureLayerTiling::CreateTile(int i, int j) { |
+ gfx::Rect tile_rect = tiling_data_.TileBoundsWithBorder(i, j); |
+ tile_rect.set_size(tiling_data_.max_texture_size()); |
+ TileMapKey key(i, j); |
+ DCHECK(!tiles_[key]); |
+ tiles_[key] = client_->CreateTile(this, tile_rect); |
+} |
+ |
Region PictureLayerTiling::OpaqueRegionInContentRect( |
const gfx::Rect& content_rect) const { |
Region opaque_region; |
@@ -57,16 +67,32 @@ Region PictureLayerTiling::OpaqueRegionInContentRect( |
return opaque_region; |
} |
-void PictureLayerTiling::SetBounds(gfx::Size size) { |
- tiling_data_.SetTotalSize(size); |
- if (size.IsEmpty()) { |
+void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) { |
+ if (layer_bounds_ == layer_bounds) |
+ return; |
+ |
+ layer_bounds_ = layer_bounds; |
+ gfx::Size content_bounds = |
+ gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); |
+ |
+ tiling_data_.SetTotalSize(content_bounds); |
+ if (layer_bounds_.IsEmpty()) { |
tiles_.clear(); |
return; |
} |
+ int right = tiling_data_.TileXIndexFromSrcCoord(content_bounds.width() - 1); |
+ int bottom = tiling_data_.TileYIndexFromSrcCoord(content_bounds.height() - 1); |
+ |
+ // TODO(enne): Be more efficient about what tiles are created. |
+ for (int j = 0; j <= bottom; ++j) { |
+ for (int i = 0; i <= right; ++i) { |
+ if (tiles_.find(TileMapKey(i, j)) == tiles_.end()) |
+ CreateTile(i, j); |
+ } |
+ } |
+ |
// Any tiles outside our new bounds are invalid and should be dropped. |
- int right = tiling_data_.TileXIndexFromSrcCoord(size.width() - 1); |
- int bottom = tiling_data_.TileYIndexFromSrcCoord(size.height() - 1); |
std::vector<TileMapKey> invalid_tile_keys; |
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
if (it->first.first > right || it->first.second > bottom) |
@@ -76,10 +102,51 @@ void PictureLayerTiling::SetBounds(gfx::Size size) { |
tiles_.erase(invalid_tile_keys[i]); |
} |
+void PictureLayerTiling::Invalidate(const Region& layer_invalidation) { |
+ std::vector<TileMapKey> new_tiles; |
+ |
+ for (Region::Iterator region_iter(layer_invalidation); |
+ region_iter.has_rect(); |
+ region_iter.next()) { |
+ |
+ gfx::Rect rect = |
+ gfx::ToEnclosingRect(ScaleRect(region_iter.rect(), contents_scale_)); |
+ rect.Intersect(ContentRect()); |
+ |
+ for (PictureLayerTiling::Iterator tile_iter(this, contents_scale_, rect); |
+ tile_iter; |
+ ++tile_iter) { |
+ TileMapKey key(tile_iter.tile_i_, tile_iter.tile_j_); |
+ if (!tiles_[key]) |
+ continue; |
+ |
+ tiles_[key] = NULL; |
+ new_tiles.push_back(key); |
+ } |
+ } |
+ |
+ for (size_t i = 0; i < new_tiles.size(); ++i) { |
+ CreateTile(new_tiles[i].first, new_tiles[i].second); |
+ } |
+} |
+ |
+PictureLayerTiling::Iterator::Iterator() |
+ : tiling_(NULL), |
+ current_tile_(NULL), |
+ tile_i_(0), |
+ tile_j_(0), |
+ left_(0), |
+ top_(0), |
+ right_(0), |
+ bottom_(0) { |
+} |
+ |
PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling, |
- gfx::Rect content_rect) |
+ float dest_scale, |
+ gfx::Rect dest_rect) |
: tiling_(tiling), |
- content_rect_(content_rect), |
+ dest_rect_(dest_rect), |
+ dest_to_content_scale_(tiling_->contents_scale_ / dest_scale), |
current_tile_(NULL), |
tile_i_(0), |
tile_j_(0), |
@@ -88,9 +155,12 @@ PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling, |
right_(0), |
bottom_(0) { |
DCHECK(tiling_); |
- if (content_rect_.IsEmpty()) |
+ if (dest_rect_.IsEmpty()) |
return; |
+ gfx::Rect content_rect = |
+ gfx::ToEnclosingRect(gfx::ScaleRect(dest_rect_, dest_to_content_scale_)); |
+ |
left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); |
top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); |
right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( |
@@ -98,73 +168,96 @@ PictureLayerTiling::Iterator::Iterator(PictureLayerTiling* tiling, |
bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( |
content_rect.bottom() - 1); |
- tile_i_ = left_; |
+ tile_i_ = left_ - 1; |
tile_j_ = top_; |
- current_tile_ = tiling_->TileAt(tile_i_, tile_j_); |
+ ++(*this); |
} |
PictureLayerTiling::Iterator::~Iterator() { |
} |
PictureLayerTiling::Iterator& PictureLayerTiling::Iterator::operator++() { |
- if (!current_tile_) |
+ if (tile_j_ > bottom_) |
return *this; |
- do { |
- tile_i_++; |
- if (tile_i_ > right_) { |
- tile_i_ = left_; |
- tile_j_++; |
- if (tile_j_ > top_) |
- current_tile_ = NULL; |
- return *this; |
+ bool first_time = tile_i_ < left_; |
+ bool new_row = false; |
+ tile_i_++; |
+ if (tile_i_ > right_) { |
+ tile_i_ = left_; |
+ tile_j_++; |
+ new_row = true; |
+ if (tile_j_ > bottom_) { |
+ current_tile_ = NULL; |
+ return *this; |
} |
- } while (!geometry_rect().IsEmpty()); |
+ } |
current_tile_ = tiling_->TileAt(tile_i_, tile_j_); |
+ |
+ // Calculate the current geometry rect. Due to floating point rounding |
+ // and ToEnclosedRect, tiles might overlap in destination space on the |
+ // edges. |
+ gfx::Rect last_geometry_rect = current_geometry_rect_; |
+ |
+ gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); |
+ current_geometry_rect_ = gfx::ToEnclosingRect( |
+ gfx::ScaleRect(content_rect, 1 / dest_to_content_scale_)); |
+ current_geometry_rect_.Intersect(dest_rect_); |
+ |
+ if (first_time) |
+ return *this; |
+ |
+ // Iteration happens left->right, top->bottom. Running off the bottom-right |
+ // edge is handled by the intersection above with dest_rect_. Here we make |
+ // sure that the new current geometry rect doesn't overlap with the last. |
+ int min_left; |
+ int min_top; |
+ if (new_row) { |
+ min_left = dest_rect_.x(); |
+ min_top = last_geometry_rect.bottom(); |
+ } else { |
+ min_left = last_geometry_rect.right(); |
+ min_top = last_geometry_rect.y(); |
+ } |
+ |
+ int inset_left = std::max(0, min_left - current_geometry_rect_.x()); |
+ int inset_top = std::max(0, min_top - current_geometry_rect_.y()); |
+ current_geometry_rect_.Inset(inset_left, inset_top, 0, 0); |
+ |
+ if (!new_row) { |
+ DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x()); |
+ DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom()); |
+ DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y()); |
+ } |
+ |
return *this; |
} |
gfx::Rect PictureLayerTiling::Iterator::geometry_rect() const { |
- gfx::Rect geometry_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); |
- geometry_rect.Intersect(content_rect_); |
- return geometry_rect; |
+ return current_geometry_rect_; |
} |
-gfx::Rect PictureLayerTiling::Iterator::full_tile_rect() const { |
- gfx::Rect tile_rect = |
- tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_); |
- tile_rect.set_size(texture_size()); |
- return tile_rect; |
-} |
+gfx::RectF PictureLayerTiling::Iterator::texture_rect() const { |
+ gfx::Rect full_bounds = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, |
+ tile_j_); |
+ full_bounds.set_size(texture_size()); |
-gfx::Rect PictureLayerTiling::Iterator::texture_rect() const { |
- gfx::Rect full_bounds = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); |
- gfx::Rect visible = geometry_rect(); |
- gfx::Vector2d display_offset = visible.origin() - full_bounds.origin(); |
- gfx::Vector2d offset = visible.origin() - full_bounds.origin(); |
- offset += tiling_->tiling_data_.TextureOffset(tile_i_, tile_j_); |
+ // Convert from dest space => content space => texture space. |
+ gfx::RectF texture_rect = gfx::ScaleRect(current_geometry_rect_, |
+ dest_to_content_scale_); |
+ texture_rect.Offset(-full_bounds.OffsetFromOrigin()); |
- return gfx::Rect(gfx::PointAtOffsetFromOrigin(offset), visible.size()); |
-} |
+ DCHECK_GE(texture_rect.x(), 0); |
+ DCHECK_GE(texture_rect.y(), 0); |
+ DCHECK_LE(texture_rect.right(), texture_size().width()); |
+ DCHECK_LE(texture_rect.bottom(), texture_size().height()); |
-gfx::Rect PictureLayerTiling::Iterator::opaque_rect() const { |
- gfx::Rect opaque_rect; |
- opaque_rect = current_tile_->opaque_rect(); |
- opaque_rect.Intersect(content_rect_); |
- return opaque_rect; |
+ return texture_rect; |
} |
gfx::Size PictureLayerTiling::Iterator::texture_size() const { |
return tiling_->tiling_data_.max_texture_size(); |
} |
-bool PictureLayerTiling::Iterator::operator==(const Iterator& other) const { |
- return tiling_ == other.tiling_ && current_tile_ == other.current_tile_; |
-} |
- |
-bool PictureLayerTiling::Iterator::operator!=(const Iterator& other) const { |
- return !(*this == other); |
-} |
- |
} // namespace cc |