blob: 72c14d3e8f81bf7f09178f87c4de489b30bc00cb [file] [log] [blame]
// Copyright 2017 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/layers/effect_tree_layer_list_iterator.h"
namespace cc {
EffectTreeLayerListIterator::EffectTreeLayerListIterator(
LayerTreeImpl* layer_tree_impl)
: state_(EffectTreeLayerListIterator::State::END),
current_effect_tree_index_(EffectTree::kInvalidNodeId),
next_effect_tree_index_(EffectTree::kInvalidNodeId),
lowest_common_effect_tree_ancestor_index_(EffectTree::kInvalidNodeId),
layer_tree_impl_(layer_tree_impl),
effect_tree_(&layer_tree_impl->property_trees()->effect_tree) {
layer_list_iterator_ = layer_tree_impl->rbegin();
// Find the front-most drawn layer.
while (
layer_list_iterator_ != layer_tree_impl->rend() &&
!(*layer_list_iterator_)->is_drawn_render_surface_layer_list_member()) {
layer_list_iterator_++;
}
// If there are no drawn layers, start at the root render surface, if it
// exists.
if (layer_list_iterator_ == layer_tree_impl->rend()) {
DCHECK(effect_tree_->size() > EffectTree::kContentsRootNodeId);
state_ = State::TARGET_SURFACE;
current_effect_tree_index_ = EffectTree::kContentsRootNodeId;
} else {
state_ = State::LAYER;
current_effect_tree_index_ =
(*layer_list_iterator_)->render_target_effect_tree_index();
next_effect_tree_index_ = current_effect_tree_index_;
lowest_common_effect_tree_ancestor_index_ = current_effect_tree_index_;
}
}
EffectTreeLayerListIterator::EffectTreeLayerListIterator(
const EffectTreeLayerListIterator& iterator) = default;
EffectTreeLayerListIterator::~EffectTreeLayerListIterator() {}
void EffectTreeLayerListIterator::operator++() {
switch (state_) {
case State::LAYER:
// Find the next drawn layer.
layer_list_iterator_++;
while (layer_list_iterator_ != layer_tree_impl_->rend() &&
!(*layer_list_iterator_)
->is_drawn_render_surface_layer_list_member()) {
layer_list_iterator_++;
}
if (layer_list_iterator_ == layer_tree_impl_->rend()) {
next_effect_tree_index_ = EffectTree::kInvalidNodeId;
lowest_common_effect_tree_ancestor_index_ = EffectTree::kInvalidNodeId;
state_ = State::TARGET_SURFACE;
break;
}
next_effect_tree_index_ =
(*layer_list_iterator_)->render_target_effect_tree_index();
// If the next drawn layer has a different target effect tree index, check
// for surfaces whose contributors have all been visited.
if (next_effect_tree_index_ != current_effect_tree_index_) {
lowest_common_effect_tree_ancestor_index_ =
effect_tree_->LowestCommonAncestorWithRenderSurface(
current_effect_tree_index_, next_effect_tree_index_);
// If the current layer's target effect node is an ancestor of the next
// layer's target effect node, then the current effect node still has
// more contributors that need to be visited. Otherwise, all
// contributors have been visited, so we visit the node's surface next.
if (current_effect_tree_index_ ==
lowest_common_effect_tree_ancestor_index_) {
current_effect_tree_index_ = next_effect_tree_index_;
lowest_common_effect_tree_ancestor_index_ = next_effect_tree_index_;
} else {
state_ = State::TARGET_SURFACE;
}
}
break;
case State::TARGET_SURFACE:
if (current_effect_tree_index_ == EffectTree::kContentsRootNodeId) {
current_effect_tree_index_ = EffectTree::kInvalidNodeId;
state_ = State::END;
DCHECK(next_effect_tree_index_ == EffectTree::kInvalidNodeId);
DCHECK(layer_list_iterator_ == layer_tree_impl_->rend());
} else {
state_ = State::CONTRIBUTING_SURFACE;
}
break;
case State::CONTRIBUTING_SURFACE:
DCHECK(current_effect_tree_index_ !=
lowest_common_effect_tree_ancestor_index_);
// Step towards the lowest common ancestor.
current_effect_tree_index_ =
effect_tree_->Node(current_effect_tree_index_)->target_id;
if (current_effect_tree_index_ == next_effect_tree_index_) {
state_ = State::LAYER;
} else if (current_effect_tree_index_ ==
lowest_common_effect_tree_ancestor_index_) {
// In this case, we know that more content contributes to the current
// effect node (since the next effect node is a descendant), so we're
// not yet ready to visit it as a target surface. The same holds for all
// effect nodes on the path from the current node to the next effect
// tree node.
state_ = State::LAYER;
current_effect_tree_index_ = next_effect_tree_index_;
lowest_common_effect_tree_ancestor_index_ = next_effect_tree_index_;
} else {
// In this case, the lowest common ancestor is a proper ancestor of the
// current effect node. This means that all contributors to the current
// effect node have been visited, so we're ready to visit it as a target
// surface.
state_ = State::TARGET_SURFACE;
}
break;
case State::END:
NOTREACHED();
}
}
} // namespace cc