Bug 1328702: ContainerLayer::RemoveAllChildren implementation. r=kats,mattwoodrow
authorMilan Sreckovic <milan@mozilla.com>
Thu, 05 Jan 2017 13:41:10 -0500
changeset 328809 ea6db01a7f77f1cc903ef376f9d198218f312670
parent 328808 c0f94e1d6f111be24267f5d0e2ee5b09c31aa231
child 328810 7c54af30e12bdb70a36fdd811e447b0c2f675b79
push id85546
push userkwierso@gmail.com
push dateWed, 11 Jan 2017 02:36:30 +0000
treeherdermozilla-inbound@c5bce4cd684a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, mattwoodrow
bugs1328702
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1328702: ContainerLayer::RemoveAllChildren implementation. r=kats,mattwoodrow MozReview-Commit-ID: 6zC3v8dQcWD
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/client/ClientContainerLayer.h
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1177,16 +1177,53 @@ ContainerLayer::InsertAfter(Layer* aChil
     next->SetPrevSibling(aChild);
   }
   aAfter->SetNextSibling(aChild);
   NS_ADDREF(aChild);
   DidInsertChild(aChild);
   return true;
 }
 
+void
+ContainerLayer::RemoveAllChildren()
+{
+  // Optimizes "while (mFirstChild) ContainerLayer::RemoveChild(mFirstChild);"
+  Layer* current = mFirstChild;
+
+  // This is inlining DidRemoveChild() on each layer; we can skip the calls
+  // to NotifyPaintedLayerRemoved as it gets taken care of when as we call
+  // NotifyRemoved prior to removing any layers.
+  while (current) {
+    Layer* next = current->GetNextSibling();
+    if (current->GetType() == TYPE_READBACK) {
+      static_cast<ReadbackLayer*>(current)->NotifyRemoved();
+    }
+    current = next;
+  }
+
+  current = mFirstChild;
+  mFirstChild = nullptr;
+  while (current) {
+    MOZ_ASSERT(!current->GetPrevSibling());
+
+    Layer* next = current->GetNextSibling();
+    current->SetParent(nullptr);
+    current->SetNextSibling(nullptr);
+    if (next) {
+      next->SetPrevSibling(nullptr);
+    }
+    NS_RELEASE(current);
+    current = next;
+  }
+}
+
+// Note that ContainerLayer::RemoveAllChildren is an optimized
+// version of this code; if you make changes to ContainerLayer::RemoveChild
+// consider whether the matching changes need to be made to
+// ContainerLayer::RemoveAllChildren
 bool
 ContainerLayer::RemoveChild(Layer *aChild)
 {
   if (aChild->Manager() != Manager()) {
     NS_ERROR("Child has wrong manager");
     return false;
   }
   if (aChild->GetParent() != this) {
@@ -1620,16 +1657,20 @@ ContainerLayer::HasOpaqueAncestorLayer(L
 {
   for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
     if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
       return true;
   }
   return false;
 }
 
+// Note that ContainerLayer::RemoveAllChildren contains an optimized
+// version of this code; if you make changes to ContainerLayer::DidRemoveChild
+// consider whether the matching changes need to be made to
+// ContainerLayer::RemoveAllChildren
 void
 ContainerLayer::DidRemoveChild(Layer* aLayer)
 {
   PaintedLayer* tl = aLayer->AsPaintedLayer();
   if (tl && tl->UsedForReadback()) {
     for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
       if (l->GetType() == TYPE_READBACK) {
         static_cast<ReadbackLayer*>(l)->NotifyPaintedLayerRemoved(tl);
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -2252,16 +2252,22 @@ public:
 
   EventRegionsOverride GetEventRegionsOverride() const {
     return mEventRegionsOverride;
   }
 
 protected:
   friend class ReadbackProcessor;
 
+  // Note that this is not virtual, and is based on the implementation of
+  // ContainerLayer::RemoveChild, so it should only be called where you would
+  // want to explicitly call the base class implementation of RemoveChild;
+  // e.g., while (mFirstChild) ContainerLayer::RemoveChild(mFirstChild);
+  void RemoveAllChildren();
+
   void DidInsertChild(Layer* aLayer);
   void DidRemoveChild(Layer* aLayer);
 
   bool AnyAncestorOrThisIs3DContextLeaf();
 
   void Collect3DContextLeaves(nsTArray<Layer*>& aToSort);
 
   // Collects child layers that do not extend 3D context. For ContainerLayers
--- a/gfx/layers/basic/BasicContainerLayer.cpp
+++ b/gfx/layers/basic/BasicContainerLayer.cpp
@@ -18,20 +18,17 @@
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 BasicContainerLayer::~BasicContainerLayer()
 {
-  while (mFirstChild) {
-    ContainerLayer::RemoveChild(mFirstChild);
-  }
-
+  ContainerLayer::RemoveAllChildren();
   MOZ_COUNT_DTOR(BasicContainerLayer);
 }
 
 void
 BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
 {
   // We push groups for container layers if we need to, which always
   // are aligned in device space, so it doesn't really matter how we snap
--- a/gfx/layers/client/ClientContainerLayer.h
+++ b/gfx/layers/client/ClientContainerLayer.h
@@ -31,20 +31,17 @@ public:
   {
     MOZ_COUNT_CTOR(ClientContainerLayer);
     mSupportsComponentAlphaChildren = true;
   }
 
 protected:
   virtual ~ClientContainerLayer()
   {
-    while (mFirstChild) {
-      ContainerLayer::RemoveChild(mFirstChild);
-    }
-
+    ContainerLayer::RemoveAllChildren();
     MOZ_COUNT_DTOR(ClientContainerLayer);
   }
 
 public:
   virtual void RenderLayer() override
   {
     RenderMaskLayers(this);