| 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 | 
|  |