blob: 1faf0e04e679d468b91ab49ef5e209794d8abea5 [file] [log] [blame]
// 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