普通文本  |  312行  |  10.62 KB

// Copyright 2011 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/trees/tree_synchronizer.h"

#include <set>

#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
#include "cc/layers/scrollbar_layer_interface.h"

namespace cc {

typedef base::ScopedPtrHashMap<int, LayerImpl> ScopedPtrLayerImplMap;
typedef base::hash_map<int, LayerImpl*> RawPtrLayerImplMap;

void CollectExistingLayerImplRecursive(ScopedPtrLayerImplMap* old_layers,
                                       scoped_ptr<LayerImpl> layer_impl) {
  if (!layer_impl)
    return;

  layer_impl->ClearScrollbars();
  if (ScrollbarLayerImplBase* scrollbar_layer =
          layer_impl->ToScrollbarLayer()) {
    scrollbar_layer->ClearClipLayer();
    scrollbar_layer->ClearScrollLayer();
  }

  OwnedLayerImplList& children = layer_impl->children();
  for (OwnedLayerImplList::iterator it = children.begin();
       it != children.end();
       ++it)
    CollectExistingLayerImplRecursive(old_layers, children.take(it));

  CollectExistingLayerImplRecursive(old_layers, layer_impl->TakeMaskLayer());
  CollectExistingLayerImplRecursive(old_layers, layer_impl->TakeReplicaLayer());

  int id = layer_impl->id();
  old_layers->set(id, layer_impl.Pass());
}

template <typename LayerType>
scoped_ptr<LayerImpl> SynchronizeTreesInternal(
    LayerType* layer_root,
    scoped_ptr<LayerImpl> old_layer_impl_root,
    LayerTreeImpl* tree_impl) {
  DCHECK(tree_impl);

  TRACE_EVENT0("cc", "TreeSynchronizer::SynchronizeTrees");
  ScopedPtrLayerImplMap old_layers;
  RawPtrLayerImplMap new_layers;

  CollectExistingLayerImplRecursive(&old_layers, old_layer_impl_root.Pass());

  scoped_ptr<LayerImpl> new_tree = SynchronizeTreesRecursive(
      &new_layers, &old_layers, layer_root, tree_impl);

  UpdateScrollbarLayerPointersRecursive(&new_layers, layer_root);

  return new_tree.Pass();
}

scoped_ptr<LayerImpl> TreeSynchronizer::SynchronizeTrees(
    Layer* layer_root,
    scoped_ptr<LayerImpl> old_layer_impl_root,
    LayerTreeImpl* tree_impl) {
  return SynchronizeTreesInternal(
      layer_root, old_layer_impl_root.Pass(), tree_impl);
}

scoped_ptr<LayerImpl> TreeSynchronizer::SynchronizeTrees(
    LayerImpl* layer_root,
    scoped_ptr<LayerImpl> old_layer_impl_root,
    LayerTreeImpl* tree_impl) {
  return SynchronizeTreesInternal(
      layer_root, old_layer_impl_root.Pass(), tree_impl);
}

template <typename LayerType>
scoped_ptr<LayerImpl> ReuseOrCreateLayerImpl(RawPtrLayerImplMap* new_layers,
                                             ScopedPtrLayerImplMap* old_layers,
                                             LayerType* layer,
                                             LayerTreeImpl* tree_impl) {
  scoped_ptr<LayerImpl> layer_impl = old_layers->take(layer->id());

  if (!layer_impl)
    layer_impl = layer->CreateLayerImpl(tree_impl);

  (*new_layers)[layer->id()] = layer_impl.get();
  return layer_impl.Pass();
}

template <typename LayerType>
scoped_ptr<LayerImpl> SynchronizeTreesRecursiveInternal(
    RawPtrLayerImplMap* new_layers,
    ScopedPtrLayerImplMap* old_layers,
    LayerType* layer,
    LayerTreeImpl* tree_impl) {
  if (!layer)
    return scoped_ptr<LayerImpl>();

  scoped_ptr<LayerImpl> layer_impl =
      ReuseOrCreateLayerImpl(new_layers, old_layers, layer, tree_impl);

  layer_impl->ClearChildList();
  for (size_t i = 0; i < layer->children().size(); ++i) {
    layer_impl->AddChild(SynchronizeTreesRecursiveInternal(
        new_layers, old_layers, layer->child_at(i), tree_impl));
  }

  layer_impl->SetMaskLayer(SynchronizeTreesRecursiveInternal(
      new_layers, old_layers, layer->mask_layer(), tree_impl));
  layer_impl->SetReplicaLayer(SynchronizeTreesRecursiveInternal(
      new_layers, old_layers, layer->replica_layer(), tree_impl));

  return layer_impl.Pass();
}

scoped_ptr<LayerImpl> SynchronizeTreesRecursive(
    RawPtrLayerImplMap* new_layers,
    ScopedPtrLayerImplMap* old_layers,
    Layer* layer,
    LayerTreeImpl* tree_impl) {
  return SynchronizeTreesRecursiveInternal(
      new_layers, old_layers, layer, tree_impl);
}

scoped_ptr<LayerImpl> SynchronizeTreesRecursive(
    RawPtrLayerImplMap* new_layers,
    ScopedPtrLayerImplMap* old_layers,
    LayerImpl* layer,
    LayerTreeImpl* tree_impl) {
  return SynchronizeTreesRecursiveInternal(
      new_layers, old_layers, layer, tree_impl);
}

template <typename LayerType, typename ScrollbarLayerType>
void UpdateScrollbarLayerPointersRecursiveInternal(
    const RawPtrLayerImplMap* new_layers,
    LayerType* layer) {
  if (!layer)
    return;

  for (size_t i = 0; i < layer->children().size(); ++i) {
    UpdateScrollbarLayerPointersRecursiveInternal<
        LayerType, ScrollbarLayerType>(new_layers, layer->child_at(i));
  }

  ScrollbarLayerType* scrollbar_layer = layer->ToScrollbarLayer();
  if (!scrollbar_layer)
    return;

  RawPtrLayerImplMap::const_iterator iter =
      new_layers->find(layer->id());
  ScrollbarLayerImplBase* scrollbar_layer_impl =
      iter != new_layers->end()
          ? static_cast<ScrollbarLayerImplBase*>(iter->second)
          : NULL;
  DCHECK(scrollbar_layer_impl);

  scrollbar_layer->PushScrollClipPropertiesTo(scrollbar_layer_impl);
}

void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
                                           Layer* layer) {
  UpdateScrollbarLayerPointersRecursiveInternal<Layer, ScrollbarLayerInterface>(
      new_layers, layer);
}

void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
                                           LayerImpl* layer) {
  UpdateScrollbarLayerPointersRecursiveInternal<
      LayerImpl,
      ScrollbarLayerImplBase>(new_layers, layer);
}

// static
template <typename LayerType>
void TreeSynchronizer::PushPropertiesInternal(
    LayerType* layer,
    LayerImpl* layer_impl,
    size_t* num_dependents_need_push_properties_for_parent) {
  if (!layer) {
    DCHECK(!layer_impl);
    return;
  }

  DCHECK_EQ(layer->id(), layer_impl->id());

  bool push_layer = layer->needs_push_properties();
  bool recurse_on_children_and_dependents =
      layer->descendant_needs_push_properties();

  if (push_layer)
    layer->PushPropertiesTo(layer_impl);
  else if (layer->ToScrollbarLayer())
    layer->ToScrollbarLayer()->PushScrollClipPropertiesTo(layer_impl);

  size_t num_dependents_need_push_properties = 0;
  if (recurse_on_children_and_dependents) {
    PushPropertiesInternal(layer->mask_layer(),
                           layer_impl->mask_layer(),
                           &num_dependents_need_push_properties);
    PushPropertiesInternal(layer->replica_layer(),
                           layer_impl->replica_layer(),
                           &num_dependents_need_push_properties);

    const OwnedLayerImplList& impl_children = layer_impl->children();
    DCHECK_EQ(layer->children().size(), impl_children.size());

    for (size_t i = 0; i < layer->children().size(); ++i) {
      PushPropertiesInternal(layer->child_at(i),
                             impl_children[i],
                             &num_dependents_need_push_properties);
    }

    // When PushPropertiesTo completes for a layer, it may still keep
    // its needs_push_properties() state if the layer must push itself
    // every PushProperties tree walk. Here we keep track of those layers, and
    // ensure that their ancestors know about them for the next PushProperties
    // tree walk.
    layer->num_dependents_need_push_properties_ =
        num_dependents_need_push_properties;
  }

  bool add_self_to_parent = num_dependents_need_push_properties > 0 ||
                            layer->needs_push_properties();
  *num_dependents_need_push_properties_for_parent += add_self_to_parent ? 1 : 0;
}

static void CheckScrollAndClipPointersRecursive(Layer* layer,
                                                LayerImpl* layer_impl) {
  DCHECK_EQ(!!layer, !!layer_impl);
  if (!layer)
    return;

  // Having a scroll parent on the impl thread implies having one the main
  // thread, too. The main thread may have a scroll parent that is not in the
  // tree because it's been removed but not deleted. In this case, the layer
  // impl will have no scroll parent. Same argument applies for clip parents and
  // scroll/clip children.
  DCHECK(!layer_impl->scroll_parent() || !!layer->scroll_parent());
  DCHECK(!layer_impl->clip_parent() || !!layer->clip_parent());
  DCHECK(!layer_impl->scroll_children() || !!layer->scroll_children());
  DCHECK(!layer_impl->clip_children() || !!layer->clip_children());

  if (layer_impl->scroll_parent())
    DCHECK_EQ(layer->scroll_parent()->id(), layer_impl->scroll_parent()->id());

  if (layer_impl->clip_parent())
    DCHECK_EQ(layer->clip_parent()->id(), layer_impl->clip_parent()->id());

  if (layer_impl->scroll_children()) {
    for (std::set<Layer*>::iterator it = layer->scroll_children()->begin();
         it != layer->scroll_children()->end();
         ++it) {
      DCHECK_EQ((*it)->scroll_parent(), layer);
    }
    for (std::set<LayerImpl*>::iterator it =
             layer_impl->scroll_children()->begin();
         it != layer_impl->scroll_children()->end();
         ++it) {
      DCHECK_EQ((*it)->scroll_parent(), layer_impl);
    }
  }

  if (layer_impl->clip_children()) {
    for (std::set<Layer*>::iterator it = layer->clip_children()->begin();
         it != layer->clip_children()->end();
         ++it) {
      DCHECK_EQ((*it)->clip_parent(), layer);
    }
    for (std::set<LayerImpl*>::iterator it =
             layer_impl->clip_children()->begin();
         it != layer_impl->clip_children()->end();
         ++it) {
      DCHECK_EQ((*it)->clip_parent(), layer_impl);
    }
  }

  for (size_t i = 0u; i < layer->children().size(); ++i) {
    CheckScrollAndClipPointersRecursive(layer->child_at(i),
                                        layer_impl->child_at(i));
  }
}

void TreeSynchronizer::PushProperties(Layer* layer,
                                      LayerImpl* layer_impl) {
  size_t num_dependents_need_push_properties = 0;
  PushPropertiesInternal(
      layer, layer_impl, &num_dependents_need_push_properties);
#if DCHECK_IS_ON
  CheckScrollAndClipPointersRecursive(layer, layer_impl);
#endif
}

void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) {
  size_t num_dependents_need_push_properties = 0;
  PushPropertiesInternal(
      layer, layer_impl, &num_dependents_need_push_properties);
}

}  // namespace cc