Bug 1466024 - Cleanup nsDisplaySubDocument display items when we swap the subdoc into a different outer document. r?miko draft
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 01 Jun 2018 17:23:55 +1200
changeset 802565 a7432441cf58e2caad195957cc22ed3010c90000
parent 802564 594a2484dfaf5523aec8c2c21b5e0eec854012bf
push id111914
push usermwoodrow@mozilla.com
push dateFri, 01 Jun 2018 05:25:27 +0000
reviewersmiko
bugs1466024
milestone62.0a1
Bug 1466024 - Cleanup nsDisplaySubDocument display items when we swap the subdoc into a different outer document. r?miko MozReview-Commit-ID: E4NKiIdXZsY
layout/base/nsLayoutUtils.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3829,17 +3829,18 @@ nsLayoutUtils::PaintFrame(gfxContext* aR
     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
   }
   if (aFlags & PaintFrameFlags::PAINT_NO_COMPOSITE) {
     flags |= nsDisplayList::PAINT_NO_COMPOSITE;
   }
   if (aFlags & PaintFrameFlags::PAINT_COMPRESSED) {
     flags |= nsDisplayList::PAINT_COMPRESSED;
   }
-  if (updateState == PartialUpdateResult::NoChange) {
+  if (updateState == PartialUpdateResult::NoChange &&
+      !aRenderingContext) {
     flags |= nsDisplayList::PAINT_IDENTICAL_DISPLAY_LIST;
   }
 
   TimeStamp paintStart = TimeStamp::Now();
   RefPtr<LayerManager> layerManager
     = list.PaintRoot(&builder, aRenderingContext, flags);
   Telemetry::AccumulateTimeDelta(Telemetry::PAINT_RASTERIZE_TIME,
                                  paintStart);
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -38,16 +38,17 @@
 #include "nsLayoutUtils.h"
 #include "FrameLayerBuilder.h"
 #include "nsPluginFrame.h"
 #include "nsContentUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/HTMLFrameElement.h"
+#include "RetainedDisplayListBuilder.h"
 
 using namespace mozilla;
 using mozilla::layout::RenderFrameParent;
 
 static bool sShowPreviousPage = true;
 
 static nsIDocument*
 GetDocumentFromView(nsView* aView)
@@ -1152,16 +1153,19 @@ nsSubDocumentFrame::BeginSwapDocShells(n
   }
 
   nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
   if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
       !other->mFrameLoader || !other->mDidCreateDoc) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
+  ClearDisplayItems();
+  other->ClearDisplayItems();
+
   if (mInnerView && other->mInnerView) {
     nsView* ourSubdocViews = mInnerView->GetFirstChild();
     nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
     nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
     nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
 
     ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
     ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
@@ -1256,16 +1260,40 @@ nsSubDocumentFrame::EndSwapDocShells(nsI
   }
   if (weakOther.IsAlive()) {
     other->PresShell()->
       FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
     other->InvalidateFrameSubtree();
   }
 }
 
+void
+nsSubDocumentFrame::ClearDisplayItems()
+{
+  DisplayItemArray* items = GetProperty(DisplayItems());
+  if (!items) {
+    return;
+  }
+
+  nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
+  MOZ_ASSERT(displayRoot);
+
+  RetainedDisplayListBuilder* retainedBuilder =
+    displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
+  MOZ_ASSERT(retainedBuilder);
+
+  for (nsDisplayItem* i : *items) {
+    if (i->GetType() == DisplayItemType::TYPE_SUBDOCUMENT) {
+      i->GetChildren()->DeleteAll(retainedBuilder->Builder());
+      static_cast<nsDisplaySubDocument*>(i)->Disown();
+      break;
+    }
+  }
+}
+
 nsView*
 nsSubDocumentFrame::EnsureInnerView()
 {
   if (mInnerView) {
     return mInnerView;
   }
 
   // create, init, set the parent of the view
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -147,16 +147,18 @@ protected:
   nscoord GetIntrinsicISize();
   nscoord GetIntrinsicBSize();
 
   // Show our document viewer. The document viewer is hidden via a script
   // runner, so that we can save and restore the presentation if we're
   // being reframed.
   void ShowViewer();
 
+  void ClearDisplayItems();
+
   /* Obtains the frame we should use for intrinsic size information if we are
    * an HTML <object> or <embed>  (a replaced element - not <iframe>)
    * and our sub-document has an intrinsic size. The frame returned is the
    * frame for the document element of the document we're embedding.
    *
    * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
    * says it should be called ObtainDocShell because of its side effects.
    */
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7163,16 +7163,29 @@ void
 nsDisplaySubDocument::RemoveFrame(nsIFrame* aFrame)
 {
   if (aFrame == mSubDocFrame) {
     mSubDocFrame = nullptr;
   }
   nsDisplayItem::RemoveFrame(aFrame);
 }
 
+void
+nsDisplaySubDocument::Disown()
+{
+  if (mFrame) {
+    mFrame->RemoveDisplayItem(this);
+    mFrame = nullptr;
+  }
+  if (mSubDocFrame) {
+    mSubDocFrame->RemoveDisplayItem(this);
+    mSubDocFrame = nullptr;
+  }
+}
+
 UniquePtr<ScrollMetadata>
 nsDisplaySubDocument::ComputeScrollMetadata(LayerManager* aLayerManager,
                                             const ContainerLayerParameters& aContainerParameters)
 {
   if (!(mFlags & nsDisplayOwnLayerFlags::eGenerateScrollableLayer)) {
     return UniquePtr<ScrollMetadata>(nullptr);
   }
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5852,16 +5852,18 @@ public:
                                                            const ContainerLayerParameters& aContainerParameters);
 
   virtual nsIFrame* FrameForInvalidation() const override;
 
   virtual bool HasDeletedFrame() const override;
 
   virtual void RemoveFrame(nsIFrame* aFrame) override;
 
+  void Disown();
+
 protected:
   ViewID mScrollParentId;
   bool mForceDispatchToContentRegion;
   bool mShouldFlatten;
   nsSubDocumentFrame* mSubDocFrame;
 };
 
 /**