1 // Copyright 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cc/trees/tree_synchronizer.h" 6 7 #include <set> 8 9 #include "base/containers/hash_tables.h" 10 #include "base/containers/scoped_ptr_hash_map.h" 11 #include "base/debug/trace_event.h" 12 #include "base/logging.h" 13 #include "cc/animation/scrollbar_animation_controller.h" 14 #include "cc/input/scrollbar.h" 15 #include "cc/layers/layer.h" 16 #include "cc/layers/layer_impl.h" 17 #include "cc/layers/scrollbar_layer_impl_base.h" 18 #include "cc/layers/scrollbar_layer_interface.h" 19 20 namespace cc { 21 22 typedef base::ScopedPtrHashMap<int, LayerImpl> ScopedPtrLayerImplMap; 23 typedef base::hash_map<int, LayerImpl*> RawPtrLayerImplMap; 24 25 void CollectExistingLayerImplRecursive(ScopedPtrLayerImplMap* old_layers, 26 scoped_ptr<LayerImpl> layer_impl) { 27 if (!layer_impl) 28 return; 29 30 layer_impl->ClearScrollbars(); 31 if (ScrollbarLayerImplBase* scrollbar_layer = 32 layer_impl->ToScrollbarLayer()) { 33 scrollbar_layer->ClearClipLayer(); 34 scrollbar_layer->ClearScrollLayer(); 35 } 36 37 OwnedLayerImplList& children = layer_impl->children(); 38 for (OwnedLayerImplList::iterator it = children.begin(); 39 it != children.end(); 40 ++it) 41 CollectExistingLayerImplRecursive(old_layers, children.take(it)); 42 43 CollectExistingLayerImplRecursive(old_layers, layer_impl->TakeMaskLayer()); 44 CollectExistingLayerImplRecursive(old_layers, layer_impl->TakeReplicaLayer()); 45 46 int id = layer_impl->id(); 47 old_layers->set(id, layer_impl.Pass()); 48 } 49 50 template <typename LayerType> 51 scoped_ptr<LayerImpl> SynchronizeTreesInternal( 52 LayerType* layer_root, 53 scoped_ptr<LayerImpl> old_layer_impl_root, 54 LayerTreeImpl* tree_impl) { 55 DCHECK(tree_impl); 56 57 TRACE_EVENT0("cc", "TreeSynchronizer::SynchronizeTrees"); 58 ScopedPtrLayerImplMap old_layers; 59 RawPtrLayerImplMap new_layers; 60 61 CollectExistingLayerImplRecursive(&old_layers, old_layer_impl_root.Pass()); 62 63 scoped_ptr<LayerImpl> new_tree = SynchronizeTreesRecursive( 64 &new_layers, &old_layers, layer_root, tree_impl); 65 66 UpdateScrollbarLayerPointersRecursive(&new_layers, layer_root); 67 68 return new_tree.Pass(); 69 } 70 71 scoped_ptr<LayerImpl> TreeSynchronizer::SynchronizeTrees( 72 Layer* layer_root, 73 scoped_ptr<LayerImpl> old_layer_impl_root, 74 LayerTreeImpl* tree_impl) { 75 return SynchronizeTreesInternal( 76 layer_root, old_layer_impl_root.Pass(), tree_impl); 77 } 78 79 scoped_ptr<LayerImpl> TreeSynchronizer::SynchronizeTrees( 80 LayerImpl* layer_root, 81 scoped_ptr<LayerImpl> old_layer_impl_root, 82 LayerTreeImpl* tree_impl) { 83 return SynchronizeTreesInternal( 84 layer_root, old_layer_impl_root.Pass(), tree_impl); 85 } 86 87 template <typename LayerType> 88 scoped_ptr<LayerImpl> ReuseOrCreateLayerImpl(RawPtrLayerImplMap* new_layers, 89 ScopedPtrLayerImplMap* old_layers, 90 LayerType* layer, 91 LayerTreeImpl* tree_impl) { 92 scoped_ptr<LayerImpl> layer_impl = old_layers->take(layer->id()); 93 94 if (!layer_impl) 95 layer_impl = layer->CreateLayerImpl(tree_impl); 96 97 (*new_layers)[layer->id()] = layer_impl.get(); 98 return layer_impl.Pass(); 99 } 100 101 template <typename LayerType> 102 scoped_ptr<LayerImpl> SynchronizeTreesRecursiveInternal( 103 RawPtrLayerImplMap* new_layers, 104 ScopedPtrLayerImplMap* old_layers, 105 LayerType* layer, 106 LayerTreeImpl* tree_impl) { 107 if (!layer) 108 return scoped_ptr<LayerImpl>(); 109 110 scoped_ptr<LayerImpl> layer_impl = 111 ReuseOrCreateLayerImpl(new_layers, old_layers, layer, tree_impl); 112 113 layer_impl->ClearChildList(); 114 for (size_t i = 0; i < layer->children().size(); ++i) { 115 layer_impl->AddChild(SynchronizeTreesRecursiveInternal( 116 new_layers, old_layers, layer->child_at(i), tree_impl)); 117 } 118 119 layer_impl->SetMaskLayer(SynchronizeTreesRecursiveInternal( 120 new_layers, old_layers, layer->mask_layer(), tree_impl)); 121 layer_impl->SetReplicaLayer(SynchronizeTreesRecursiveInternal( 122 new_layers, old_layers, layer->replica_layer(), tree_impl)); 123 124 return layer_impl.Pass(); 125 } 126 127 scoped_ptr<LayerImpl> SynchronizeTreesRecursive( 128 RawPtrLayerImplMap* new_layers, 129 ScopedPtrLayerImplMap* old_layers, 130 Layer* layer, 131 LayerTreeImpl* tree_impl) { 132 return SynchronizeTreesRecursiveInternal( 133 new_layers, old_layers, layer, tree_impl); 134 } 135 136 scoped_ptr<LayerImpl> SynchronizeTreesRecursive( 137 RawPtrLayerImplMap* new_layers, 138 ScopedPtrLayerImplMap* old_layers, 139 LayerImpl* layer, 140 LayerTreeImpl* tree_impl) { 141 return SynchronizeTreesRecursiveInternal( 142 new_layers, old_layers, layer, tree_impl); 143 } 144 145 template <typename LayerType, typename ScrollbarLayerType> 146 void UpdateScrollbarLayerPointersRecursiveInternal( 147 const RawPtrLayerImplMap* new_layers, 148 LayerType* layer) { 149 if (!layer) 150 return; 151 152 for (size_t i = 0; i < layer->children().size(); ++i) { 153 UpdateScrollbarLayerPointersRecursiveInternal< 154 LayerType, ScrollbarLayerType>(new_layers, layer->child_at(i)); 155 } 156 157 ScrollbarLayerType* scrollbar_layer = layer->ToScrollbarLayer(); 158 if (!scrollbar_layer) 159 return; 160 161 RawPtrLayerImplMap::const_iterator iter = 162 new_layers->find(layer->id()); 163 ScrollbarLayerImplBase* scrollbar_layer_impl = 164 iter != new_layers->end() 165 ? static_cast<ScrollbarLayerImplBase*>(iter->second) 166 : NULL; 167 DCHECK(scrollbar_layer_impl); 168 169 scrollbar_layer->PushScrollClipPropertiesTo(scrollbar_layer_impl); 170 } 171 172 void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers, 173 Layer* layer) { 174 UpdateScrollbarLayerPointersRecursiveInternal<Layer, ScrollbarLayerInterface>( 175 new_layers, layer); 176 } 177 178 void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers, 179 LayerImpl* layer) { 180 UpdateScrollbarLayerPointersRecursiveInternal< 181 LayerImpl, 182 ScrollbarLayerImplBase>(new_layers, layer); 183 } 184 185 // static 186 template <typename LayerType> 187 void TreeSynchronizer::PushPropertiesInternal( 188 LayerType* layer, 189 LayerImpl* layer_impl, 190 size_t* num_dependents_need_push_properties_for_parent) { 191 if (!layer) { 192 DCHECK(!layer_impl); 193 return; 194 } 195 196 DCHECK_EQ(layer->id(), layer_impl->id()); 197 198 bool push_layer = layer->needs_push_properties(); 199 bool recurse_on_children_and_dependents = 200 layer->descendant_needs_push_properties(); 201 202 if (push_layer) 203 layer->PushPropertiesTo(layer_impl); 204 else if (layer->ToScrollbarLayer()) 205 layer->ToScrollbarLayer()->PushScrollClipPropertiesTo(layer_impl); 206 207 size_t num_dependents_need_push_properties = 0; 208 if (recurse_on_children_and_dependents) { 209 PushPropertiesInternal(layer->mask_layer(), 210 layer_impl->mask_layer(), 211 &num_dependents_need_push_properties); 212 PushPropertiesInternal(layer->replica_layer(), 213 layer_impl->replica_layer(), 214 &num_dependents_need_push_properties); 215 216 const OwnedLayerImplList& impl_children = layer_impl->children(); 217 DCHECK_EQ(layer->children().size(), impl_children.size()); 218 219 for (size_t i = 0; i < layer->children().size(); ++i) { 220 PushPropertiesInternal(layer->child_at(i), 221 impl_children[i], 222 &num_dependents_need_push_properties); 223 } 224 225 // When PushPropertiesTo completes for a layer, it may still keep 226 // its needs_push_properties() state if the layer must push itself 227 // every PushProperties tree walk. Here we keep track of those layers, and 228 // ensure that their ancestors know about them for the next PushProperties 229 // tree walk. 230 layer->num_dependents_need_push_properties_ = 231 num_dependents_need_push_properties; 232 } 233 234 bool add_self_to_parent = num_dependents_need_push_properties > 0 || 235 layer->needs_push_properties(); 236 *num_dependents_need_push_properties_for_parent += add_self_to_parent ? 1 : 0; 237 } 238 239 static void CheckScrollAndClipPointersRecursive(Layer* layer, 240 LayerImpl* layer_impl) { 241 DCHECK_EQ(!!layer, !!layer_impl); 242 if (!layer) 243 return; 244 245 // Having a scroll parent on the impl thread implies having one the main 246 // thread, too. The main thread may have a scroll parent that is not in the 247 // tree because it's been removed but not deleted. In this case, the layer 248 // impl will have no scroll parent. Same argument applies for clip parents and 249 // scroll/clip children. 250 DCHECK(!layer_impl->scroll_parent() || !!layer->scroll_parent()); 251 DCHECK(!layer_impl->clip_parent() || !!layer->clip_parent()); 252 DCHECK(!layer_impl->scroll_children() || !!layer->scroll_children()); 253 DCHECK(!layer_impl->clip_children() || !!layer->clip_children()); 254 255 if (layer_impl->scroll_parent()) 256 DCHECK_EQ(layer->scroll_parent()->id(), layer_impl->scroll_parent()->id()); 257 258 if (layer_impl->clip_parent()) 259 DCHECK_EQ(layer->clip_parent()->id(), layer_impl->clip_parent()->id()); 260 261 if (layer_impl->scroll_children()) { 262 for (std::set<Layer*>::iterator it = layer->scroll_children()->begin(); 263 it != layer->scroll_children()->end(); 264 ++it) { 265 DCHECK_EQ((*it)->scroll_parent(), layer); 266 } 267 for (std::set<LayerImpl*>::iterator it = 268 layer_impl->scroll_children()->begin(); 269 it != layer_impl->scroll_children()->end(); 270 ++it) { 271 DCHECK_EQ((*it)->scroll_parent(), layer_impl); 272 } 273 } 274 275 if (layer_impl->clip_children()) { 276 for (std::set<Layer*>::iterator it = layer->clip_children()->begin(); 277 it != layer->clip_children()->end(); 278 ++it) { 279 DCHECK_EQ((*it)->clip_parent(), layer); 280 } 281 for (std::set<LayerImpl*>::iterator it = 282 layer_impl->clip_children()->begin(); 283 it != layer_impl->clip_children()->end(); 284 ++it) { 285 DCHECK_EQ((*it)->clip_parent(), layer_impl); 286 } 287 } 288 289 for (size_t i = 0u; i < layer->children().size(); ++i) { 290 CheckScrollAndClipPointersRecursive(layer->child_at(i), 291 layer_impl->child_at(i)); 292 } 293 } 294 295 void TreeSynchronizer::PushProperties(Layer* layer, 296 LayerImpl* layer_impl) { 297 size_t num_dependents_need_push_properties = 0; 298 PushPropertiesInternal( 299 layer, layer_impl, &num_dependents_need_push_properties); 300 #if DCHECK_IS_ON 301 CheckScrollAndClipPointersRecursive(layer, layer_impl); 302 #endif 303 } 304 305 void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) { 306 size_t num_dependents_need_push_properties = 0; 307 PushPropertiesInternal( 308 layer, layer_impl, &num_dependents_need_push_properties); 309 } 310 311 } // namespace cc 312