summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorvollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-22 15:49:36 +0000
committervollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-22 15:49:36 +0000
commit167c71249ca6de270b3dba75ca94f5de2deb3ea4 (patch)
treef18410fa594d656f881902ffbbdb1b9df08f5672 /cc
parent1d0bd6b4e8fa4df302f106db41e597ae2df8bb56 (diff)
downloadchromium_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.h2
-rw-r--r--cc/layers/layer.cc122
-rw-r--r--cc/layers/layer.h42
-rw-r--r--cc/layers/layer_impl.cc118
-rw-r--r--cc/layers/layer_impl.h45
-rw-r--r--cc/trees/tree_synchronizer_unittest.cc213
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(&copy_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