Fix stale compositor references from ui::Layer
This is needed to fix some issues in tests exposed by the WebKit compositor. The
problem is that sometimes during the teardown paths, some layers have stale a
pointer to the compositor that has already been destroyed. The WebKit layer
(rightfully) calls ScheduleDraw when the layer hierarchy is changed, exposing
the issue.
We now always walk back to the root layer to find the compositor, and reset the
pointer when the compositor's root changes (or it gets destroyed).
BUG=99524
TEST=views_unittest, aura_unittest, compositor_unittests with (and without) use_webkit_compositor=1
Review URL: http://codereview.chromium.org/8510076
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110223 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index d1caa04..0e8518d6 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -71,7 +71,7 @@
}
void Window::Init(ui::Layer::LayerType layer_type) {
- layer_.reset(new ui::Layer(Desktop::GetInstance()->compositor(), layer_type));
+ layer_.reset(new ui::Layer(layer_type));
layer_->SetVisible(false);
layer_->set_delegate(this);
}
diff --git a/ui/gfx/compositor/compositor.cc b/ui/gfx/compositor/compositor.cc
index 6e9e1d5..485dc2d 100644
--- a/ui/gfx/compositor/compositor.cc
+++ b/ui/gfx/compositor/compositor.cc
@@ -26,6 +26,8 @@
}
Compositor::~Compositor() {
+ if (root_layer_)
+ root_layer_->SetCompositor(NULL);
}
void Compositor::ScheduleDraw() {
@@ -33,8 +35,10 @@
}
void Compositor::SetRootLayer(Layer* root_layer) {
+ if (root_layer_)
+ root_layer_->SetCompositor(NULL);
root_layer_ = root_layer;
- if (!root_layer_->GetCompositor())
+ if (root_layer_ && !root_layer_->GetCompositor())
root_layer_->SetCompositor(this);
OnRootLayerChanged();
}
diff --git a/ui/gfx/compositor/compositor.h b/ui/gfx/compositor/compositor.h
index 33a7bce..23fff5b 100644
--- a/ui/gfx/compositor/compositor.h
+++ b/ui/gfx/compositor/compositor.h
@@ -122,7 +122,10 @@
// Schedules a redraw of the layer tree associated with this compositor.
virtual void ScheduleDraw();
- // Sets the root of the layer tree drawn by this Compositor.
+ // Sets the root of the layer tree drawn by this Compositor. The root layer
+ // must have no parent. The compositor's root layer is reset if the root layer
+ // is destroyed. NULL can be passed to reset the root layer, in which case the
+ // compositor will stop drawing anything.
// The Compositor does not own the root layer.
const Layer* root_layer() const { return root_layer_; }
Layer* root_layer() { return root_layer_; }
diff --git a/ui/gfx/compositor/compositor_cc.cc b/ui/gfx/compositor/compositor_cc.cc
index 0d8b4fc4..ce75713 100644
--- a/ui/gfx/compositor/compositor_cc.cc
+++ b/ui/gfx/compositor/compositor_cc.cc
@@ -174,7 +174,8 @@
void CompositorCC::OnRootLayerChanged() {
root_web_layer_.removeAllChildren();
- root_web_layer_.addChild(root_layer()->web_layer());
+ if (root_layer())
+ root_web_layer_.addChild(root_layer()->web_layer());
}
void CompositorCC::DrawTree() {
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc
index fd7b862..2e3b9be 100644
--- a/ui/gfx/compositor/layer.cc
+++ b/ui/gfx/compositor/layer.cc
@@ -32,13 +32,17 @@
return remainder < EPSILON || base - remainder < EPSILON;
}
+const ui::Layer* GetRoot(const ui::Layer* layer) {
+ return layer->parent() ? GetRoot(layer->parent()) : layer;
+}
+
} // namespace
namespace ui {
-Layer::Layer(Compositor* compositor)
+Layer::Layer()
: type_(LAYER_HAS_TEXTURE),
- compositor_(compositor),
+ compositor_(NULL),
parent_(NULL),
visible_(true),
fills_bounds_opaquely_(true),
@@ -51,9 +55,9 @@
#endif
}
-Layer::Layer(Compositor* compositor, LayerType type)
+Layer::Layer(LayerType type)
: type_(type),
- compositor_(compositor),
+ compositor_(NULL),
parent_(NULL),
visible_(true),
fills_bounds_opaquely_(true),
@@ -67,6 +71,8 @@
}
Layer::~Layer() {
+ if (compositor_)
+ compositor_->SetRootLayer(NULL);
if (parent_)
parent_->Remove(this);
for (size_t i = 0; i < children_.size(); ++i)
@@ -77,19 +83,20 @@
}
Compositor* Layer::GetCompositor() {
- return compositor_ ? compositor_ : parent_ ? parent_->GetCompositor() : NULL;
+ return GetRoot(this)->compositor_;
}
void Layer::SetCompositor(Compositor* compositor) {
- // This function must only be called once, with a valid compositor, and only
- // for the compositor's root layer.
- DCHECK(!compositor_);
- DCHECK(compositor);
- DCHECK_EQ(compositor->root_layer(), this);
+ // This function must only be called to set the compositor on the root layer,
+ // or to reset it.
+ DCHECK(!compositor || !compositor_);
+ DCHECK(!compositor || compositor->root_layer() == this);
+ DCHECK(!parent_);
compositor_ = compositor;
}
void Layer::Add(Layer* child) {
+ DCHECK(!child->compositor_);
if (child->parent_)
child->parent_->Remove(child);
child->parent_ = this;
@@ -235,8 +242,8 @@
if (source == target)
return;
- const Layer* root_layer = source->compositor()->root_layer();
- CHECK_EQ(root_layer, target->compositor()->root_layer());
+ const Layer* root_layer = GetRoot(source);
+ CHECK_EQ(root_layer, GetRoot(target));
if (source != root_layer)
source->ConvertPointForAncestor(root_layer, point);
diff --git a/ui/gfx/compositor/layer.h b/ui/gfx/compositor/layer.h
index d8cb66c..76fef3e 100644
--- a/ui/gfx/compositor/layer.h
+++ b/ui/gfx/compositor/layer.h
@@ -48,10 +48,8 @@
LAYER_HAS_TEXTURE = 1
};
- // |compositor| can be NULL, and will be set later when the Layer is added to
- // a Compositor.
- explicit Layer(Compositor* compositor);
- Layer(Compositor* compositor, LayerType type);
+ Layer();
+ explicit Layer(LayerType type);
virtual ~Layer();
// Retrieves the Layer's compositor. The Layer will walk up its parent chain
@@ -152,10 +150,6 @@
const gfx::Rect& hole_rect() const { return hole_rect_; }
- // The compositor.
- const Compositor* compositor() const { return compositor_; }
- Compositor* compositor() { return compositor_; }
-
const ui::Texture* texture() const { return texture_.get(); }
// |texture| cannot be NULL, and this function cannot be called more than
diff --git a/ui/gfx/compositor/layer_unittest.cc b/ui/gfx/compositor/layer_unittest.cc
index e6b04f3..3ed24514 100644
--- a/ui/gfx/compositor/layer_unittest.cc
+++ b/ui/gfx/compositor/layer_unittest.cc
@@ -34,8 +34,8 @@
class ColoredLayer : public Layer, public LayerDelegate {
public:
- ColoredLayer(Compositor* compositor, SkColor color)
- : Layer(compositor, Layer::LAYER_HAS_TEXTURE),
+ explicit ColoredLayer(SkColor color)
+ : Layer(Layer::LAYER_HAS_TEXTURE),
color_(color) {
set_delegate(this);
}
@@ -71,11 +71,11 @@
}
Layer* CreateLayer(Layer::LayerType type) {
- return new Layer(GetCompositor(), type);
+ return new Layer(type);
}
Layer* CreateColorLayer(SkColor color, const gfx::Rect& bounds) {
- Layer* layer = new ColoredLayer(GetCompositor(), color);
+ Layer* layer = new ColoredLayer(color);
layer->SetBounds(bounds);
return layer;
}
@@ -203,6 +203,7 @@
#define MAYBE_Hierarchy DISABLED_Hierarchy
#define MAYBE_HierarchyNoTexture DISABLED_HierarchyNoTexture
#define MAYBE_DrawPixels DISABLED_DrawPixels
+#define MAYBE_SetRootLayer DISABLED_SetRootLayer
#else
#define MAYBE_Delegate Delegate
#define MAYBE_Draw Draw
@@ -210,6 +211,7 @@
#define MAYBE_Hierarchy Hierarchy
#define MAYBE_HierarchyNoTexture HierarchyNoTexture
#define MAYBE_DrawPixels DrawPixels
+#define MAYBE_SetRootLayer SetRootLayer
#endif
TEST_F(LayerWithRealCompositorTest, MAYBE_Draw) {
@@ -257,11 +259,11 @@
Compositor* compositor() { return compositor_.get(); }
virtual Layer* CreateLayer(Layer::LayerType type) {
- return new Layer(compositor(), type);
+ return new Layer(type);
}
Layer* CreateColorLayer(SkColor color, const gfx::Rect& bounds) {
- Layer* layer = new ColoredLayer(compositor(), color);
+ Layer* layer = new ColoredLayer(color);
layer->SetBounds(bounds);
return layer;
}
@@ -461,7 +463,7 @@
}
Layer* CreateLayer(Layer::LayerType type) OVERRIDE {
- Layer* layer = new Layer(compositor(), type);
+ Layer* layer = new Layer(type);
layer->set_delegate(default_layer_delegate_.get());
return layer;
}
@@ -888,9 +890,9 @@
// Various visibile/drawn assertions.
TEST_F(LayerWithNullDelegateTest, Visibility) {
- scoped_ptr<Layer> l1(new Layer(NULL, Layer::LAYER_HAS_TEXTURE));
- scoped_ptr<Layer> l2(new Layer(NULL, Layer::LAYER_HAS_TEXTURE));
- scoped_ptr<Layer> l3(new Layer(NULL, Layer::LAYER_HAS_TEXTURE));
+ scoped_ptr<Layer> l1(new Layer(Layer::LAYER_HAS_TEXTURE));
+ scoped_ptr<Layer> l2(new Layer(Layer::LAYER_HAS_TEXTURE));
+ scoped_ptr<Layer> l3(new Layer(Layer::LAYER_HAS_TEXTURE));
l1->Add(l2.get());
l2->Add(l3.get());
@@ -999,4 +1001,30 @@
EXPECT_TRUE(is_all_red);
}
+// Checks the logic around Compositor::SetRootLayer and Layer::SetCompositor.
+TEST_F(LayerWithRealCompositorTest, MAYBE_SetRootLayer) {
+ Compositor* compositor = GetCompositor();
+ Layer l1;
+ EXPECT_EQ(NULL, l1.GetCompositor());
+
+ Layer l2;
+ EXPECT_EQ(NULL, l2.GetCompositor());
+
+ compositor->SetRootLayer(&l1);
+ EXPECT_EQ(compositor, l1.GetCompositor());
+
+ l1.Add(&l2);
+ EXPECT_EQ(compositor, l2.GetCompositor());
+
+ l1.Remove(&l2);
+ EXPECT_EQ(NULL, l2.GetCompositor());
+
+ l1.Add(&l2);
+ EXPECT_EQ(compositor, l2.GetCompositor());
+
+ compositor->SetRootLayer(NULL);
+ EXPECT_EQ(NULL, l1.GetCompositor());
+ EXPECT_EQ(NULL, l2.GetCompositor());
+}
+
} // namespace ui
diff --git a/views/view.cc b/views/view.cc
index 9d5e3038..1240f4a 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -1779,7 +1779,7 @@
for (int i = 0, count = child_count(); i < count; ++i)
child_at(i)->UpdateChildLayerVisibility(true);
- layer_.reset(new ui::Layer(NULL));
+ layer_.reset(new ui::Layer());
layer_->set_delegate(this);
UpdateParentLayers();
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
index c4a5256..f4c8068 100644
--- a/views/view_unittest.cc
+++ b/views/view_unittest.cc
@@ -2565,7 +2565,7 @@
EXPECT_EQ(0u, layer->children().size());
EXPECT_FALSE(layer->transform().HasChange());
EXPECT_EQ(widget()->GetRootView()->bounds(), layer->bounds());
- EXPECT_TRUE(layer->compositor() != NULL);
+ EXPECT_TRUE(layer->GetCompositor() != NULL);
}
// Verifies that the complete bounds of a texture are updated if the texture
diff --git a/views/widget/native_widget_aura.cc b/views/widget/native_widget_aura.cc
index 4ff026ef..ee23f42 100644
--- a/views/widget/native_widget_aura.cc
+++ b/views/widget/native_widget_aura.cc
@@ -201,11 +201,11 @@
}
const ui::Compositor* NativeWidgetAura::GetCompositor() const {
- return window_->layer()->compositor();
+ return window_->layer()->GetCompositor();
}
ui::Compositor* NativeWidgetAura::GetCompositor() {
- return window_->layer()->compositor();
+ return window_->layer()->GetCompositor();
}
void NativeWidgetAura::CalculateOffsetToAncestorWithLayer(