Bug 1418722 - Mark nsDisplayPerspective items for removal when the inner transform frame gets removed from the frame tree. r=mstange a=gchang
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 28 Nov 2017 09:39:08 +1300
changeset 445060 8e32013003246a66c93de4d1c5e6b53f3f2df08d
parent 445059 c88f2766d765ad9af1a48ad84c7a4e7166515cdd
child 445061 63d5a1145380e16af66d7cc53eba165c4e1b1924
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, gchang
bugs1418722
milestone58.0
Bug 1418722 - Mark nsDisplayPerspective items for removal when the inner transform frame gets removed from the frame tree. r=mstange a=gchang
layout/painting/crashtests/1418722-1.html
layout/painting/crashtests/crashtests.list
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
new file mode 100644
--- /dev/null
+++ b/layout/painting/crashtests/1418722-1.html
@@ -0,0 +1,17 @@
+<html class="reftest-wait">
+<body>
+  <div style="width:200px; height:200px; perspective:1000px">
+    <div style="width:200px; height:200px; transform:translateZ(2px); background-color:green" id="transformed"></div>
+  </div>
+  <div style="width: 200px; height:200px; background-color:red" id="helper"></div>
+</body>
+<script>
+  function doTest() {
+    var element = document.getElementById("transformed");
+    element.parentNode.removeChild(element);
+    document.getElementById("helper").style.backgroundColor = "blue";
+    document.documentElement.className = "";
+  }
+  window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</html>
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -1,5 +1,6 @@
 load 1402183-1.html
 skip-if(!(stylo||styloVsGecko)||Android) load 1407470-1.html
 load 1413073-1.html
 load 1413073-2.html
 load 1405881-1.html
+load 1418722-1.html
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8877,16 +8877,18 @@ nsDisplayPerspective::nsDisplayPerspecti
                                            nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aPerspectiveFrame)
   , mList(aBuilder, aPerspectiveFrame, aList)
   , mTransformFrame(aTransformFrame)
   , mIndex(aBuilder->AllocatePerspectiveItemIndex())
 {
   MOZ_ASSERT(mList.GetChildren()->Count() == 1);
   MOZ_ASSERT(mList.GetChildren()->GetTop()->GetType() == DisplayItemType::TYPE_TRANSFORM);
+
+  mTransformFrame->AddDisplayItem(this);
 }
 
 already_AddRefed<Layer>
 nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
                                  LayerManager *aManager,
                                  const ContainerLayerParameters& aContainerParameters)
 {
   float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2034,17 +2034,17 @@ public:
    * @return the nsIFrame that provides the style data, and should
    * be checked when deciding if this display item can be reused.
    */
   virtual nsIFrame* FrameForInvalidation() const
   {
     return mFrame;
   }
 
-  bool HasDeletedFrame() const { return !mFrame; }
+  virtual bool HasDeletedFrame() const { return !mFrame; }
 
   virtual nsIFrame* StyleFrame() const { return mFrame; }
 
   /**
    * Compute the used z-index of our frame; returns zero for elements to which
    * z-index does not apply, and for z-index:auto.
    * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
    */
@@ -6097,16 +6097,22 @@ class nsDisplayPerspective : public nsDi
   typedef mozilla::gfx::Point3D Point3D;
 
 public:
   NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE)
 
   nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aTransformFrame,
                        nsIFrame* aPerspectiveFrame,
                        nsDisplayList* aList);
+  ~nsDisplayPerspective()
+  {
+    if (mTransformFrame) {
+      mTransformFrame->RemoveDisplayItem(this);
+    }
+  }
 
   virtual uint32_t GetPerFrameKey() const override {
     return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
   }
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override
   {
@@ -6203,16 +6209,26 @@ public:
   }
 
   virtual void Destroy(nsDisplayListBuilder* aBuilder) override
   {
     mList.GetChildren()->DeleteAll(aBuilder);
     nsDisplayItem::Destroy(aBuilder);
   }
 
+  virtual bool HasDeletedFrame() const override { return !mTransformFrame || nsDisplayItem::HasDeletedFrame(); }
+
+  virtual void RemoveFrame(nsIFrame* aFrame) override
+  {
+    if (aFrame == mTransformFrame) {
+      mTransformFrame = nullptr;
+    }
+    nsDisplayItem::RemoveFrame(aFrame);
+  }
+
 private:
   nsDisplayWrapList mList;
   nsIFrame* mTransformFrame;
   uint32_t mIndex;
 };
 
 /**
  * This class adds basic support for limiting the rendering (in the inline axis