Chromium Code Reviews| Index: cc/resources/active_picture_layer_tiling.cc |
| diff --git a/cc/resources/active_picture_layer_tiling.cc b/cc/resources/active_picture_layer_tiling.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3b8682a27289f04154af4c3dae06e9340978f5aa |
| --- /dev/null |
| +++ b/cc/resources/active_picture_layer_tiling.cc |
| @@ -0,0 +1,280 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "cc/resources/active_picture_layer_tiling.h" |
| + |
| +#include "ui/gfx/geometry/point_conversions.h" |
| +#include "ui/gfx/geometry/rect_conversions.h" |
| +#include "ui/gfx/geometry/safe_integer_conversions.h" |
| +#include "ui/gfx/geometry/size_conversions.h" |
| + |
| +namespace cc { |
| + |
| +scoped_ptr<PictureLayerTiling> ActivePictureLayerTiling::Create( |
| + float contents_scale, |
| + scoped_refptr<RasterSource> raster_source, |
| + PictureLayerTilingClient* client, |
| + size_t max_tiles_for_interest_area, |
| + float skewport_target_time_in_seconds, |
| + int skewport_extrapolation_limit_in_content_pixels) { |
| + return make_scoped_ptr(new ActivePictureLayerTiling( |
| + contents_scale, raster_source, client, max_tiles_for_interest_area, |
| + skewport_target_time_in_seconds, |
| + skewport_extrapolation_limit_in_content_pixels)); |
| +} |
| + |
| +ActivePictureLayerTiling::ActivePictureLayerTiling( |
| + float contents_scale, |
| + scoped_refptr<RasterSource> raster_source, |
| + PictureLayerTilingClient* client, |
| + size_t max_tiles_for_interest_area, |
| + float skewport_target_time_in_seconds, |
| + int skewport_extrapolation_limit_in_content_pixels) |
| + : PictureLayerTiling(contents_scale, |
| + raster_source, |
| + client, |
| + max_tiles_for_interest_area, |
| + skewport_target_time_in_seconds, |
| + skewport_extrapolation_limit_in_content_pixels) { |
| +} |
| + |
| +ActivePictureLayerTiling::~ActivePictureLayerTiling() { |
| +} |
| + |
| +void ActivePictureLayerTiling::SetRasterSourceAndResize( |
| + const scoped_refptr<RasterSource> raster_source) { |
| + DCHECK(!raster_source->IsSolidColor()); |
| + gfx::Size old_layer_bounds = raster_source_->GetSize(); |
| + raster_source_ = raster_source; |
| + gfx::Size new_layer_bounds = raster_source_->GetSize(); |
| + gfx::Size content_bounds = |
| + gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_)); |
| + gfx::Size tile_size = client_->CalculateTileSize(content_bounds); |
| + |
| + if (tile_size != tiling_data_.max_texture_size()) { |
| + tiling_data_.SetTilingSize(content_bounds); |
| + tiling_data_.SetMaxTextureSize(tile_size); |
| + // When the tile size changes, the TilingData positions no longer work |
| + // as valid keys to the TileMap, so just drop all tiles and clear the live |
| + // tiles rect. |
| + Reset(); |
| + return; |
| + } |
| + |
| + if (old_layer_bounds == new_layer_bounds) |
| + return; |
| + |
| + // The SetLiveTilesRect() method would drop tiles outside the new bounds, |
| + // but may do so incorrectly if resizing the tiling causes the number of |
| + // tiles in the tiling_data_ to change. |
| + gfx::Rect content_rect(content_bounds); |
| + int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x()); |
| + int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y()); |
| + int before_right = |
| + tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1); |
| + int before_bottom = |
| + tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1); |
| + |
| + // The live_tiles_rect_ is clamped to stay within the tiling size as we |
| + // change it. |
| + live_tiles_rect_.Intersect(content_rect); |
| + tiling_data_.SetTilingSize(content_bounds); |
| + |
| + int after_right = -1; |
| + int after_bottom = -1; |
| + if (!live_tiles_rect_.IsEmpty()) { |
| + after_right = |
| + tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1); |
| + after_bottom = |
| + tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1); |
| + } |
| + |
| + // Drop tiles outside the new layer bounds if the layer shrank. |
| + for (int i = after_right + 1; i <= before_right; ++i) { |
| + for (int j = before_top; j <= before_bottom; ++j) |
| + RemoveTileAt(i, j); |
| + } |
| + for (int i = before_left; i <= after_right; ++i) { |
| + for (int j = after_bottom + 1; j <= before_bottom; ++j) |
| + RemoveTileAt(i, j); |
| + } |
| + |
| + CreateMissingTilesInLiveTilesRect(); |
| +} |
| + |
| +void ActivePictureLayerTiling::Invalidate(const Region& layer_invalidation) { |
| + // We only invalidate the active tiling when it's orphaned: it has no pending |
| + // twin, so it's slated for removal in the future. |
| + DCHECK(!client_->GetPendingOrActiveTwinTiling(this)); |
| + if (live_tiles_rect_.IsEmpty()) |
| + return; |
| + std::vector<TileMapKey> new_tile_keys; |
| + gfx::Rect expanded_live_tiles_rect = |
| + tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_); |
| + for (Region::Iterator iter(layer_invalidation); iter.has_rect(); |
| + iter.next()) { |
| + gfx::Rect layer_rect = iter.rect(); |
| + gfx::Rect content_rect = |
| + gfx::ScaleToEnclosingRect(layer_rect, contents_scale_); |
| + // Consider tiles inside the live tiles rect even if only their border |
| + // pixels intersect the invalidation. But don't consider tiles outside |
| + // the live tiles rect with the same conditions, as they won't exist. |
| + int border_pixels = tiling_data_.border_texels(); |
| + content_rect.Inset(-border_pixels, -border_pixels); |
| + // Avoid needless work by not bothering to invalidate where there aren't |
| + // tiles. |
| + content_rect.Intersect(expanded_live_tiles_rect); |
| + if (content_rect.IsEmpty()) |
| + continue; |
| + // Since the content_rect includes border pixels already, don't include |
| + // borders when iterating to avoid double counting them. |
| + bool include_borders = false; |
| + for ( |
| + TilingData::Iterator iter(&tiling_data_, content_rect, include_borders); |
| + iter; ++iter) { |
| + if (RemoveTileAt(iter.index_x(), iter.index_y())) |
| + new_tile_keys.push_back(iter.index()); |
| + } |
| + } |
| + |
| + for (const auto& key : new_tile_keys) |
| + CreateTile(key.first, key.second); |
| +} |
| + |
| +void ActivePictureLayerTiling::SetRasterSourceOnTiles() { |
| + for (auto& tile_pair : tiles_) |
| + tile_pair.second->set_raster_source(raster_source_.get()); |
| +} |
| + |
| +void ActivePictureLayerTiling::CreateMissingTilesInLiveTilesRect() { |
| + bool include_borders = false; |
| + for (TilingData::Iterator iter(&tiling_data_, live_tiles_rect_, |
| + include_borders); |
| + iter; ++iter) { |
| + TileMapKey key = iter.index(); |
| + TileMap::iterator find = tiles_.find(key); |
| + if (find != tiles_.end()) |
| + continue; |
| + CreateTile(key.first, key.second); |
| + } |
| + |
| + VerifyLiveTilesRect(false); |
| +} |
| + |
| +void ActivePictureLayerTiling::TakeTilesAndPropertiesFrom( |
| + PictureLayerTiling* pending_twin) { |
| + SetRasterSourceAndResize(pending_twin->raster_source_); |
| + resolution_ = pending_twin->resolution_; |
| + SetLiveTilesRect(pending_twin->live_tiles_rect()); |
| + |
| + for (const auto& tile_pair : pending_twin->tiles_) |
| + tiles_[tile_pair.first] = tile_pair.second; |
| + pending_twin->tiles_.clear(); |
| + |
| + VerifyLiveTilesRect(false); |
| + |
| + SetTilePriorityRects(pending_twin->current_content_to_screen_scale_, |
| + pending_twin->current_visible_rect_, |
| + pending_twin->current_skewport_rect_, |
| + pending_twin->current_soon_border_rect_, |
| + pending_twin->current_eventually_rect_, |
| + pending_twin->current_occlusion_in_layer_space_); |
| +} |
| + |
| +bool ActivePictureLayerTiling::IsTileOccluded(const Tile* tile) const { |
| + if (!IsTileOccludedOnActiveTree(tile)) |
| + return false; |
| + |
| + // If we decide that the tile is occluded, but the same tile would not be |
|
enne (OOO)
2015/04/02 21:45:34
Can you help me understand this logic in the land
vmpstr
2015/04/02 22:33:26
This tile exists on the active tree and the questi
|
| + // occluded with a pending viewport, then we have to treat this tile as |
| + // unoccluded. |
| + const PictureLayerTiling* pending_twin = |
| + client_->GetPendingOrActiveTwinTiling(this); |
| + if (pending_twin) { |
| + // If there's a pending tile in the same position. Or if the pending twin |
| + // would have to be creating all tiles, then we don't need to worry about |
| + // occlusion on the twin. |
| + if (!TilingMatchesTileIndecies(pending_twin) || |
| + pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) { |
| + return true; |
| + } |
| + return pending_twin->IsTileOccluded(tile); |
| + } |
| + return true; |
| +} |
| + |
| +bool ActivePictureLayerTiling::IsTileRequiredForActivation( |
| + const Tile* tile) const { |
| + const PictureLayerTiling* pending_twin = |
| + client_->GetPendingOrActiveTwinTiling(this); |
| + // If we don't have a pending tree, or the pending tree will overwrite the |
| + // given tile, then it is not required for activation. |
| + if (!pending_twin || !TilingMatchesTileIndecies(pending_twin) || |
| + pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) { |
| + return false; |
| + } |
| + // Otherwise, ask the pending twin if this tile is required for activation. |
| + return pending_twin->IsTileRequiredForActivation(tile); |
| +} |
| + |
| +bool ActivePictureLayerTiling::IsTileRequiredForDraw(const Tile* tile) const { |
| + if (resolution_ != HIGH_RESOLUTION) |
| + return false; |
| + |
| + bool tile_is_visible = current_visible_rect_.Intersects(tile->content_rect()); |
| + if (!tile_is_visible) |
| + return false; |
| + |
| + if (IsTileOccludedOnActiveTree(tile)) |
| + return false; |
| + return true; |
| +} |
| + |
| +bool ActivePictureLayerTiling::IsTileOccludedOnActiveTree( |
|
enne (OOO)
2015/04/02 21:45:34
This looks a lot like PendingPictureLayerTiling::I
vmpstr
2015/04/02 22:33:26
Yep, I think this can be moved to PictureLayerTili
|
| + const Tile* tile) const { |
| + if (!current_occlusion_in_layer_space_.HasOcclusion()) |
| + return false; |
| + gfx::Rect tile_query_rect = |
| + gfx::IntersectRects(tile->content_rect(), current_visible_rect_); |
| + // Explicitly check if the tile is outside the viewport. If so, we need to |
| + // return false, since occlusion for this tile is unknown. |
| + if (tile_query_rect.IsEmpty()) |
| + return false; |
| + |
| + if (contents_scale_ != 1.f) { |
| + tile_query_rect = |
| + gfx::ScaleToEnclosingRect(tile_query_rect, 1.f / contents_scale_); |
| + } |
| + return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect); |
| +} |
| + |
| +void ActivePictureLayerTiling::SetLiveTilesRect( |
| + const gfx::Rect& new_live_tiles_rect) { |
| + DCHECK(new_live_tiles_rect.IsEmpty() || |
| + gfx::Rect(tiling_size()).Contains(new_live_tiles_rect)) |
| + << "tiling_size: " << tiling_size().ToString() |
| + << " new_live_tiles_rect: " << new_live_tiles_rect.ToString(); |
| + if (live_tiles_rect_ == new_live_tiles_rect) |
| + return; |
| + |
| + // Iterate to delete all tiles outside of our new live_tiles rect. |
| + for (TilingData::DifferenceIterator iter(&tiling_data_, live_tiles_rect_, |
| + new_live_tiles_rect); |
| + iter; ++iter) { |
| + RemoveTileAt(iter.index_x(), iter.index_y()); |
| + } |
| + |
| + // Iterate to allocate new tiles for all regions with newly exposed area. |
| + for (TilingData::DifferenceIterator iter(&tiling_data_, new_live_tiles_rect, |
| + live_tiles_rect_); |
| + iter; ++iter) { |
| + TileMapKey key(iter.index()); |
| + CreateTile(key.first, key.second); |
| + } |
| + |
| + live_tiles_rect_ = new_live_tiles_rect; |
| + VerifyLiveTilesRect(false); |
| +} |
| + |
| +} // namespace cc |