Bug 1342994 Part 2 - Use UniquePtr to replace explicit new/delete and non-owing pointers in printing APIs. draft
authorTing-Yu Lin <tlin@mozilla.com>
Mon, 06 Mar 2017 16:28:20 +0800
changeset 494898 4d667b8f1fe658dd10e949e60c1e2191d9906ac7
parent 494593 fe81d14d9914aee22893de3078075abbcb797f51
child 548243 58ca80803477f79995290635c9f57173ecac8f4d
push id48184
push userbmo:tlin@mozilla.com
push dateWed, 08 Mar 2017 03:14:48 +0000
bugs1342994
milestone55.0a1
Bug 1342994 Part 2 - Use UniquePtr to replace explicit new/delete and non-owing pointers in printing APIs. Also, rewrite some for-loops as range-based. Other APIs still using nsPrintObject* involve with nsPrintData::mPrintDocList or nsPagePrintTimer::mPrintObj. nsPrintEngine::FindPrintObjectByDOMWin() could have its argument converted to UniquePtr, but it needs to return nullptr to represent "found nothing." Therefore, I leave its argument as it was for consistency. MozReview-Commit-ID: 7hXaVy5IKHQ
layout/printing/nsPrintData.cpp
layout/printing/nsPrintData.h
layout/printing/nsPrintEngine.cpp
layout/printing/nsPrintEngine.h
layout/printing/nsPrintObject.cpp
layout/printing/nsPrintObject.h
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -20,17 +20,17 @@
 static mozilla::LazyLogModule gPrintingLog("printing");
 
 #define PR_PL(_p1)  MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug, _p1);
 
 //---------------------------------------------------
 //-- nsPrintData Class Impl
 //---------------------------------------------------
 nsPrintData::nsPrintData(ePrintDataType aType) :
-  mType(aType), mDebugFilePtr(nullptr), mPrintObject(nullptr), mSelectedPO(nullptr),
+  mType(aType), mDebugFilePtr(nullptr), mSelectedPO(nullptr),
   mPrintDocList(0), mIsIFrameSelected(false),
   mIsParentAFrameSet(false), mOnStartSent(false),
   mIsAborted(false), mPreparingForPrint(false), mDocWasToBeDestroyed(false),
   mShrinkToFit(false), mPrintFrameType(nsIPrintSettings::kFramesAsIs),
   mNumPrintablePages(0), mNumPagesPrinted(0),
   mShrinkRatio(1.0), mOrigDCScale(1.0), mPPEventListeners(nullptr),
   mBrandName(nullptr)
 {
@@ -79,18 +79,16 @@ nsPrintData::~nsPrintData()
         rv = mPrintDC->AbortDocument();
       }
       if (NS_FAILED(rv)) {
         // XXX nsPrintData::ShowPrintErrorDialog(rv);
       }
     }
   }
 
-  delete mPrintObject;
-
   if (mBrandName) {
     free(mBrandName);
   }
 }
 
 void nsPrintData::OnStartPrinting()
 {
   if (!mOnStartSent) {
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsPrintData_h___
 #define nsPrintData_h___
 
 #include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
 
 // Interfaces
 #include "nsDeviceContext.h"
 #include "nsIPrintProgressParams.h"
 #include "nsIPrintSettings.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
@@ -52,25 +53,29 @@ public:
 
   void DoOnStatusChange(nsresult aStatus);
 
 
   ePrintDataType               mType;            // the type of data this is (Printing or Print Preview)
   RefPtr<nsDeviceContext>   mPrintDC;
   FILE                        *mDebugFilePtr;    // a file where information can go to when printing
 
-  nsPrintObject *                mPrintObject;
-  nsPrintObject *                mSelectedPO;
+  mozilla::UniquePtr<nsPrintObject> mPrintObject;
+  nsPrintObject* mSelectedPO; // This is a non-owning pointer.
 
   nsCOMArray<nsIWebProgressListener> mPrintProgressListeners;
   nsCOMPtr<nsIPrintProgressParams> mPrintProgressParams;
 
   nsCOMPtr<nsPIDOMWindowOuter> mCurrentFocusWin; // cache a pointer to the currently focused window
 
+  // Array of non-owning pointers to all the nsPrintObjects owned by this
+  // nsPrintData. This includes this->mPrintObject, as well as all of its
+  // mKids (and their mKids, etc.)
   nsTArray<nsPrintObject*>    mPrintDocList;
+
   bool                        mIsIFrameSelected;
   bool                        mIsParentAFrameSet;
   bool                        mOnStartSent;
   bool                        mIsAborted;           // tells us the document is being aborted
   bool                        mPreparingForPrint;   // see comments above
   bool                        mDocWasToBeDestroyed; // see comments above
   bool                        mShrinkToFit;
   int16_t                     mPrintFrameType;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -161,18 +161,18 @@ static const char * gPrintRangeStr[]    
 
 #ifdef EXTENDED_DEBUG_PRINTING
 // Forward Declarations
 static void DumpPrintObjectsListStart(const char * aStr, nsTArray<nsPrintObject*> * aDocList);
 static void DumpPrintObjectsTree(nsPrintObject * aPO, int aLevel= 0, FILE* aFD = nullptr);
 static void DumpPrintObjectsTreeLayout(nsPrintObject * aPO,nsDeviceContext * aDC, int aLevel= 0, FILE * aFD = nullptr);
 
 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
-#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
-#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
+#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject.get());
+#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject.get(), mPrt->mPrintDC);
 #else
 #define DUMP_DOC_LIST(_title)
 #define DUMP_DOC_TREE
 #define DUMP_DOC_TREELAYOUT
 #endif
 
 class nsScriptSuppressor
 {
@@ -320,17 +320,17 @@ nsPrintEngine::InstallPrintPreviewListen
       mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
       mPrt->mPPEventListeners->AddListeners();
     }
   }
 }
 
 //----------------------------------------------------------------------
 nsresult
-nsPrintEngine::GetSeqFrameAndCountPagesInternal(nsPrintObject*  aPO,
+nsPrintEngine::GetSeqFrameAndCountPagesInternal(const UniquePtr<nsPrintObject>& aPO,
                                                 nsIFrame*&    aSeqFrame,
                                                 int32_t&      aCount)
 {
   NS_ENSURE_ARG_POINTER(aPO);
 
   // This is sometimes incorrectly called before the pres shell has been created
   // (bug 1141756). MOZ_DIAGNOSTIC_ASSERT so we'll still see the crash in
   // Nightly/Aurora in case the other patch fixes this.
@@ -508,22 +508,21 @@ nsPrintEngine::DoCommonPrint(bool       
       nsCOMPtr<nsIContentViewer> viewer;
       webContainer->GetContentViewer(getter_AddRefs(viewer));
       if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) {
         viewer->GetDocument()->OnPageHide(false, nullptr);
       }
     }
 
     nsAutoScriptBlocker scriptBlocker;
-    mPrt->mPrintObject = new nsPrintObject();
-    NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY);
+    mPrt->mPrintObject = MakeUnique<nsPrintObject>();
     rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject),
+    NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject.get()),
                    NS_ERROR_OUT_OF_MEMORY);
 
     mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
     mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
 
     // Build the "tree" of PrintObjects
     BuildDocTree(mPrt->mPrintObject->mDocShell, &mPrt->mPrintDocList,
                  mPrt->mPrintObject);
@@ -1155,17 +1154,17 @@ nsPrintEngine::IsParentAFrameSet(nsIDocS
 
 
 //---------------------------------------------------------------------
 // Recursively build a list of sub documents to be printed
 // that mirrors the document tree
 void
 nsPrintEngine::BuildDocTree(nsIDocShell *      aParentNode,
                             nsTArray<nsPrintObject*> * aDocList,
-                            nsPrintObject *            aPO)
+                            const UniquePtr<nsPrintObject>& aPO)
 {
   NS_ASSERTION(aParentNode, "Pointer is null!");
   NS_ASSERTION(aDocList, "Pointer is null!");
   NS_ASSERTION(aPO, "Pointer is null!");
 
   int32_t childWebshellCount;
   aParentNode->GetChildCount(&childWebshellCount);
   if (childWebshellCount > 0) {
@@ -1175,24 +1174,24 @@ nsPrintEngine::BuildDocTree(nsIDocShell 
       nsCOMPtr<nsIDocShell> childAsShell(do_QueryInterface(child));
 
       nsCOMPtr<nsIContentViewer>  viewer;
       childAsShell->GetContentViewer(getter_AddRefs(viewer));
       if (viewer) {
         nsCOMPtr<nsIContentViewerFile> viewerFile(do_QueryInterface(viewer));
         if (viewerFile) {
           nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(childAsShell);
-          nsPrintObject * po = new nsPrintObject();
-          po->mParent = aPO;
+          auto po = MakeUnique<nsPrintObject>();
+          po->mParent = aPO.get();
           nsresult rv = po->Init(childAsShell, doc, aPO->mPrintPreview);
           if (NS_FAILED(rv))
             NS_NOTREACHED("Init failed?");
-          aPO->mKids.AppendElement(po);
-          aDocList->AppendElement(po);
-          BuildDocTree(childAsShell, aDocList, po);
+          aPO->mKids.AppendElement(Move(po));
+          aDocList->AppendElement(aPO->mKids.LastElement().get());
+          BuildDocTree(childAsShell, aDocList, aPO->mKids.LastElement());
         }
       }
     }
   }
 }
 
 //---------------------------------------------------------------------
 void
@@ -1233,18 +1232,18 @@ nsPrintEngine::GetDocumentTitleAndURL(ns
 
 //---------------------------------------------------------------------
 // The walks the PO tree and for each document it walks the content
 // tree looking for any content that are sub-shells
 //
 // It then sets the mContent pointer in the "found" PO object back to the
 // the document that contained it.
 void
-nsPrintEngine::MapContentToWebShells(nsPrintObject* aRootPO,
-                                     nsPrintObject* aPO)
+nsPrintEngine::MapContentToWebShells(const UniquePtr<nsPrintObject>& aRootPO,
+                                     const UniquePtr<nsPrintObject>& aPO)
 {
   NS_ASSERTION(aRootPO, "Pointer is null!");
   NS_ASSERTION(aPO, "Pointer is null!");
 
   // Recursively walk the content from the root item
   // XXX Would be faster to enumerate the subdocuments, although right now
   //     nsIDocument doesn't expose quite what would be needed.
   nsCOMPtr<nsIContentViewer> viewer;
@@ -1259,18 +1258,18 @@ nsPrintEngine::MapContentToWebShells(nsP
   Element* rootElement = doc->GetRootElement();
   if (rootElement) {
     MapContentForPO(aPO, rootElement);
   } else {
     NS_WARNING("Null root content on (sub)document.");
   }
 
   // Continue recursively walking the chilren of this PO
-  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
-    MapContentToWebShells(aRootPO, aPO->mKids[i]);
+  for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
+    MapContentToWebShells(aRootPO, kid);
   }
 
 }
 
 //-------------------------------------------------------
 // A Frame's sub-doc may contain content or a FrameSet
 // When it contains a FrameSet the mFrameType for the PrintObject
 // is always set to an eFrame. Which is fine when printing "AsIs"
@@ -1280,24 +1279,23 @@ nsPrintEngine::MapContentToWebShells(nsP
 //
 // This method walks the PO tree and checks to see if the PrintObject is
 // an eFrame and has children that are eFrames (meaning it's a Frame containing a FrameSet)
 // If so, then the mFrameType need to be changed to eFrameSet
 //
 // Also note: We only want to call this we are printing "Each Frame Separately"
 //            when printing "As Is" leave it as an eFrame
 void
-nsPrintEngine::CheckForChildFrameSets(nsPrintObject* aPO)
+nsPrintEngine::CheckForChildFrameSets(const UniquePtr<nsPrintObject>& aPO)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
 
   // Continue recursively walking the chilren of this PO
   bool hasChildFrames = false;
-  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
-    nsPrintObject* po = aPO->mKids[i];
+  for (const UniquePtr<nsPrintObject>& po : aPO->mKids) {
     if (po->mFrameType == eFrame) {
       hasChildFrames = true;
       CheckForChildFrameSets(po);
     }
   }
 
   if (hasChildFrames && aPO->mFrameType == eFrame) {
     aPO->mFrameType = eFrameSet;
@@ -1315,37 +1313,35 @@ nsPrintEngine::CheckForChildFrameSets(ns
 // This is used later to (after reflow) to find the absolute location
 // of the sub-doc on its parent's page frame so it can be
 // printed in the correct location.
 //
 // This method recursvely "walks" the content for a document finding
 // all the Frames and IFrames, then sets the "mFrameType" data member
 // which tells us what type of PO we have
 void
-nsPrintEngine::MapContentForPO(nsPrintObject*   aPO,
+nsPrintEngine::MapContentForPO(const UniquePtr<nsPrintObject>& aPO,
                                nsIContent*      aContent)
 {
   NS_PRECONDITION(aPO && aContent, "Null argument");
 
   nsIDocument* doc = aContent->GetComposedDoc();
 
   NS_ASSERTION(doc, "Content without a document from a document tree?");
 
   nsIDocument* subDoc = doc->GetSubDocumentFor(aContent);
 
   if (subDoc) {
     nsCOMPtr<nsIDocShell> docShell(subDoc->GetDocShell());
 
     if (docShell) {
       nsPrintObject * po = nullptr;
-      int32_t cnt = aPO->mKids.Length();
-      for (int32_t i=0;i<cnt;i++) {
-        nsPrintObject* kid = aPO->mKids.ElementAt(i);
+      for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
         if (kid->mDocument == subDoc) {
-          po = kid;
+          po = kid.get();
           break;
         }
       }
 
       // XXX If a subdocument has no onscreen presentation, there will be no PO
       //     This is even if there should be a print presentation
       if (po) {
 
@@ -1377,17 +1373,17 @@ nsPrintEngine::MapContentForPO(nsPrintOb
 bool
 nsPrintEngine::IsThereAnIFrameSelected(nsIDocShell* aDocShell,
                                        nsPIDOMWindowOuter* aDOMWin,
                                        bool& aIsParentFrameSet)
 {
   aIsParentFrameSet = IsParentAFrameSet(aDocShell);
   bool iFrameIsSelected = false;
   if (mPrt && mPrt->mPrintObject) {
-    nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin);
+    nsPrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), aDOMWin);
     iFrameIsSelected = po && po->mFrameType == eIFrame;
   } else {
     // First, check to see if we are a frameset
     if (!aIsParentFrameSet) {
       // Check to see if there is a currenlt focused frame
       // if so, it means the selected frame is either the main docshell
       // or an IFRAME
       if (aDOMWin) {
@@ -1410,28 +1406,28 @@ nsPrintEngine::IsThereAnIFrameSelected(n
 void
 nsPrintEngine::SetPrintPO(nsPrintObject* aPO, bool aPrint)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
 
   // Set whether to print flag
   aPO->mDontPrint = !aPrint;
 
-  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
-    SetPrintPO(aPO->mKids[i], aPrint);
+  for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
+    SetPrintPO(kid.get(), aPrint);
   }
 }
 
 //---------------------------------------------------------------------
 // This will first use a Title and/or URL from the PrintSettings
 // if one isn't set then it uses the one from the document
 // then if not title is there we will make sure we send something back
 // depending on the situation.
 void
-nsPrintEngine::GetDisplayTitleAndURL(nsPrintObject*   aPO,
+nsPrintEngine::GetDisplayTitleAndURL(const UniquePtr<nsPrintObject>& aPO,
                                      nsAString&       aTitle,
                                      nsAString&       aURLStr,
                                      eDocTitleDefault aDefType)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
 
   if (!mPrt)
     return;
@@ -1775,40 +1771,40 @@ nsPrintEngine::SetupToPrintContent()
 
   return rv;
 }
 
 //-------------------------------------------------------
 // Recursively reflow each sub-doc and then calc
 // all the frame locations of the sub-docs
 nsresult
-nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale)
+nsPrintEngine::ReflowDocList(const UniquePtr<nsPrintObject>& aPO,
+                             bool aSetPixelScale)
 {
   NS_ENSURE_ARG_POINTER(aPO);
 
   // Check to see if the subdocument's element has been hidden by the parent document
   if (aPO->mParent && aPO->mParent->mPresShell) {
     nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
     if (!frame || !frame->StyleVisibility()->IsVisible()) {
-      SetPrintPO(aPO, false);
+      SetPrintPO(aPO.get(), false);
       aPO->mInvisible = true;
       return NS_OK;
     }
   }
 
-  UpdateZoomRatio(aPO, aSetPixelScale);
+  UpdateZoomRatio(aPO.get(), aSetPixelScale);
 
   nsresult rv;
   // Reflow the PO
   rv = ReflowPrintObject(aPO);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  int32_t cnt = aPO->mKids.Length();
-  for (int32_t i=0;i<cnt;i++) {
-    rv = ReflowDocList(aPO->mKids[i], aSetPixelScale);
+  for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
+    rv = ReflowDocList(kid, aSetPixelScale);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 void
 nsPrintEngine::FirePrintPreviewUpdateEvent()
 {
@@ -2105,17 +2101,17 @@ nsPrintEngine::SetRootView(
   // Setup hierarchical relationship in view manager
   aPO->mViewManager->SetRootView(rootView);
 
   return NS_OK;
 }
 
 // Reflow a nsPrintObject
 nsresult
-nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
+nsPrintEngine::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO)
 {
   NS_ENSURE_STATE(aPO);
 
   if (!aPO->IsPrintable()) {
     return NS_OK;
   }
 
   NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
@@ -2161,23 +2157,24 @@ nsPrintEngine::ReflowPrintObject(nsPrint
 
   // The pres shell now owns the style set object.
 
 
   bool doReturn = false;;
   bool documentIsTopLevel = false;
   nsSize adjSize;
 
-  rv = SetRootView(aPO, doReturn, documentIsTopLevel, adjSize);
+  rv = SetRootView(aPO.get(), doReturn, documentIsTopLevel, adjSize);
 
   if (NS_FAILED(rv) || doReturn) {
     return rv;
   }
 
-  PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO, aPO->mPresShell.get(),
+  PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n",
+         aPO.get(), aPO->mPresShell.get(),
          gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
 
 
   // This docshell stuff is weird; will go away when we stop having multiple
   // presentations per document
   aPO->mPresContext->SetContainer(aPO->mDocShell);
 
   aPO->mPresShell->BeginObservingDocument();
@@ -2199,17 +2196,17 @@ nsPrintEngine::ReflowPrintObject(nsPrint
   rv = aPO->mPresShell->Initialize(adjSize.width, adjSize.height);
 
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
 
   // Process the reflow event Initialize posted
   aPO->mPresShell->FlushPendingNotifications(FlushType::Layout);
 
-  rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel);
+  rv = UpdateSelectionAndShrinkPrintObject(aPO.get(), documentIsTopLevel);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef EXTENDED_DEBUG_PRINTING
     if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
       nsAutoCString docStr;
       nsAutoCString urlStr;
       GetDocTitleAndURL(aPO, docStr, urlStr);
       char filename[256];
@@ -2274,31 +2271,31 @@ nsPrintEngine::CalcNumPrintablePages(int
 
 //-----------------------------------------------------------------
 //-- Section: Printing Methods
 //-----------------------------------------------------------------
 
 //-------------------------------------------------------
 // Called for each DocShell that needs to be printed
 bool
-nsPrintEngine::PrintDocContent(nsPrintObject* aPO, nsresult& aStatus)
+nsPrintEngine::PrintDocContent(const UniquePtr<nsPrintObject>& aPO,
+                               nsresult& aStatus)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
   aStatus = NS_OK;
 
   if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) {
     aStatus = DoPrint(aPO);
     return true;
   }
 
   // If |aPO->mPrintAsIs| and |aPO->mHasBeenPrinted| are true,
   // the kids frames are already processed in |PrintPage|.
   if (!aPO->mInvisible && !(aPO->mPrintAsIs && aPO->mHasBeenPrinted)) {
-    for (uint32_t i=0;i<aPO->mKids.Length();i++) {
-      nsPrintObject* po = aPO->mKids[i];
+    for (const UniquePtr<nsPrintObject>& po : aPO->mKids) {
       bool printed = PrintDocContent(po, aStatus);
       if (printed || NS_FAILED(aStatus)) {
         return true;
       }
     }
   }
   return false;
 }
@@ -2386,21 +2383,21 @@ static nsresult CloneSelection(nsIDocume
   for (int32_t i = 0; i < rangeCount; ++i) {
       CloneRangeToSelection(origSelection->GetRangeAt(i), aDoc, selection);
   }
   return NS_OK;
 }
 
 //-------------------------------------------------------
 nsresult
-nsPrintEngine::DoPrint(nsPrintObject * aPO)
+nsPrintEngine::DoPrint(const UniquePtr<nsPrintObject>& aPO)
 {
   PR_PL(("\n"));
   PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]));
-  PR_PL(("****** In DV::DoPrint   PO: %p \n", aPO));
+  PR_PL(("****** In DV::DoPrint   PO: %p \n", aPO.get()));
 
   nsIPresShell*   poPresShell   = aPO->mPresShell;
   nsPresContext*  poPresContext = aPO->mPresContext;
 
   NS_ASSERTION(poPresContext, "PrintObject has not been reflowed");
   NS_ASSERTION(poPresContext->Type() != nsPresContext::eContext_PrintPreview,
                "How did this context end up here?");
 
@@ -2526,27 +2523,27 @@ nsPrintEngine::DoPrint(nsPrintObject * a
         SetIsPrinting(false);
         return NS_ERROR_FAILURE;
       }
 
       mPageSeqFrame = seqFrame;
       pageSequence->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
 
       // Schedule Page to Print
-      PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]));
+      PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO.get(), gFrameTypesStr[aPO->mFrameType]));
       StartPagePrintTimer(aPO);
     }
   }
 
   return NS_OK;
 }
 
 //---------------------------------------------------------------------
 void
-nsPrintEngine::SetDocAndURLIntoProgress(nsPrintObject* aPO,
+nsPrintEngine::SetDocAndURLIntoProgress(const UniquePtr<nsPrintObject>& aPO,
                                         nsIPrintProgressParams* aParams)
 {
   NS_ASSERTION(aPO, "Must have valid nsPrintObject");
   NS_ASSERTION(aParams, "Must have valid nsIPrintProgressParams");
 
   if (!aPO || !aPO->mDocShell || !aParams) {
     return;
   }
@@ -3092,18 +3089,18 @@ nsPrintEngine::DonePrintingPages(nsPrint
 // Recursively sets the PO items to be printed "As Is"
 // from the given item down into the tree
 void
 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
 
   aPO->mPrintAsIs = aAsIs;
-  for (uint32_t i=0;i<aPO->mKids.Length();i++) {
-    SetPrintAsIs(aPO->mKids[i], aAsIs);
+  for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
+    SetPrintAsIs(kid.get(), aAsIs);
   }
 }
 
 //-------------------------------------------------------
 // Given a DOMWindow it recursively finds the PO object that matches
 nsPrintObject*
 nsPrintEngine::FindPrintObjectByDOMWin(nsPrintObject* aPO,
                                        nsPIDOMWindowOuter* aDOMWin)
@@ -3116,19 +3113,18 @@ nsPrintEngine::FindPrintObjectByDOMWin(n
     return nullptr;
   }
 
   nsCOMPtr<nsIDocument> doc = aDOMWin->GetDoc();
   if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) {
     return aPO;
   }
 
-  int32_t cnt = aPO->mKids.Length();
-  for (int32_t i = 0; i < cnt; ++i) {
-    nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin);
+  for (const UniquePtr<nsPrintObject>& kid : aPO->mKids) {
+    nsPrintObject* po = FindPrintObjectByDOMWin(kid.get(), aDOMWin);
     if (po) {
       return po;
     }
   }
 
   return nullptr;
 }
 
@@ -3173,25 +3169,24 @@ nsPrintEngine::EnablePOsForPrinting()
   //
   // This means there are not FrameSets,
   // but the document could contain an IFrame
   if (printHowEnable == nsIPrintSettings::kFrameEnableNone) {
 
     // Print all the pages or a sub range of pages
     if (printRangeType == nsIPrintSettings::kRangeAllPages ||
         printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
-      SetPrintPO(mPrt->mPrintObject, true);
+      SetPrintPO(mPrt->mPrintObject.get(), true);
 
       // Set the children so they are PrinAsIs
       // In this case, the children are probably IFrames
       if (mPrt->mPrintObject->mKids.Length() > 0) {
-        for (uint32_t i=0;i<mPrt->mPrintObject->mKids.Length();i++) {
-          nsPrintObject* po = mPrt->mPrintObject->mKids[i];
+        for (const UniquePtr<nsPrintObject>& po : mPrt->mPrintObject->mKids) {
           NS_ASSERTION(po, "nsPrintObject can't be null!");
-          SetPrintAsIs(po);
+          SetPrintAsIs(po.get());
         }
 
         // ***** Another override *****
         mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
       }
       PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
       PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
       PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
@@ -3200,17 +3195,17 @@ nsPrintEngine::EnablePOsForPrinting()
 
     // This means we are either printed a selected IFrame or
     // we are printing the current selection
     if (printRangeType == nsIPrintSettings::kRangeSelection) {
 
       // If the currentFocusDOMWin can'r be null if something is selected
       if (mPrt->mCurrentFocusWin) {
         // Find the selected IFrame
-        nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
+        nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), mPrt->mCurrentFocusWin);
         if (po != nullptr) {
           mPrt->mSelectedPO = po;
           // Makes sure all of its children are be printed "AsIs"
           SetPrintAsIs(po);
 
           // Now, only enable this POs (the selected PO) and all of its children
           SetPrintPO(po, true);
 
@@ -3248,17 +3243,17 @@ nsPrintEngine::EnablePOsForPrinting()
     }
   }
 
   // check to see if there is a selection when a FrameSet is present
   if (printRangeType == nsIPrintSettings::kRangeSelection) {
     // If the currentFocusDOMWin can'r be null if something is selected
     if (mPrt->mCurrentFocusWin) {
       // Find the selected IFrame
-      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
+      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), mPrt->mCurrentFocusWin);
       if (po != nullptr) {
         mPrt->mSelectedPO = po;
         // Makes sure all of its children are be printed "AsIs"
         SetPrintAsIs(po);
 
         // Now, only enable this POs (the selected PO) and all of its children
         SetPrintPO(po, true);
 
@@ -3279,28 +3274,28 @@ nsPrintEngine::EnablePOsForPrinting()
         PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
         return NS_OK;
       }
     }
   }
 
   // If we are printing "AsIs" then sets all the POs to be printed as is
   if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
-    SetPrintAsIs(mPrt->mPrintObject);
-    SetPrintPO(mPrt->mPrintObject, true);
+    SetPrintAsIs(mPrt->mPrintObject.get());
+    SetPrintPO(mPrt->mPrintObject.get(), true);
     return NS_OK;
   }
 
   // If we are printing the selected Frame then
   // find that PO for that selected DOMWin and set it all of its
   // children to be printed
   if (mPrt->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
 
     if ((mPrt->mIsParentAFrameSet && mPrt->mCurrentFocusWin) || mPrt->mIsIFrameSelected) {
-      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, mPrt->mCurrentFocusWin);
+      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), mPrt->mCurrentFocusWin);
       if (po != nullptr) {
         mPrt->mSelectedPO = po;
         // NOTE: Calling this sets the "po" and
         // we don't want to do this for documents that have no children,
         // because then the "DoEndPage" gets called and it shouldn't
         if (po->mKids.Length() > 0) {
           // Makes sure that itself, and all of its children are printed "AsIs"
           SetPrintAsIs(po);
@@ -3311,17 +3306,17 @@ nsPrintEngine::EnablePOsForPrinting()
       }
     }
     return NS_OK;
   }
 
   // If we are print each subdoc separately,
   // then don't print any of the FraneSet Docs
   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
-    SetPrintPO(mPrt->mPrintObject, true);
+    SetPrintPO(mPrt->mPrintObject.get(), true);
     int32_t cnt = mPrt->mPrintDocList.Length();
     for (int32_t i=0;i<cnt;i++) {
       nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
       NS_ASSERTION(po, "nsPrintObject can't be null!");
       if (po->mFrameType == eFrameSet) {
         po->mDontPrint = true;
       }
     }
@@ -3490,17 +3485,17 @@ nsPrintEngine::FinishPrintPreview()
 
 //-----------------------------------------------------------------
 //-- Done: Finishing up or Cleaning up
 //-----------------------------------------------------------------
 
 
 /*=============== Timer Related Code ======================*/
 nsresult
-nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO)
+nsPrintEngine::StartPagePrintTimer(const UniquePtr<nsPrintObject>& aPO)
 {
   if (!mPagePrintTimer) {
     // Get the delay time in between the printing of each page
     // this gives the user more time to press cancel
     int32_t printPageDelay = 50;
     mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
 
     RefPtr<nsPagePrintTimer> timer =
@@ -3514,17 +3509,17 @@ nsPrintEngine::StartPagePrintTimer(nsPri
       printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
       if (NS_SUCCEEDED(rv) && remotePrintJob) {
         remotePrintJob->SetPagePrintTimer(mPagePrintTimer);
         remotePrintJob->SetPrintEngine(this);
       }
     }
   }
 
-  return mPagePrintTimer->Start(aPO);
+  return mPagePrintTimer->Start(aPO.get());
 }
 
 /*=============== nsIObserver Interface ======================*/
 NS_IMETHODIMP
 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
@@ -3838,17 +3833,19 @@ static void DumpPrintObjectsTree(nsPrint
     NS_ASSERTION(po, "nsPrintObject can't be null!");
     for (int32_t k=0;k<aLevel;k++) fprintf(fd, "  ");
     fprintf(fd, "%s %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po, po->mDocShell.get(), po->mSeqFrame,
            po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height);
   }
 }
 
 //-------------------------------------------------------------
-static void GetDocTitleAndURL(nsPrintObject* aPO, nsACString& aDocStr, nsACString& aURLStr)
+static void GetDocTitleAndURL(const UniquePtr<nsPrintObject>& aPO,
+                              nsACString& aDocStr,
+                              nsACString& aURLStr)
 {
   nsAutoString docTitleStr;
   nsAutoString docURLStr;
   nsPrintEngine::GetDisplayTitleAndURL(aPO,
                                        docTitleStr, docURLStr,
                                        nsPrintEngine::eDocTitleDefURLDoc);
   aDocStr = NS_ConvertUTF16toUTF8(docTitleStr);
   aURLStr = NS_ConvertUTF16toUTF8(docURLStr);
@@ -3910,18 +3907,18 @@ static void DumpPrintObjectsListStart(co
   NS_ASSERTION(aStr, "Pointer is null!");
   NS_ASSERTION(aDocList, "Pointer is null!");
 
   PR_PL(("%s\n", aStr));
   DumpPrintObjectsList(aDocList);
 }
 
 #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList);
-#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject);
-#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC);
+#define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject.get());
+#define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject.get(), mPrt->mPrintDC);
 
 #else
 #define DUMP_DOC_LIST(_title)
 #define DUMP_DOC_TREE
 #define DUMP_DOC_TREELAYOUT
 #endif
 
 //---------------------------------------------------------------
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -92,62 +92,64 @@ public:
   nsresult DocumentReadyForPrinting();
   nsresult GetSelectionDocument(nsIDeviceContextSpec * aDevSpec,
                                 nsIDocument ** aNewDoc);
 
   nsresult SetupToPrintContent();
   nsresult EnablePOsForPrinting();
   nsPrintObject* FindSmallestSTF();
 
-  bool     PrintDocContent(nsPrintObject* aPO, nsresult& aStatus);
-  nsresult DoPrint(nsPrintObject * aPO);
+  bool PrintDocContent(const mozilla::UniquePtr<nsPrintObject>& aPO,
+                       nsresult& aStatus);
+  nsresult DoPrint(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void SetPrintPO(nsPrintObject* aPO, bool aPrint);
 
   void TurnScriptingOn(bool aDoTurnOn);
   bool CheckDocumentForPPCaching();
   void InstallPrintPreviewListener();
 
   // nsIDocumentViewerPrint Printing Methods
   bool     HasPrintCallbackCanvas();
   bool     PrePrintPage();
   bool     PrintPage(nsPrintObject* aPOect, bool& aInRange);
   bool     DonePrintingPages(nsPrintObject* aPO, nsresult aResult);
 
   //---------------------------------------------------------------------
   void BuildDocTree(nsIDocShell *      aParentNode,
                     nsTArray<nsPrintObject*> * aDocList,
-                    nsPrintObject *            aPO);
-  nsresult ReflowDocList(nsPrintObject * aPO, bool aSetPixelScale);
+                    const mozilla::UniquePtr<nsPrintObject>& aPO);
+  nsresult ReflowDocList(const mozilla::UniquePtr<nsPrintObject>& aPO,
+                         bool aSetPixelScale);
 
-  nsresult ReflowPrintObject(nsPrintObject * aPO);
+  nsresult ReflowPrintObject(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
-  void CheckForChildFrameSets(nsPrintObject* aPO);
+  void CheckForChildFrameSets(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void CalcNumPrintablePages(int32_t& aNumPages);
   void ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify);
   nsresult CleanupOnFailure(nsresult aResult, bool aIsPrinting);
   // If FinishPrintPreview() fails, caller may need to reset the state of the
   // object, for example by calling CleanupOnFailure().
   nsresult FinishPrintPreview();
   static void CloseProgressDialog(nsIWebProgressListener* aWebProgressListener);
-  void SetDocAndURLIntoProgress(nsPrintObject* aPO,
+  void SetDocAndURLIntoProgress(const mozilla::UniquePtr<nsPrintObject>& aPO,
                                 nsIPrintProgressParams* aParams);
   void EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront);
   nsresult CheckForPrinters(nsIPrintSettings* aPrintSettings);
   void CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount);
 
   bool IsThereARangeSelection(nsPIDOMWindowOuter* aDOMWin);
 
   void FirePrintingErrorEvent(nsresult aPrintError);
   //---------------------------------------------------------------------
 
 
   // Timer Methods
-  nsresult StartPagePrintTimer(nsPrintObject* aPO);
+  nsresult StartPagePrintTimer(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   bool IsWindowsInOurSubTree(nsPIDOMWindowOuter* aDOMWindow);
   static bool IsParentAFrameSet(nsIDocShell * aParent);
   bool IsThereAnIFrameSelected(nsIDocShell* aDocShell,
                                nsPIDOMWindowOuter* aDOMWin,
                                bool& aIsParentFrameSet);
 
   static nsPrintObject* FindPrintObjectByDOMWin(nsPrintObject* aParentObject,
@@ -157,17 +159,17 @@ public:
   already_AddRefed<nsPIDOMWindowOuter> FindFocusedDOMWindow();
 
   //---------------------------------------------------------------------
   // Static Methods
   //---------------------------------------------------------------------
   static void GetDocumentTitleAndURL(nsIDocument* aDoc,
                                      nsAString&   aTitle,
                                      nsAString&   aURLStr);
-  void GetDisplayTitleAndURL(nsPrintObject*   aPO,
+  void GetDisplayTitleAndURL(const mozilla::UniquePtr<nsPrintObject>& aPO,
                              nsAString&       aTitle,
                              nsAString&       aURLStr,
                              eDocTitleDefault aDefType);
 
   static bool HasFramesetChild(nsIContent* aContent);
 
   bool     CheckBeforeDestroy();
   nsresult Cancelled();
@@ -211,17 +213,17 @@ protected:
                        nsIWebProgressListener* aWebProgressListener,
                        nsIDOMDocument* aDoc);
 
   nsresult DoCommonPrint(bool aIsPrintPreview, nsIPrintSettings* aPrintSettings,
                          nsIWebProgressListener* aWebProgressListener,
                          nsIDOMDocument* aDoc);
 
   void FirePrintCompletionEvent();
-  static nsresult GetSeqFrameAndCountPagesInternal(nsPrintObject*  aPO,
+  static nsresult GetSeqFrameAndCountPagesInternal(const mozilla::UniquePtr<nsPrintObject>& aPO,
                                                    nsIFrame*&      aSeqFrame,
                                                    int32_t&        aCount);
 
   static nsresult FindSelectionBoundsWithList(nsFrameList::Enumerator& aChildFrames,
                                               nsIFrame *      aParentFrame,
                                               nsRect&         aRect,
                                               nsIFrame *&     aStartFrame,
                                               nsRect&         aStartRect,
@@ -238,19 +240,21 @@ protected:
   static nsresult GetPageRangeForSelection(nsIPageSequenceFrame* aPageSeqFrame,
                                            nsIFrame**            aStartFrame,
                                            int32_t&              aStartPageNum,
                                            nsRect&               aStartRect,
                                            nsIFrame**            aEndFrame,
                                            int32_t&              aEndPageNum,
                                            nsRect&               aEndRect);
 
-  static void MapContentForPO(nsPrintObject* aPO, nsIContent* aContent);
+  static void MapContentForPO(const mozilla::UniquePtr<nsPrintObject>& aPO,
+                              nsIContent* aContent);
 
-  static void MapContentToWebShells(nsPrintObject* aRootPO, nsPrintObject* aPO);
+  static void MapContentToWebShells(const mozilla::UniquePtr<nsPrintObject>& aRootPO,
+                                    const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   static void SetPrintAsIs(nsPrintObject* aPO, bool aAsIs = true);
 
   void DisconnectPagePrintTimer();
 
   // Static member variables
   bool mIsCreatingPrintPreview;
   bool mIsDoingPrinting;
--- a/layout/printing/nsPrintObject.cpp
+++ b/layout/printing/nsPrintObject.cpp
@@ -26,20 +26,16 @@ nsPrintObject::nsPrintObject() :
 {
   MOZ_COUNT_CTOR(nsPrintObject);
 }
 
 
 nsPrintObject::~nsPrintObject()
 {
   MOZ_COUNT_DTOR(nsPrintObject);
-  for (uint32_t i=0;i<mKids.Length();i++) {
-    nsPrintObject* po = mKids[i];
-    delete po;
-  }
 
   DestroyPresentation();
   if (mDidCreateDocShell && mDocShell) {
     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
     if (baseWin) {
       baseWin->Destroy();
     }
   }
--- a/layout/printing/nsPrintObject.h
+++ b/layout/printing/nsPrintObject.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsPrintObject_h___
 #define nsPrintObject_h___
 
 #include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
 
 // Interfaces
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsViewManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 
@@ -45,18 +46,18 @@ public:
 
   RefPtr<nsPresContext>  mPresContext;
   nsCOMPtr<nsIPresShell>   mPresShell;
   RefPtr<nsViewManager> mViewManager;
 
   nsCOMPtr<nsIContent>     mContent;
   PrintObjectType  mFrameType;
 
-  nsTArray<nsPrintObject*> mKids;
-  nsPrintObject*   mParent;
+  nsTArray<mozilla::UniquePtr<nsPrintObject>> mKids;
+  nsPrintObject*   mParent; // This is a non-owning pointer.
   bool             mHasBeenPrinted;
   bool             mDontPrint;
   bool             mPrintAsIs;
   bool             mInvisible;        // Indicates PO is set to not visible by CSS
   bool             mPrintPreview;
   bool             mDidCreateDocShell;
   float            mShrinkRatio;
   float            mZoomRatio;