diff options
author | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-22 15:49:36 +0000 |
---|---|---|
committer | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-22 15:49:36 +0000 |
commit | 167c71249ca6de270b3dba75ca94f5de2deb3ea4 (patch) | |
tree | f18410fa594d656f881902ffbbdb1b9df08f5672 /cc | |
parent | 1d0bd6b4e8fa4df302f106db41e597ae2df8bb56 (diff) | |
download | chromium_src-167c71249ca6de270b3dba75ca94f5de2deb3ea4.zip chromium_src-167c71249ca6de270b3dba75ca94f5de2deb3ea4.tar.gz chromium_src-167c71249ca6de270b3dba75ca94f5de2deb3ea4.tar.bz2 |
Add plumbing for scroll parent.
Plumbs the scroll parent information into the cc layer trees. These relationships are not yet used. (That task is accomplished here https://codereview.chromium.org/18191009/).
R=shawnsingh@chromium.org
BUG=254435
Review URL: https://chromiumcodereview.appspot.com/18133004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219026 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/layers/compositing_reasons.h | 2 | ||||
-rw-r--r-- | cc/layers/layer.cc | 122 | ||||
-rw-r--r-- | cc/layers/layer.h | 42 | ||||
-rw-r--r-- | cc/layers/layer_impl.cc | 118 | ||||
-rw-r--r-- | cc/layers/layer_impl.h | 45 | ||||
-rw-r--r-- | cc/trees/tree_synchronizer_unittest.cc | 213 |
6 files changed, 542 insertions, 0 deletions
diff --git a/cc/layers/compositing_reasons.h b/cc/layers/compositing_reasons.h index 28c2f7b..4c9f633 100644 --- a/cc/layers/compositing_reasons.h +++ b/cc/layers/compositing_reasons.h @@ -52,6 +52,8 @@ const uint64 kCompositingReasonLayerForScrollingContainer = const uint64 kCompositingReasonLayerForForeground = GG_UINT64_C(1) << 29; const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30; const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31; +const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32; +const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33; typedef uint64 CompositingReasons; diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 62d903e..b513563 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc @@ -56,6 +56,8 @@ Layer::Layer() use_parent_backface_visibility_(false), draw_checkerboard_for_missing_tiles_(false), force_render_surface_(false), + scroll_parent_(NULL), + clip_parent_(NULL), replica_layer_(NULL), raster_scale_(0.f), client_(NULL) { @@ -88,6 +90,9 @@ Layer::~Layer() { DCHECK_EQ(this, replica_layer_->parent()); replica_layer_->RemoveFromParent(); } + + RemoveFromScrollTree(); + RemoveFromClipTree(); } void Layer::SetLayerTreeHost(LayerTreeHost* host) { @@ -566,6 +571,66 @@ bool Layer::TransformIsAnimating() const { return layer_animation_controller_->IsAnimatingProperty(Animation::Transform); } +void Layer::SetScrollParent(Layer* parent) { + DCHECK(IsPropertyChangeAllowed()); + if (scroll_parent_ == parent) + return; + + if (scroll_parent_) + scroll_parent_->RemoveScrollChild(this); + + scroll_parent_ = parent; + + if (scroll_parent_) + scroll_parent_->AddScrollChild(this); + + SetNeedsCommit(); +} + +void Layer::AddScrollChild(Layer* child) { + if (!scroll_children_) + scroll_children_.reset(new std::set<Layer*>); + scroll_children_->insert(child); + SetNeedsCommit(); +} + +void Layer::RemoveScrollChild(Layer* child) { + scroll_children_->erase(child); + if (scroll_children_->empty()) + scroll_children_.reset(); + SetNeedsCommit(); +} + +void Layer::SetClipParent(Layer* ancestor) { + DCHECK(IsPropertyChangeAllowed()); + if (clip_parent_ == ancestor) + return; + + if (clip_parent_) + clip_parent_->RemoveClipChild(this); + + clip_parent_ = ancestor; + + if (clip_parent_) + clip_parent_->AddClipChild(this); + + SetNeedsCommit(); +} + +void Layer::AddClipChild(Layer* child) { + if (!clip_children_) + clip_children_.reset(new std::set<Layer*>); + clip_children_->insert(child); + SetNeedsCommit(); +} + +void Layer::RemoveClipChild(Layer* child) { + clip_children_->erase(child); + if (clip_children_->empty()) + clip_children_.reset(); + SetNeedsCommit(); +} + void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) { DCHECK(IsPropertyChangeAllowed()); if (scroll_offset_ == scroll_offset) @@ -794,6 +859,37 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetScrollOffset(scroll_offset_); layer->SetMaxScrollOffset(max_scroll_offset_); + LayerImpl* scroll_parent = NULL; + if (scroll_parent_) + scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id()); + + layer->SetScrollParent(scroll_parent); + if (scroll_children_) { + std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>; + for (std::set<Layer*>::iterator it = scroll_children_->begin(); + it != scroll_children_->end(); ++it) + scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id())); + layer->SetScrollChildren(scroll_children); + } + + LayerImpl* clip_parent = NULL; + if (clip_parent_) { + clip_parent = + layer->layer_tree_impl()->LayerById(clip_parent_->id()); + } + + layer->SetClipParent(clip_parent); + if (clip_children_) { + std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>; + for (std::set<Layer*>::iterator it = clip_children_->begin(); + it != clip_children_->end(); ++it) { + LayerImpl* clip_child = layer->layer_tree_impl()->LayerById((*it)->id()); + DCHECK(clip_child); + clip_children->insert(clip_child); + } + layer->SetClipChildren(clip_children); + } + // Wrap the copy_requests_ in a PostTask to the main thread. ScopedPtrVector<CopyOutputRequest> main_thread_copy_requests; for (ScopedPtrVector<CopyOutputRequest>::iterator it = copy_requests_.begin(); @@ -985,4 +1081,30 @@ bool Layer::SupportsLCDText() const { return false; } +void Layer::RemoveFromScrollTree() { + if (scroll_children_.get()) { + for (std::set<Layer*>::iterator it = scroll_children_->begin(); + it != scroll_children_->end(); ++it) + (*it)->scroll_parent_ = NULL; + } + + if (scroll_parent_) + scroll_parent_->RemoveScrollChild(this); + + scroll_parent_ = NULL; +} + +void Layer::RemoveFromClipTree() { + if (clip_children_.get()) { + for (std::set<Layer*>::iterator it = clip_children_->begin(); + it != clip_children_->end(); ++it) + (*it)->clip_parent_ = NULL; + } + + if (clip_parent_) + clip_parent_->RemoveClipChild(this); + + clip_parent_ = NULL; +} + } // namespace cc diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 868777c..5349900 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h @@ -5,6 +5,7 @@ #ifndef CC_LAYERS_LAYER_H_ #define CC_LAYERS_LAYER_H_ +#include <set> #include <string> #include "base/callback.h" @@ -157,6 +158,34 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, const gfx::Transform& transform() const { return transform_; } bool TransformIsAnimating() const; + void SetScrollParent(Layer* parent); + + Layer* scroll_parent() { return scroll_parent_; } + const Layer* scroll_parent() const { return scroll_parent_; } + + void AddScrollChild(Layer* child); + void RemoveScrollChild(Layer* child); + + std::set<Layer*>* scroll_children() { return scroll_children_.get(); } + const std::set<Layer*>* scroll_children() const { + return scroll_children_.get(); + } + + void SetClipParent(Layer* ancestor); + + Layer* clip_parent() { return clip_parent_; } + const Layer* clip_parent() const { + return clip_parent_; + } + + void AddClipChild(Layer* child); + void RemoveClipChild(Layer* child); + + std::set<Layer*>* clip_children() { return clip_children_.get(); } + const std::set<Layer*>* clip_children() const { + return clip_children_.get(); + } + DrawProperties<Layer, RenderSurface>& draw_properties() { return draw_properties_; } @@ -431,6 +460,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, return needs_push_properties() || descendant_needs_push_properties(); } + // If this layer has a scroll parent, it removes |this| from its list of + // scroll children. + void RemoveFromScrollTree(); + + // If this layer has a clip parent, it removes |this| from its list of clip + // children. + void RemoveFromClipTree(); + void reset_raster_scale_to_unknown() { raster_scale_ = 0.f; } // This flag is set when the layer needs to push properties to the impl @@ -519,6 +556,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, bool use_parent_backface_visibility_; bool draw_checkerboard_for_missing_tiles_; bool force_render_surface_; + Layer* scroll_parent_; + scoped_ptr<std::set<Layer*> > scroll_children_; + + Layer* clip_parent_; + scoped_ptr<std::set<Layer*> > clip_children_; gfx::Transform transform_; gfx::Transform sublayer_transform_; diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 0267d9f..faf5bad 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc @@ -29,6 +29,8 @@ namespace cc { LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id) : parent_(NULL), + scroll_parent_(NULL), + clip_parent_(NULL), mask_layer_id_(-1), replica_layer_id_(-1), layer_id_(id), @@ -73,6 +75,24 @@ LayerImpl::~LayerImpl() { layer_tree_impl_->UnregisterLayer(this); layer_animation_controller_->RemoveValueObserver(this); + + if (scroll_children_) { + for (std::set<LayerImpl*>::iterator it = scroll_children_->begin(); + it != scroll_children_->end(); ++it) + (*it)->scroll_parent_ = NULL; + } + + if (scroll_parent_) + scroll_parent_->RemoveScrollChild(this); + + if (clip_children_) { + for (std::set<LayerImpl*>::iterator it = clip_children_->begin(); + it != clip_children_->end(); ++it) + (*it)->clip_parent_ = NULL; + } + + if (clip_parent_) + clip_parent_->RemoveClipChild(this); } void LayerImpl::AddChild(scoped_ptr<LayerImpl> child) { @@ -104,6 +124,64 @@ void LayerImpl::ClearChildList() { layer_tree_impl()->set_needs_update_draw_properties(); } +bool LayerImpl::HasAncestor(const LayerImpl* ancestor) const { + if (!ancestor) + return false; + + for (const LayerImpl* layer = this; layer; layer = layer->parent()) { + if (layer == ancestor) + return true; + } + + return false; +} + +void LayerImpl::SetScrollParent(LayerImpl* parent) { + if (scroll_parent_ == parent) + return; + + if (scroll_parent_) + scroll_parent_->RemoveScrollChild(this); + + scroll_parent_ = parent; +} + +void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) { + if (scroll_children_.get() == children) + return; + scroll_children_.reset(children); +} + +void LayerImpl::RemoveScrollChild(LayerImpl* child) { + DCHECK(scroll_children_); + scroll_children_->erase(child); + if (scroll_children_->empty()) + scroll_children_.reset(); +} + +void LayerImpl::SetClipParent(LayerImpl* ancestor) { + if (clip_parent_ == ancestor) + return; + + if (clip_parent_) + clip_parent_->RemoveClipChild(this); + + clip_parent_ = ancestor; +} + +void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) { + if (clip_children_.get() == children) + return; + clip_children_.reset(children); +} + +void LayerImpl::RemoveClipChild(LayerImpl* child) { + DCHECK(clip_children_); + clip_children_->erase(child); + if (clip_children_->empty()) + clip_children_.reset(); +} + void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) { if (requests->empty()) return; @@ -441,6 +519,34 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetScrollOffset(scroll_offset_); layer->SetMaxScrollOffset(max_scroll_offset_); + LayerImpl* scroll_parent = NULL; + if (scroll_parent_) + scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id()); + + layer->SetScrollParent(scroll_parent); + if (scroll_children_) { + std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>; + for (std::set<LayerImpl*>::iterator it = scroll_children_->begin(); + it != scroll_children_->end(); ++it) + scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id())); + layer->SetScrollChildren(scroll_children); + } + + LayerImpl* clip_parent = NULL; + if (clip_parent_) { + clip_parent = layer->layer_tree_impl()->LayerById( + clip_parent_->id()); + } + + layer->SetClipParent(clip_parent); + if (clip_children_) { + std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>; + for (std::set<LayerImpl*>::iterator it = clip_children_->begin(); + it != clip_children_->end(); ++it) + clip_children->insert(layer->layer_tree_impl()->LayerById((*it)->id())); + layer->SetClipChildren(clip_children); + } + layer->PassCopyRequests(©_requests_); // If the main thread commits multiple times before the impl thread actually @@ -1128,6 +1234,12 @@ CompositingReasonsAsValue(CompositingReasons reasons) { if (reasons & kCompositingReasonLayerForMask) reason_list->AppendString("Is a mask layer"); + if (reasons & kCompositingReasonOverflowScrollingParent) + reason_list->AppendString("Scroll parent is not an ancestor"); + + if (reasons & kCompositingReasonOutOfFlowClipping) + reason_list->AppendString("Has clipping ancestor"); + return reason_list.PassAs<base::Value>(); } @@ -1157,6 +1269,12 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const { state->Set("mask_layer", mask_layer_->AsValue().release()); if (replica_layer_) state->Set("replica_layer", replica_layer_->AsValue().release()); + + if (scroll_parent_) + state->SetInteger("scroll_parent", scroll_parent_->id()); + + if (clip_parent_) + state->SetInteger("clip_parent", clip_parent_->id()); } size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; } diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 03bd2d0..c18e8a0 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -5,6 +5,7 @@ #ifndef CC_LAYERS_LAYER_IMPL_H_ #define CC_LAYERS_LAYER_IMPL_H_ +#include <set> #include <string> #include "base/logging.h" @@ -83,6 +84,38 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { // Warning: This does not preserve tree structure invariants. void ClearChildList(); + bool HasAncestor(const LayerImpl* ancestor) const; + + void SetScrollParent(LayerImpl* parent); + + LayerImpl* scroll_parent() { return scroll_parent_; } + const LayerImpl* scroll_parent() const { return scroll_parent_; } + + void SetScrollChildren(std::set<LayerImpl*>* children); + void RemoveScrollChild(LayerImpl* child); + + std::set<LayerImpl*>* scroll_children() { return scroll_children_.get(); } + const std::set<LayerImpl*>* scroll_children() const { + return scroll_children_.get(); + } + + void SetClipParent(LayerImpl* ancestor); + + LayerImpl* clip_parent() { + return clip_parent_; + } + const LayerImpl* clip_parent() const { + return clip_parent_; + } + + void SetClipChildren(std::set<LayerImpl*>* children); + void RemoveClipChild(LayerImpl* child); + + std::set<LayerImpl*>* clip_children() { return clip_children_.get(); } + const std::set<LayerImpl*>* clip_children() const { + return clip_children_.get(); + } + void PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests); void TakeCopyRequestsAndTransformToTarget( ScopedPtrVector<CopyOutputRequest>* request); @@ -476,6 +509,18 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver { // Properties internal to LayerImpl LayerImpl* parent_; OwnedLayerImplList children_; + + LayerImpl* scroll_parent_; + + // Storing a pointer to a set rather than a set since this will be rarely + // used. If this pointer turns out to be too heavy, we could have this (and + // the scroll parent above) be stored in a LayerImpl -> scroll_info + // map somewhere. + scoped_ptr<std::set<LayerImpl*> > scroll_children_; + + LayerImpl* clip_parent_; + scoped_ptr<std::set<LayerImpl*> > clip_children_; + // mask_layer_ can be temporarily stolen during tree sync, we need this ID to // confirm newly assigned layer is still the previous one int mask_layer_id_; diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc index f1b6d32..5252c063 100644 --- a/cc/trees/tree_synchronizer_unittest.cc +++ b/cc/trees/tree_synchronizer_unittest.cc @@ -5,6 +5,7 @@ #include "cc/trees/tree_synchronizer.h" #include <algorithm> +#include <set> #include <vector> #include "cc/animation/layer_animation_controller.h" @@ -124,6 +125,56 @@ void ExpectTreesAreIdentical(Layer* layer, ASSERT_EQ(layer_children.size(), layer_impl_children.size()); + const std::set<Layer*>* layer_scroll_children = layer->scroll_children(); + const std::set<LayerImpl*>* layer_impl_scroll_children = + layer_impl->scroll_children(); + + ASSERT_EQ(!!layer_scroll_children, !!layer_impl_scroll_children); + + if (layer_scroll_children) { + ASSERT_EQ( + layer_scroll_children->size(), + layer_impl_scroll_children->size()); + } + + const Layer* layer_scroll_parent = layer->scroll_parent(); + const LayerImpl* layer_impl_scroll_parent = layer_impl->scroll_parent(); + + ASSERT_EQ(!!layer_scroll_parent, !!layer_impl_scroll_parent); + + if (layer_scroll_parent) { + ASSERT_EQ(layer_scroll_parent->id(), layer_impl_scroll_parent->id()); + ASSERT_TRUE(layer_scroll_parent->scroll_children()->find(layer) != + layer_scroll_parent->scroll_children()->end()); + ASSERT_TRUE(layer_impl_scroll_parent->scroll_children()->find(layer_impl) != + layer_impl_scroll_parent->scroll_children()->end()); + } + + const std::set<Layer*>* layer_clip_children = layer->clip_children(); + const std::set<LayerImpl*>* layer_impl_clip_children = + layer_impl->clip_children(); + + ASSERT_EQ(!!layer_clip_children, !!layer_impl_clip_children); + + if (layer_clip_children) + ASSERT_EQ(layer_clip_children->size(), layer_impl_clip_children->size()); + + const Layer* layer_clip_parent = layer->clip_parent(); + const LayerImpl* layer_impl_clip_parent = layer_impl->clip_parent(); + + ASSERT_EQ(!!layer_clip_parent, !!layer_impl_clip_parent); + + if (layer_clip_parent) { + const std::set<LayerImpl*>* clip_children_impl = + layer_impl_clip_parent->clip_children(); + const std::set<Layer*>* clip_children = + layer_clip_parent->clip_children(); + ASSERT_EQ(layer_clip_parent->id(), layer_impl_clip_parent->id()); + ASSERT_TRUE(clip_children->find(layer) != clip_children->end()); + ASSERT_TRUE(clip_children_impl->find(layer_impl) != + clip_children_impl->end()); + } + for (size_t i = 0; i < layer_children.size(); ++i) { ExpectTreesAreIdentical( layer_children[i].get(), layer_impl_children[i], tree_impl); @@ -531,5 +582,167 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { layer_tree_root->layer_animation_controller())->SynchronizedAnimations()); } +TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) { + LayerTreeSettings settings; + FakeProxy proxy; + DebugScopedSetImplThread impl(&proxy); + FakeRenderingStatsInstrumentation stats_instrumentation; + scoped_ptr<LayerTreeHostImpl> host_impl = + LayerTreeHostImpl::Create(settings, + NULL, + &proxy, + &stats_instrumentation); + + scoped_refptr<Layer> layer_tree_root = Layer::Create(); + scoped_refptr<Layer> scroll_parent = Layer::Create(); + layer_tree_root->AddChild(scroll_parent); + layer_tree_root->AddChild(Layer::Create()); + layer_tree_root->AddChild(Layer::Create()); + + host_->SetRootLayer(layer_tree_root); + + // First child is the second and third child's scroll parent. + layer_tree_root->children()[1]->SetScrollParent(scroll_parent); + layer_tree_root->children()[2]->SetScrollParent(scroll_parent); + + scoped_ptr<LayerImpl> layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + scoped_ptr<LayerImpl>(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Remove the first scroll child. + layer_tree_root->children()[1]->RemoveFromParent(); + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Add an additional scroll layer. + scoped_refptr<Layer> additional_scroll_child = Layer::Create(); + layer_tree_root->AddChild(additional_scroll_child); + additional_scroll_child->SetScrollParent(scroll_parent); + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Remove the scroll parent. + scroll_parent->RemoveFromParent(); + scroll_parent = NULL; + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // The scroll children should have been unhooked. + EXPECT_EQ(2u, layer_tree_root->children().size()); + EXPECT_FALSE(layer_tree_root->children()[1]->scroll_parent()); + EXPECT_FALSE(layer_tree_root->children()[2]->scroll_parent()); +} + +TEST_F(TreeSynchronizerTest, SynchronizeClipParent) { + LayerTreeSettings settings; + FakeProxy proxy; + DebugScopedSetImplThread impl(&proxy); + FakeRenderingStatsInstrumentation stats_instrumentation; + scoped_ptr<LayerTreeHostImpl> host_impl = + LayerTreeHostImpl::Create(settings, + NULL, + &proxy, + &stats_instrumentation); + + scoped_refptr<Layer> layer_tree_root = Layer::Create(); + scoped_refptr<Layer> clip_parent = Layer::Create(); + scoped_refptr<Layer> intervening = Layer::Create(); + scoped_refptr<Layer> clip_child1 = Layer::Create(); + scoped_refptr<Layer> clip_child2 = Layer::Create(); + layer_tree_root->AddChild(clip_parent); + clip_parent->AddChild(intervening); + intervening->AddChild(clip_child1); + intervening->AddChild(clip_child2); + + host_->SetRootLayer(layer_tree_root); + + // First child is the second and third child's scroll parent. + clip_child1->SetClipParent(clip_parent); + clip_child2->SetClipParent(clip_parent); + + scoped_ptr<LayerImpl> layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + scoped_ptr<LayerImpl>(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Remove the first clip child. + clip_child1->RemoveFromParent(); + clip_child1 = NULL; + + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Add an additional clip child. + scoped_refptr<Layer> additional_clip_child = Layer::Create(); + intervening->AddChild(additional_clip_child); + additional_clip_child->SetClipParent(clip_parent); + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // Remove the nearest clipping ancestor. + clip_parent->RemoveFromParent(); + clip_parent = NULL; + layer_impl_tree_root = + TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(), + layer_impl_tree_root.Pass(), + host_impl->active_tree()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), + layer_impl_tree_root.get()); + ExpectTreesAreIdentical(layer_tree_root.get(), + layer_impl_tree_root.get(), + host_impl->active_tree()); + + // The clip children should have been unhooked. + EXPECT_EQ(2u, intervening->children().size()); + EXPECT_FALSE(clip_child2->clip_parent()); + EXPECT_FALSE(additional_clip_child->clip_parent()); +} + } // namespace } // namespace cc |