| // 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; |
| |
| DCHECK_EQ(!!layer->scroll_parent(), !!layer_impl->scroll_parent()); |
| if (layer->scroll_parent()) |
| DCHECK_EQ(layer->scroll_parent()->id(), layer_impl->scroll_parent()->id()); |
| |
| DCHECK_EQ(!!layer->clip_parent(), !!layer_impl->clip_parent()); |
| if (layer->clip_parent()) |
| DCHECK_EQ(layer->clip_parent()->id(), layer_impl->clip_parent()->id()); |
| |
| DCHECK_EQ(!!layer->scroll_children(), !!layer_impl->scroll_children()); |
| if (layer->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); |
| } |
| } |
| |
| DCHECK_EQ(!!layer->clip_children(), !!layer_impl->clip_children()); |
| if (layer->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 |