Index: cc/layers/effect_tree_layer_list_iterator.cc |
diff --git a/cc/layers/effect_tree_layer_list_iterator.cc b/cc/layers/effect_tree_layer_list_iterator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a5228dcb85174694de51f21029ae30508bd9e1a5 |
--- /dev/null |
+++ b/cc/layers/effect_tree_layer_list_iterator.cc |
@@ -0,0 +1,139 @@ |
+// 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() {} |
+ |
+// Finds the lowest common ancestor that has a render surface. |
+static int LowestCommonAncestor(int effect_id_1, |
+ int effect_id_2, |
+ const EffectTree* effect_tree) { |
+ while (effect_id_1 != effect_id_2) { |
+ if (effect_id_1 < effect_id_2) |
+ effect_id_2 = effect_tree->Node(effect_id_2)->target_id; |
+ else |
+ effect_id_1 = effect_tree->Node(effect_id_1)->target_id; |
+ } |
+ |
+ return effect_id_1; |
+} |
+ |
+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_ = LowestCommonAncestor( |
+ current_effect_tree_index_, next_effect_tree_index_, effect_tree_); |
+ // 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 |