Bug 1418722 - Mark nsDisplayPerspective items for removal when the inner transform frame gets removed from the frame tree. r=mstange
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 28 Nov 2017 09:39:08 +1300
changeset 703834 a16f714be5a2e98e4013713ec22716a4a5ebd0b2
parent 703833 b97b62055f10362a4791d684f42c9e71ea202d14
child 703835 b9f05468dd0cef22561fd89c8da27cc96984900d
child 703865 cb4618e15399a3976f3d7733ffd442c0bc4e5a6e
push id90984
push userbmo:gl@mozilla.com
push dateMon, 27 Nov 2017 20:54:52 +0000
reviewersmstange
bugs1418722
milestone59.0a1
Bug 1418722 - Mark nsDisplayPerspective items for removal when the inner transform frame gets removed from the frame tree. r=mstange
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
@@ -9001,16 +9001,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
@@ -2058,17 +2058,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.
    */
@@ -6149,16 +6149,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
   {
@@ -6255,16 +6261,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