#include <algorithm>
#include <limits>
+#include <set>
#include "base/debug/trace_event_argument.h"
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_impl.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/append_quads_data.h"
+#include "cc/layers/solid_color_layer_impl.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/picture_draw_quad.h"
: LayerImpl(tree_impl, id),
twin_layer_(NULL),
pile_(PicturePileImpl::Create()),
- is_mask_(false),
ideal_page_scale_(0.f),
ideal_device_scale_(0.f),
ideal_source_scale_(0.f),
LayerImpl::PushPropertiesTo(base_layer);
// When the pending tree pushes to the active tree, the pending twin
- // disappears.
+ // becomes recycled.
layer_impl->twin_layer_ = NULL;
twin_layer_ = NULL;
- layer_impl->SetIsMask(is_mask_);
layer_impl->pile_ = pile_;
+ DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
// Tilings would be expensive to push, so we swap.
layer_impl->tilings_.swap(tilings_);
+ layer_impl->tilings_->SetClient(layer_impl);
+ if (tilings_)
+ tilings_->SetClient(this);
+
+ // Ensure that the recycle tree doesn't have any unshared tiles.
+ if (tilings_ && pile_->is_solid_color())
+ tilings_->RemoveAllTilings();
// Remove invalidated tiles from what will become a recycle tree.
if (tilings_)
tilings_->RemoveTilesInRegion(invalidation_);
- layer_impl->tilings_->SetClient(layer_impl);
- if (tilings_)
- tilings_->SetClient(this);
-
layer_impl->raster_page_scale_ = raster_page_scale_;
layer_impl->raster_device_scale_ = raster_device_scale_;
layer_impl->raster_source_scale_ = raster_source_scale_;
AppendQuadsData* append_quads_data) {
DCHECK(!needs_post_commit_initialization_);
+ SharedQuadState* shared_quad_state =
+ render_pass->CreateAndAppendSharedQuadState();
+
+ if (pile_->is_solid_color()) {
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ render_pass, content_bounds(), shared_quad_state, append_quads_data);
+
+ SolidColorLayerImpl::AppendSolidQuads(
+ render_pass,
+ occlusion_tracker,
+ shared_quad_state,
+ content_bounds(),
+ draw_properties().target_space_transform,
+ pile_->solid_color());
+ return;
+ }
+
float max_contents_scale = MaximumTilingContentsScale();
gfx::Transform scaled_draw_transform = draw_transform();
scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
gfx::ScaleToEnclosingRect(visible_content_rect(), max_contents_scale);
scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
- SharedQuadState* shared_quad_state =
- render_pass->CreateAndAppendSharedQuadState();
+ Occlusion occlusion =
+ occlusion_tracker.GetCurrentOcclusionForLayer(scaled_draw_transform);
+
shared_quad_state->SetAll(scaled_draw_transform,
scaled_content_bounds,
scaled_visible_content_rect,
gfx::Rect geometry_rect = scaled_visible_content_rect;
gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
- gfx::Rect visible_geometry_rect = occlusion_tracker.UnoccludedContentRect(
- geometry_rect, scaled_draw_transform);
+ gfx::Rect visible_geometry_rect =
+ occlusion.GetUnoccludedContentRect(geometry_rect);
if (visible_geometry_rect.IsEmpty())
return;
// unused can be considered for removal.
std::vector<PictureLayerTiling*> seen_tilings;
+ // Ignore missing tiles outside of viewport for tile priority. This is
+ // normally the same as draw viewport but can be independently overridden by
+ // embedders like Android WebView with SetExternalDrawConstraints.
+ gfx::Rect scaled_viewport_for_tile_priority = gfx::ScaleToEnclosingRect(
+ GetViewportForTilePriorityInContentSpace(), max_contents_scale);
+
size_t missing_tile_count = 0u;
size_t on_demand_missing_tile_count = 0u;
for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
iter;
++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
- gfx::Rect visible_geometry_rect = occlusion_tracker.UnoccludedContentRect(
- geometry_rect, scaled_draw_transform);
+ gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
+ gfx::Rect visible_geometry_rect =
+ occlusion.GetUnoccludedContentRect(geometry_rect);
if (visible_geometry_rect.IsEmpty())
continue;
append_quads_data->visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
+ bool has_draw_quad = false;
if (*iter && iter->IsReadyToDraw()) {
const ManagedTileState::TileVersion& tile_version =
iter->GetTileVersionForDrawing();
switch (tile_version.mode()) {
case ManagedTileState::TileVersion::RESOURCE_MODE: {
gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
- if (iter->contents_scale() != ideal_contents_scale_)
+ // The raster_contents_scale_ is the best scale that the layer is
+ // trying to produce, even though it may not be ideal. Since that's
+ // the best the layer can promise in the future, consider those as
+ // complete. But if a tile is ideal scale, we don't want to consider
+ // it incomplete and trying to replace it with a tile at a worse
+ // scale.
+ if (iter->contents_scale() != raster_contents_scale_ &&
+ iter->contents_scale() != ideal_contents_scale_ &&
+ geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
append_quads_data->num_incomplete_tiles++;
+ }
TileDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
texture_rect,
iter.texture_size(),
tile_version.contents_swizzled());
+ has_draw_quad = true;
break;
}
case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
}
gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
ResourceProvider* resource_provider =
layer_tree_impl()->resource_provider();
iter->content_rect(),
iter->contents_scale(),
pile_);
+ has_draw_quad = true;
break;
}
case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
visible_geometry_rect,
tile_version.get_solid_color(),
false);
+ has_draw_quad = true;
break;
}
}
- } else {
+ }
+
+ if (!has_draw_quad) {
if (draw_checkerboard_for_missing_tiles()) {
CheckerboardDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
false);
}
- append_quads_data->num_missing_tiles++;
+ if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
+ append_quads_data->num_missing_tiles++;
+ ++missing_tile_count;
+ }
append_quads_data->approximated_visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
- ++missing_tile_count;
continue;
}
}
void PictureLayerImpl::UpdateTiles(
- const OcclusionTracker<LayerImpl>* occlusion_tracker) {
+ const Occlusion& occlusion_in_content_space) {
TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTiles");
+ DCHECK_EQ(1.f, contents_scale_x());
+ DCHECK_EQ(1.f, contents_scale_y());
DoPostCommitInitializationIfNeeded();
- // TODO(danakj): We should always get an occlusion tracker when we are using
- // occlusion, so update this check when we don't use a pending tree in the
- // browser compositor.
- DCHECK(!occlusion_tracker ||
- layer_tree_impl()->settings().use_occlusion_for_tile_prioritization);
-
- // Transforms and viewport are invalid for tile management inside a
- // resourceless software draw, so don't update them.
- if (!layer_tree_impl()->resourceless_software_draw()) {
- visible_rect_for_tile_priority_ = visible_content_rect();
- viewport_rect_for_tile_priority_ =
- layer_tree_impl()->ViewportRectForTilePriority();
- screen_space_transform_for_tile_priority_ = screen_space_transform();
- }
+ visible_rect_for_tile_priority_ = visible_content_rect();
+ viewport_rect_for_tile_priority_ =
+ layer_tree_impl()->ViewportRectForTilePriority();
+ screen_space_transform_for_tile_priority_ = screen_space_transform();
if (!CanHaveTilings()) {
ideal_page_scale_ = 0.f;
should_update_tile_priorities_ = true;
- UpdateTilePriorities(occlusion_tracker);
+ UpdateTilePriorities(occlusion_in_content_space);
if (layer_tree_impl()->IsPendingTree())
MarkVisibleResourcesAsRequired();
}
void PictureLayerImpl::UpdateTilePriorities(
- const OcclusionTracker<LayerImpl>* occlusion_tracker) {
+ const Occlusion& occlusion_in_content_space) {
+ DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+
TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTilePriorities");
double current_frame_time_in_seconds =
- (layer_tree_impl()->CurrentFrameTimeTicks() -
+ (layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
base::TimeTicks()).InSecondsF();
bool tiling_needs_update = false;
if (!tiling_needs_update)
return;
+ gfx::Rect viewport_rect_in_layer_space =
+ GetViewportForTilePriorityInContentSpace();
+ WhichTree tree =
+ layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
+ // they are the same space in picture lbayer, as contents scale is always 1.
+ tilings_->tiling_at(i)->UpdateTilePriorities(tree,
+ viewport_rect_in_layer_space,
+ ideal_contents_scale_,
+ current_frame_time_in_seconds,
+ occlusion_in_content_space);
+ }
+
+ // Tile priorities were modified.
+ layer_tree_impl()->DidModifyTilePriorities();
+}
+
+gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
// If visible_rect_for_tile_priority_ is empty or
// viewport_rect_for_tile_priority_ is set to be different from the device
// viewport, try to inverse project the viewport into layer space and use
visible_rect_in_content_space =
gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
view_to_layer, viewport_rect_for_tile_priority_));
-
- visible_rect_in_content_space.Intersect(gfx::Rect(content_bounds()));
}
}
+ return visible_rect_in_content_space;
+}
- gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
- visible_rect_in_content_space, 1.f / contents_scale_x());
- WhichTree tree =
- layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- tilings_->tiling_at(i)->UpdateTilePriorities(tree,
- visible_layer_rect,
- ideal_contents_scale_,
- current_frame_time_in_seconds,
- occlusion_tracker,
- render_target(),
- draw_transform());
- }
-
- // Tile priorities were modified.
- layer_tree_impl()->DidModifyTilePriorities();
+PictureLayerImpl* PictureLayerImpl::GetRecycledTwinLayer() {
+ // TODO(vmpstr): Maintain recycled twin as a member. crbug.com/407418
+ return static_cast<PictureLayerImpl*>(
+ layer_tree_impl()->FindRecycleTreeLayerById(id()));
}
void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
const gfx::Rect& content_rect) {
+ DCHECK(!pile_->is_solid_color());
if (!pile_->CanRaster(tiling->contents_scale(), content_rect))
return scoped_refptr<Tile>();
+ int flags = 0;
+
// TODO(vmpstr): Revisit this. For now, enabling analysis means that we get as
// much savings on memory as we can. However, for some cases like ganesh or
// small layers, the amount of time we spend analyzing might not justify
- // memory savings that we can get.
+ // memory savings that we can get. Note that we don't handle solid color
+ // masks, so we shouldn't bother analyzing those.
// Bugs: crbug.com/397198, crbug.com/396908
- int flags = Tile::USE_PICTURE_ANALYSIS;
+ if (!pile_->is_mask())
+ flags = Tile::USE_PICTURE_ANALYSIS;
return layer_tree_impl()->tile_manager()->CreateTile(
pile_.get(),
content_rect.size(),
content_rect,
- contents_opaque() ? content_rect : gfx::Rect(),
tiling->contents_scale(),
id(),
layer_tree_impl()->source_frame_number(),
const PictureLayerTiling* tiling) const {
if (!twin_layer_)
return NULL;
- for (size_t i = 0; i < twin_layer_->tilings_->num_tilings(); ++i)
- if (twin_layer_->tilings_->tiling_at(i)->contents_scale() ==
- tiling->contents_scale())
- return twin_layer_->tilings_->tiling_at(i);
- return NULL;
+ return twin_layer_->tilings_->TilingAtScale(tiling->contents_scale());
+}
+
+PictureLayerTiling* PictureLayerImpl::GetRecycledTwinTiling(
+ const PictureLayerTiling* tiling) {
+ PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
+ if (!recycled_twin || !recycled_twin->tilings_)
+ return NULL;
+ return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
}
size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
gfx::Size PictureLayerImpl::CalculateTileSize(
const gfx::Size& content_bounds) const {
- if (is_mask_) {
- int max_size = layer_tree_impl()->MaxTextureSize();
- return gfx::Size(
- std::min(max_size, content_bounds.width()),
- std::min(max_size, content_bounds.height()));
- }
-
int max_texture_size =
layer_tree_impl()->resource_provider()->max_texture_size();
+ if (pile_->is_mask()) {
+ // Masks are not tiled, so if we can't cover the whole mask with one tile,
+ // don't make any tiles at all. Returning an empty size signals this.
+ if (content_bounds.width() > max_texture_size ||
+ content_bounds.height() > max_texture_size)
+ return gfx::Size();
+ return content_bounds;
+ }
+
gfx::Size default_tile_size = layer_tree_impl()->settings().default_tile_size;
if (layer_tree_impl()->use_gpu_rasterization()) {
// TODO(ernstm) crbug.com/365877: We need a unified way to override the
// when we stop using the pending tree in the browser compositor. If we want
// to support occlusion tracking here, we need to dirty the draw properties
// or save occlusion as a draw property.
- UpdateTilePriorities(NULL);
+ UpdateTilePriorities(Occlusion());
}
}
-void PictureLayerImpl::SetIsMask(bool is_mask) {
- if (is_mask_ == is_mask)
- return;
- is_mask_ = is_mask;
- if (tilings_)
- tilings_->RemoveAllTiles();
-}
-
ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
gfx::Rect content_rect(content_bounds());
- float scale = MaximumTilingContentsScale();
PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), scale, content_rect, ideal_contents_scale_);
+ tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
// Mask resource not ready yet.
if (!iter || !*iter)
return 0;
// Masks only supported if they fit on exactly one tile.
- if (iter.geometry_rect() != content_rect)
- return 0;
+ DCHECK(iter.geometry_rect() == content_rect)
+ << "iter rect " << iter.geometry_rect().ToString() << " content rect "
+ << content_rect.ToString();
const ManagedTileState::TileVersion& tile_version =
iter->GetTileVersionForDrawing();
if (visible_content_rect().IsEmpty())
return;
- gfx::Rect rect(visible_content_rect());
+ // Only mark tiles inside the viewport for tile priority as required for
+ // activation. This viewport is normally the same as the draw viewport but
+ // can be independently overridden by embedders like Android WebView with
+ // SetExternalDrawConstraints.
+ gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
+ rect.Intersect(visible_content_rect());
float min_acceptable_scale =
std::min(raster_contents_scale_, ideal_contents_scale_);
high_res = tiling;
continue;
}
- for (PictureLayerTiling::CoverageIterator iter(tiling,
- contents_scale_x(),
- rect);
- iter;
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
++iter) {
if (!*iter || !iter->IsReadyToDraw())
continue;
// As a second pass, mark as required any visible high res tiles not filled in
// by acceptable non-ideal tiles from the first pass.
if (MarkVisibleTilesAsRequired(
- high_res, twin_high_res, contents_scale_x(), rect, missing_region)) {
+ high_res, twin_high_res, rect, missing_region)) {
// As an optional third pass, if a high res tile was skipped because its
// twin was also missing, then fall back to mark low res tiles as required
// in case the active twin is substituting those for missing high res
// content. Only suitable, when low res is enabled.
if (low_res) {
- MarkVisibleTilesAsRequired(
- low_res, twin_low_res, contents_scale_x(), rect, missing_region);
+ MarkVisibleTilesAsRequired(low_res, twin_low_res, rect, missing_region);
}
}
}
bool PictureLayerImpl::MarkVisibleTilesAsRequired(
PictureLayerTiling* tiling,
const PictureLayerTiling* optional_twin_tiling,
- float contents_scale,
const gfx::Rect& rect,
const Region& missing_region) const {
bool twin_had_missing_tile = false;
- for (PictureLayerTiling::CoverageIterator iter(tiling,
- contents_scale,
- rect);
- iter;
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
++iter) {
Tile* tile = *iter;
// A null tile (i.e. missing recording) can just be skipped.
if (optional_twin_tiling) {
Tile* twin_tile = optional_twin_tiling->TileAt(iter.i(), iter.j());
if (!twin_tile || twin_tile == tile) {
- twin_had_missing_tile = true;
+ // However if the shared tile is being used on the active tree, then
+ // there's no missing content in this place, and low res is not needed.
+ if (!twin_tile || !twin_tile->IsReadyToDraw())
+ twin_had_missing_tile = true;
continue;
}
}
draw_properties().screen_space_transform_is_animating)
return true;
+ if (draw_properties().screen_space_transform_is_animating &&
+ raster_contents_scale_ != ideal_contents_scale_ &&
+ ShouldAdjustRasterScaleDuringScaleAnimations())
+ return true;
+
bool is_pinching = layer_tree_impl()->PinchGestureActive();
if (is_pinching && raster_page_scale_) {
// We change our raster scale when it is:
// TODO(danakj): Adjust raster source scale closer to ideal source scale at
// a throttled rate. Possibly make use of invalidation_.IsEmpty() on pending
// tree. This will allow CSS scale changes to get re-rastered at an
- // appropriate rate.
+ // appropriate rate. (crbug.com/413636)
if (raster_source_scale_is_fixed_) {
raster_contents_scale_ /= raster_source_scale_;
raster_source_scale_ = 1.f;
raster_contents_scale_ =
std::max(raster_contents_scale_, MinimumContentsScale());
- // Since we're not re-rasterizing during animation, rasterize at the maximum
+ // If we're not re-rasterizing during animation, rasterize at the maximum
// scale that will occur during the animation, if the maximum scale is
// known. However, to avoid excessive memory use, don't rasterize at a scale
// at which this layer would become larger than the viewport.
- if (draw_properties().screen_space_transform_is_animating) {
+ if (draw_properties().screen_space_transform_is_animating &&
+ !ShouldAdjustRasterScaleDuringScaleAnimations()) {
bool can_raster_at_maximum_scale = false;
if (draw_properties().maximum_animation_contents_scale > 0.f) {
gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(gfx::ScaleSize(
}
}
- // If this layer would only create one tile at this content scale,
+ // If this layer would create zero or one tiles at this content scale,
// don't create a low res tiling.
gfx::Size content_bounds =
gfx::ToCeiledSize(gfx::ScaleSize(bounds(), raster_contents_scale_));
gfx::Size tile_size = CalculateTileSize(content_bounds);
- if (tile_size.width() >= content_bounds.width() &&
- tile_size.height() >= content_bounds.height()) {
+ bool tile_covers_bounds = tile_size.width() >= content_bounds.width() &&
+ tile_size.height() >= content_bounds.height();
+ if (tile_size.IsEmpty() || tile_covers_bounds) {
low_res_raster_contents_scale_ = raster_contents_scale_;
return;
}
if (to_remove.empty())
return;
- PictureLayerImpl* recycled_twin = static_cast<PictureLayerImpl*>(
- layer_tree_impl()->FindRecycleTreeLayerById(id()));
+ PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
// Remove tilings on this tree and the twin tree.
for (size_t i = 0; i < to_remove.size(); ++i) {
const PictureLayerTiling* twin_tiling = GetTwinTiling(to_remove[i]);
}
bool PictureLayerImpl::CanHaveTilings() const {
+ if (pile_->is_solid_color())
+ return false;
if (!DrawsContent())
return false;
if (!pile_->HasRecordings())
#endif
}
+bool PictureLayerImpl::ShouldAdjustRasterScaleDuringScaleAnimations() const {
+ if (!layer_tree_impl()->use_gpu_rasterization())
+ return false;
+
+ // Re-rastering text at different scales using GPU rasterization causes
+ // texture uploads for glyphs at each scale (see crbug.com/366225). To
+ // workaround this performance issue, we don't re-rasterize layers with
+ // text during scale animations.
+ // TODO(ajuma): Remove this workaround once text can be efficiently
+ // re-rastered at different scales (e.g. by using distance-field fonts).
+ if (pile_->has_text())
+ return false;
+
+ return true;
+}
+
float PictureLayerImpl::MaximumTilingContentsScale() const {
float max_contents_scale = MinimumContentsScale();
for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
*width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}
+void PictureLayerImpl::GetAllTilesForTracing(
+ std::set<const Tile*>* tiles) const {
+ if (!tilings_)
+ return;
+
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i)
+ tilings_->tiling_at(i)->GetAllTilesForTracing(tiles);
+}
+
void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded();
LayerImpl::AsValueInto(state);
tilings_->AsValueInto(state);
state->EndArray();
+ state->BeginArray("tile_priority_rect");
+ MathUtil::AddToTracedValue(GetViewportForTilePriorityInContentSpace(), state);
+ state->EndArray();
+
+ state->BeginArray("visible_rect");
+ MathUtil::AddToTracedValue(visible_content_rect(), state);
+ state->EndArray();
+
state->BeginArray("pictures");
pile_->AsValueInto(state);
state->EndArray();
state->BeginArray("coverage_tiles");
for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
- contents_scale_x(),
+ 1.f,
gfx::Rect(content_bounds()),
ideal_contents_scale_);
iter;
continue;
gfx::Rect rect(visible_content_rect());
- for (PictureLayerTiling::CoverageIterator iter(
- tiling, contents_scale_x(), rect);
- iter;
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
++iter) {
const Tile* tile = *iter;
// A null tile (i.e. missing recording) can just be skipped.
IteratorType index = stages_[current_stage_].iterator_type;
TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
if (!iterators_[index] || iterators_[index].get_type() != tile_type)
- ++(*this);
+ AdvanceToNextStage();
}
PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {}
TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
// First advance the iterator.
- if (iterators_[index])
- ++iterators_[index];
-
- if (iterators_[index] && iterators_[index].get_type() == tile_type)
- return *this;
+ DCHECK(iterators_[index]);
+ DCHECK(iterators_[index].get_type() == tile_type);
+ ++iterators_[index];
- // Next, advance the stage.
- ++current_stage_;
- while (current_stage_ < arraysize(stages_)) {
- index = stages_[current_stage_].iterator_type;
- tile_type = stages_[current_stage_].tile_type;
+ if (!iterators_[index] || iterators_[index].get_type() != tile_type)
+ AdvanceToNextStage();
- if (iterators_[index] && iterators_[index].get_type() == tile_type)
- break;
- ++current_stage_;
- }
return *this;
}
return *iterators_[index];
}
+void PictureLayerImpl::LayerRasterTileIterator::AdvanceToNextStage() {
+ DCHECK_LT(current_stage_, arraysize(stages_));
+ ++current_stage_;
+ while (current_stage_ < arraysize(stages_)) {
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+ if (iterators_[index] && iterators_[index].get_type() == tile_type)
+ break;
+ ++current_stage_;
+ }
+}
+
PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
: layer_(NULL),
tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),