Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 16 May 2017 20:10:26 -0400
changeset 409084 41958333867b0f537271dbd4cb4ba9e8a67a85a8
parent 409076 985b3ee939338022ef44028b5251f77af19c3638 (current diff)
parent 409083 8f89d291e303a3d637a268c5abad9c819aad9285 (diff)
child 409085 fcb2c384b08b211f31d9c453cbf0ae90fb0e2b86
child 409179 ccd1be0275e77d891ca4822fa3f8db0e26c5294e
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.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
Merge inbound to m-c. a=merge CLOSED TREE
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1761,26 +1761,27 @@ nsDocumentViewer::Destroy()
 
   // All callers are supposed to call destroy to break circular
   // references.  If we do this stuff in the destructor, the
   // destructor might never be called (especially if we're being
   // used from JS.
 
 #ifdef NS_PRINTING
   if (mPrintEngine) {
+    RefPtr<nsPrintEngine> printEngine = mozilla::Move(mPrintEngine);
 #ifdef NS_PRINT_PREVIEW
     bool doingPrintPreview;
-    mPrintEngine->GetDoingPrintPreview(&doingPrintPreview);
+    printEngine->GetDoingPrintPreview(&doingPrintPreview);
     if (doingPrintPreview) {
-      mPrintEngine->FinishPrintPreview();
+      printEngine->FinishPrintPreview();
     }
 #endif
-
-    mPrintEngine->Destroy();
-    mPrintEngine = nullptr;
+    printEngine->Destroy();
+    MOZ_ASSERT(!mPrintEngine,
+               "mPrintEngine shouldn't be recreated while destroying it");
   }
 #endif
 
   // Avoid leaking the old viewer.
   if (mPreviousViewer) {
     mPreviousViewer->Destroy();
     mPreviousViewer = nullptr;
   }
--- a/layout/printing/nsPagePrintTimer.h
+++ b/layout/printing/nsPagePrintTimer.h
@@ -50,17 +50,21 @@ public:
 
   NS_IMETHOD Run() override;
 
   void Stop();
 
   void WaitForRemotePrint();
   void RemotePrintFinished();
 
-  void Disconnect() { mPrintEngine = nullptr; }
+  void Disconnect()
+  {
+    mPrintEngine = nullptr;
+    mPrintObj = nullptr;
+  }
 
 private:
   ~nsPagePrintTimer();
 
   nsresult StartTimer(bool aUseDelay);
   nsresult StartWatchDogTimer();
   void     StopWatchDogTimer();
   void     Fail();
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -29,17 +29,16 @@ nsPrintData::nsPrintData(ePrintDataType 
   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)
 {
-  MOZ_COUNT_CTOR(nsPrintData);
   nsCOMPtr<nsIStringBundle> brandBundle;
   nsCOMPtr<nsIStringBundleService> svc =
     mozilla::services::GetStringBundleService();
   if (svc) {
     svc->CreateBundle( "chrome://branding/locale/brand.properties", getter_AddRefs( brandBundle ) );
     if (brandBundle) {
       brandBundle->GetStringFromName(u"brandShortName", &mBrandName );
     }
@@ -48,17 +47,16 @@ nsPrintData::nsPrintData(ePrintDataType 
   if (!mBrandName) {
     mBrandName = ToNewUnicode(NS_LITERAL_STRING("Mozilla Document"));
   }
 
 }
 
 nsPrintData::~nsPrintData()
 {
-  MOZ_COUNT_DTOR(nsPrintData);
   // remove the event listeners
   if (mPPEventListeners) {
     mPPEventListeners->RemoveListeners();
     NS_RELEASE(mPPEventListeners);
   }
 
   // Only Send an OnEndPrinting if we have started printing
   if (mOnStartSent && mType != eIsPrintPreview) {
@@ -105,29 +103,37 @@ void nsPrintData::OnEndPrinting()
 }
 
 void
 nsPrintData::DoOnProgressChange(int32_t      aProgress,
                                 int32_t      aMaxProgress,
                                 bool         aDoStartStop,
                                 int32_t      aFlag)
 {
-  for (int32_t i=0;i<mPrintProgressListeners.Count();i++) {
-    nsIWebProgressListener* wpl = mPrintProgressListeners.ObjectAt(i);
-    wpl->OnProgressChange(nullptr, nullptr, aProgress, aMaxProgress, aProgress, aMaxProgress);
+  size_t numberOfListeners = mPrintProgressListeners.Length();
+  for (size_t i = 0; i < numberOfListeners; ++i) {
+    nsCOMPtr<nsIWebProgressListener> listener =
+      mPrintProgressListeners.SafeElementAt(i);
+    if (NS_WARN_IF(!listener)) {
+      continue;
+    }
+    listener->OnProgressChange(nullptr, nullptr, aProgress, aMaxProgress,
+                               aProgress, aMaxProgress);
     if (aDoStartStop) {
-      wpl->OnStateChange(nullptr, nullptr, aFlag, NS_OK);
+      listener->OnStateChange(nullptr, nullptr, aFlag, NS_OK);
     }
   }
 }
 
 void
 nsPrintData::DoOnStatusChange(nsresult aStatus)
 {
-  uint32_t numberOfListeners = mPrintProgressListeners.Length();
-  for (uint32_t i = 0; i < numberOfListeners; ++i) {
-    nsIWebProgressListener* listener = mPrintProgressListeners.SafeElementAt(i);
-    if (listener) {
-      listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr);
+  size_t numberOfListeners = mPrintProgressListeners.Length();
+  for (size_t i = 0; i < numberOfListeners; ++i) {
+    nsCOMPtr<nsIWebProgressListener> listener =
+      mPrintProgressListeners.SafeElementAt(i);
+    if (NS_WARN_IF(!listener)) {
+      continue;
     }
+    listener->OnStatusChange(nullptr, nullptr, aStatus, nullptr);
   }
 }
 
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -8,16 +8,17 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/UniquePtr.h"
 
 // Interfaces
 #include "nsDeviceContext.h"
 #include "nsIPrintProgressParams.h"
 #include "nsIPrintSettings.h"
+#include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
 // Classes
 class nsPrintObject;
 class nsPrintPreviewListener;
 class nsIWebProgressListener;
 
@@ -32,21 +33,21 @@ class nsIWebProgressListener;
 //   while we were prparing to Print. This typically happens if a user starts
 //   to print while a page is still loading. If they start printing and pause
 //   at the print dialog and then the page comes in, we then abort printing
 //   because the document is no longer stable.
 //
 //------------------------------------------------------------------------
 class nsPrintData {
 public:
-
   typedef enum {eIsPrinting, eIsPrintPreview } ePrintDataType;
 
   explicit nsPrintData(ePrintDataType aType);
-  ~nsPrintData(); // non-virtual
+
+  NS_INLINE_DECL_REFCOUNTING(nsPrintData)
 
   // Listener Helper Methods
   void OnEndPrinting();
   void OnStartPrinting();
   void DoOnProgressChange(int32_t      aProgress,
                           int32_t      aMaxProgress,
                           bool         aDoStartStop,
                           int32_t      aFlag);
@@ -88,12 +89,13 @@ public:
   nsPrintPreviewListener*     mPPEventListeners;
 
   char16_t*            mBrandName; //  needed as a substitute name for a document
 
 private:
   nsPrintData() = delete;
   nsPrintData& operator=(const nsPrintData& aOther) = delete;
 
+  ~nsPrintData(); // non-virtual
 };
 
 #endif /* nsPrintData_h___ */
 
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -205,28 +205,28 @@ protected:
 };
 
 NS_IMPL_ISUPPORTS(nsPrintEngine, nsIWebProgressListener,
                   nsISupportsWeakReference, nsIObserver)
 
 //---------------------------------------------------
 //-- nsPrintEngine Class Impl
 //---------------------------------------------------
-nsPrintEngine::nsPrintEngine() :
-  mIsCreatingPrintPreview(false),
-  mIsDoingPrinting(false),
-  mIsDoingPrintPreview(false),
-  mProgressDialogIsShown(false),
-  mScreenDPI(115.0f),
-  mPagePrintTimer(nullptr),
-  mDebugFile(nullptr),
-  mLoadCounter(0),
-  mDidLoadDataForPrinting(false),
-  mIsDestroying(false),
-  mDisallowSelectionPrint(false)
+nsPrintEngine::nsPrintEngine()
+  : mIsCreatingPrintPreview(false)
+  , mIsDoingPrinting(false)
+  , mIsDoingPrintPreview(false)
+  , mProgressDialogIsShown(false)
+  , mScreenDPI(115.0f)
+  , mPagePrintTimer(nullptr)
+  , mDebugFile(nullptr)
+  , mLoadCounter(0)
+  , mDidLoadDataForPrinting(false)
+  , mIsDestroying(false)
+  , mDisallowSelectionPrint(false)
 {
 }
 
 //-------------------------------------------------------
 nsPrintEngine::~nsPrintEngine()
 {
   Destroy(); // for insurance
   DisconnectPagePrintTimer();
@@ -351,18 +351,22 @@ nsPrintEngine::GetSeqFrameAndCountPagesI
   aCount = aSeqFrame->PrincipalChildList().GetLength();
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------
 nsresult nsPrintEngine::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount)
 {
-  NS_ASSERTION(mPrtPreview, "mPrtPreview can't be null!");
-  return GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, aSeqFrame, aCount);
+  MOZ_ASSERT(mPrtPreview);
+  // Guarantee that mPrintPreview->mPrintObject won't be deleted during a call
+  // of GetSeqFrameAndCountPagesInternal().
+  RefPtr<nsPrintData> printDataForPrintPreview = mPrtPreview;
+  return GetSeqFrameAndCountPagesInternal(
+           printDataForPrintPreview->mPrintObject, aSeqFrame, aCount);
 }
 //---------------------------------------------------------------------------------
 //-- Done: Methods needed by the DocViewer
 //---------------------------------------------------------------------------------
 
 
 //---------------------------------------------------------------------------------
 //-- Section: nsIWebBrowserPrint
@@ -426,33 +430,34 @@ nsPrintEngine::DoCommonPrint(bool       
 
     if (mIsDoingPrintPreview) {
       mOldPrtPreview = Move(mPrtPreview);
     }
   } else {
     mProgressDialogIsShown = false;
   }
 
-  mPrt = mozilla::MakeUnique<nsPrintData>(aIsPrintPreview
-                                          ? nsPrintData::eIsPrintPreview
-                                          : nsPrintData::eIsPrinting);
-  NS_ENSURE_TRUE(mPrt, NS_ERROR_OUT_OF_MEMORY);
+  // Grab the new instance with local variable to guarantee that it won't be
+  // deleted during this method.
+  mPrt = new nsPrintData(aIsPrintPreview ? nsPrintData::eIsPrintPreview :
+                                           nsPrintData::eIsPrinting);
+  RefPtr<nsPrintData> printData = mPrt;
 
   // if they don't pass in a PrintSettings, then get the Global PS
-  mPrt->mPrintSettings = aPrintSettings;
-  if (!mPrt->mPrintSettings) {
-    rv = GetGlobalPrintSettings(getter_AddRefs(mPrt->mPrintSettings));
+  printData->mPrintSettings = aPrintSettings;
+  if (!printData->mPrintSettings) {
+    rv = GetGlobalPrintSettings(getter_AddRefs(printData->mPrintSettings));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  rv = CheckForPrinters(mPrt->mPrintSettings);
+  rv = CheckForPrinters(printData->mPrintSettings);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mPrt->mPrintSettings->SetIsCancelled(false);
-  mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
+  printData->mPrintSettings->SetIsCancelled(false);
+  printData->mPrintSettings->GetShrinkToFit(&printData->mShrinkToFit);
 
   if (aIsPrintPreview) {
     SetIsCreatingPrintPreview(true);
     SetIsPrintPreview(true);
     nsCOMPtr<nsIContentViewer> viewer =
       do_QueryInterface(mDocViewerPrint);
     if (viewer) {
       viewer->SetTextZoom(1.0f);
@@ -464,103 +469,109 @@ nsPrintEngine::DoCommonPrint(bool       
   // Create a print session and let the print settings know about it.
   // Don't overwrite an existing print session.
   // The print settings hold an nsWeakPtr to the session so it does not
   // need to be cleared from the settings at the end of the job.
   // XXX What lifetime does the printSession need to have?
   nsCOMPtr<nsIPrintSession> printSession;
   bool remotePrintJobListening = false;
   if (!aIsPrintPreview) {
-    rv = mPrt->mPrintSettings->GetPrintSession(getter_AddRefs(printSession));
+    rv = printData->mPrintSettings->GetPrintSession(
+                                      getter_AddRefs(printSession));
     if (NS_FAILED(rv) || !printSession) {
       printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
       NS_ENSURE_SUCCESS(rv, rv);
-      mPrt->mPrintSettings->SetPrintSession(printSession);
+      printData->mPrintSettings->SetPrintSession(printSession);
     } else {
       RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
       printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
       if (NS_SUCCEEDED(rv) && remotePrintJob) {
         // If we have a RemotePrintJob add it to the print progress listeners,
         // so it can forward to the parent.
-        mPrt->mPrintProgressListeners.AppendElement(remotePrintJob);
+        printData->mPrintProgressListeners.AppendElement(remotePrintJob);
         remotePrintJobListening = true;
       }
     }
 
   }
 
   if (aWebProgressListener != nullptr) {
-    mPrt->mPrintProgressListeners.AppendObject(aWebProgressListener);
+    printData->mPrintProgressListeners.AppendObject(aWebProgressListener);
   }
 
   // Get the currently focused window and cache it
   // because the Print Dialog will "steal" focus and later when you try
   // to get the currently focused windows it will be nullptr
-  mPrt->mCurrentFocusWin = FindFocusedDOMWindow();
+  printData->mCurrentFocusWin = FindFocusedDOMWindow();
 
   // Check to see if there is a "regular" selection
-  bool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin);
+  bool isSelection = IsThereARangeSelection(printData->mCurrentFocusWin);
 
   // Get the docshell for this documentviewer
   nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
   {
     if (aIsPrintPreview) {
       nsCOMPtr<nsIContentViewer> viewer;
       webContainer->GetContentViewer(getter_AddRefs(viewer));
       if (viewer && viewer->GetDocument() && viewer->GetDocument()->IsShowing()) {
         viewer->GetDocument()->OnPageHide(false, nullptr);
       }
     }
 
     nsAutoScriptBlocker scriptBlocker;
-    mPrt->mPrintObject = MakeUnique<nsPrintObject>();
-    rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
+    printData->mPrintObject = MakeUnique<nsPrintObject>();
+    rv = printData->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject.get()),
+    NS_ENSURE_TRUE(printData->mPrintDocList.AppendElement(
+                                              printData->mPrintObject.get()),
                    NS_ERROR_OUT_OF_MEMORY);
 
-    mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
-    mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc;
+    printData->mIsParentAFrameSet = IsParentAFrameSet(webContainer);
+    printData->mPrintObject->mFrameType =
+      printData->mIsParentAFrameSet ? eFrameSet : eDoc;
 
     // Build the "tree" of PrintObjects
-    BuildDocTree(mPrt->mPrintObject->mDocShell, &mPrt->mPrintDocList,
-                 mPrt->mPrintObject);
+    BuildDocTree(printData->mPrintObject->mDocShell, &printData->mPrintDocList,
+                 printData->mPrintObject);
   }
 
   if (!aIsPrintPreview) {
     SetIsPrinting(true);
   }
 
   // XXX This isn't really correct...
-  if (!mPrt->mPrintObject->mDocument ||
-      !mPrt->mPrintObject->mDocument->GetRootElement())
+  if (!printData->mPrintObject->mDocument ||
+      !printData->mPrintObject->mDocument->GetRootElement())
     return NS_ERROR_GFX_PRINTER_STARTDOC;
 
   // Create the linkage from the sub-docs back to the content element
   // in the parent document
-  MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject);
-
-  mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, mPrt->mCurrentFocusWin, mPrt->mIsParentAFrameSet);
+  MapContentToWebShells(printData->mPrintObject, printData->mPrintObject);
+
+  printData->mIsIFrameSelected =
+    IsThereAnIFrameSelected(webContainer, printData->mCurrentFocusWin,
+                            printData->mIsParentAFrameSet);
 
   // Setup print options for UI
-  if (mPrt->mIsParentAFrameSet) {
-    if (mPrt->mCurrentFocusWin) {
-      mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
+  if (printData->mIsParentAFrameSet) {
+    if (printData->mCurrentFocusWin) {
+      printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAll);
     } else {
-      mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
+      printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableAsIsAndEach);
     }
   } else {
-    mPrt->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
+    printData->mPrintSettings->SetHowToEnableFrameUI(nsIPrintSettings::kFrameEnableNone);
   }
   // Now determine how to set up the Frame print UI
-  mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB,
-                                        isSelection || mPrt->mIsIFrameSelected);
+  printData->mPrintSettings->SetPrintOptions(
+                               nsIPrintSettings::kEnableSelectionRB,
+                               isSelection || printData->mIsIFrameSelected);
 
   bool printingViaParent = XRE_IsContentProcess() &&
                            Preferences::GetBool("print.print_via_parent");
   nsCOMPtr<nsIDeviceContextSpec> devspec;
   if (printingViaParent) {
     devspec = new nsDeviceContextSpecProxy();
   } else {
     devspec = do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
@@ -569,22 +580,22 @@ nsPrintEngine::DoCommonPrint(bool       
 
   nsScriptSuppressor scriptSuppressor(this);
   // If printing via parent we still call ShowPrintDialog even for print preview
   // because we use that to retrieve the print settings from the printer.
   // The dialog is not shown, but this means we don't need to access the printer
   // driver from the child, which causes sandboxing issues.
   if (!aIsPrintPreview || printingViaParent) {
 #ifdef DEBUG
-    mPrt->mDebugFilePtr = mDebugFile;
+    printData->mDebugFilePtr = mDebugFile;
 #endif
 
     scriptSuppressor.Suppress();
     bool printSilently;
-    mPrt->mPrintSettings->GetPrintSilent(&printSilently);
+    printData->mPrintSettings->GetPrintSilent(&printSilently);
 
     // Check prefs for a default setting as to whether we should print silently
     printSilently =
       Preferences::GetBool("print.always_print_silent", printSilently);
 
     // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
     // This service is for the Print Dialog and the Print Progress Dialog
     // If printing silently or you can't get the service continue on
@@ -603,138 +614,142 @@ nsPrintEngine::DoCommonPrint(bool       
         // Platforms not implementing a given dialog for the service may
         // return NS_ERROR_NOT_IMPLEMENTED or an error code.
         //
         // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
         // Any other error code means we must bail out
         //
         nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
         rv = printPromptService->ShowPrintDialog(domWin, wbp,
-                                                 mPrt->mPrintSettings);
+                                                 printData->mPrintSettings);
         //
         // ShowPrintDialog triggers an event loop which means we can't assume
         // that the state of this->{anything} matches the state we've checked
         // above. Including that a given {thing} is non null.
-        if (!mPrt) {
+        if (NS_WARN_IF(mPrt != printData)) {
           return NS_ERROR_FAILURE;
         }
 
         if (NS_SUCCEEDED(rv)) {
           // since we got the dialog and it worked then make sure we
           // are telling GFX we want to print silent
           printSilently = true;
 
-          if (mPrt->mPrintSettings && !aIsPrintPreview) {
+          if (printData->mPrintSettings && !aIsPrintPreview) {
             // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
-            mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
+            printData->mPrintSettings->GetShrinkToFit(&printData->mShrinkToFit);
 
             // If we haven't already added the RemotePrintJob as a listener,
             // add it now if there is one.
             if (!remotePrintJobListening) {
               RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
               printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
               if (NS_SUCCEEDED(rv) && remotePrintJob) {
-                mPrt->mPrintProgressListeners.AppendElement(remotePrintJob);
+                printData->mPrintProgressListeners.AppendElement(
+                                                     remotePrintJob);
                 remotePrintJobListening = true;
               }
             }
           }
         } else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
           // This means the Dialog service was there,
           // but they choose not to implement this dialog and
           // are looking for default behavior from the toolkit
           rv = NS_OK;
         }
       } else {
         // No dialog service available
         rv = NS_ERROR_NOT_IMPLEMENTED;
       }
     } else {
       // Call any code that requires a run of the event loop.
-      rv = mPrt->mPrintSettings->SetupSilentPrinting();
+      rv = printData->mPrintSettings->SetupSilentPrinting();
     }
     // Check explicitly for abort because it's expected
     if (rv == NS_ERROR_ABORT)
       return rv;
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  rv = devspec->Init(nullptr, mPrt->mPrintSettings, aIsPrintPreview);
+  rv = devspec->Init(nullptr, printData->mPrintSettings, aIsPrintPreview);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mPrt->mPrintDC = new nsDeviceContext();
-  rv = mPrt->mPrintDC->InitForPrinting(devspec);
+  printData->mPrintDC = new nsDeviceContext();
+  rv = printData->mPrintDC->InitForPrinting(devspec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aIsPrintPreview) {
-    mPrt->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
+    printData->mPrintSettings->SetPrintFrameType(nsIPrintSettings::kFramesAsIs);
 
     // override any UI that wants to PrintPreview any selection or page range
     // we want to view every page in PrintPreview each time
-    mPrt->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
+    printData->mPrintSettings->SetPrintRange(nsIPrintSettings::kRangeAllPages);
   } else {
     // Always check and set the print settings first and then fall back
     // onto the PrintService if there isn't a PrintSettings
     //
     // Posiible Usage values:
     //   nsIPrintSettings::kUseInternalDefault
     //   nsIPrintSettings::kUseSettingWhenPossible
     //
     // NOTE: The consts are the same for PrintSettings and PrintSettings
     int16_t printFrameTypeUsage = nsIPrintSettings::kUseSettingWhenPossible;
-    mPrt->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
+    printData->mPrintSettings->GetPrintFrameTypeUsage(&printFrameTypeUsage);
 
     // Ok, see if we are going to use our value and override the default
     if (printFrameTypeUsage == nsIPrintSettings::kUseSettingWhenPossible) {
       // Get the Print Options/Settings PrintFrameType to see what is preferred
       int16_t printFrameType = nsIPrintSettings::kEachFrameSep;
-      mPrt->mPrintSettings->GetPrintFrameType(&printFrameType);
+      printData->mPrintSettings->GetPrintFrameType(&printFrameType);
 
       // Don't let anybody do something stupid like try to set it to
       // kNoFrames when we are printing a FrameSet
       if (printFrameType == nsIPrintSettings::kNoFrames) {
-        mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
-        mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
+        printData->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
+        printData->mPrintSettings->SetPrintFrameType(
+                                     printData->mPrintFrameType);
       } else {
         // First find out from the PrinService what options are available
         // to us for Printing FrameSets
         int16_t howToEnableFrameUI;
-        mPrt->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
+        printData->mPrintSettings->GetHowToEnableFrameUI(&howToEnableFrameUI);
         if (howToEnableFrameUI != nsIPrintSettings::kFrameEnableNone) {
           switch (howToEnableFrameUI) {
           case nsIPrintSettings::kFrameEnableAll:
-            mPrt->mPrintFrameType = printFrameType;
+            printData->mPrintFrameType = printFrameType;
             break;
 
           case nsIPrintSettings::kFrameEnableAsIsAndEach:
             if (printFrameType != nsIPrintSettings::kSelectedFrame) {
-              mPrt->mPrintFrameType = printFrameType;
+              printData->mPrintFrameType = printFrameType;
             } else { // revert back to a good value
-              mPrt->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
+              printData->mPrintFrameType = nsIPrintSettings::kEachFrameSep;
             }
             break;
           } // switch
-          mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
+          printData->mPrintSettings->SetPrintFrameType(
+                                       printData->mPrintFrameType);
         }
       }
     } else {
-      mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
+      printData->mPrintSettings->GetPrintFrameType(&printData->mPrintFrameType);
     }
   }
 
-  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
-    CheckForChildFrameSets(mPrt->mPrintObject);
+  if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
+    CheckForChildFrameSets(printData->mPrintObject);
   }
 
   if (NS_FAILED(EnablePOsForPrinting())) {
     return NS_ERROR_FAILURE;
   }
 
   // Attach progressListener to catch network requests.
-  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
+  nsCOMPtr<nsIWebProgress> webProgress =
+    do_QueryInterface(printData->mPrintObject->mDocShell);
   webProgress->AddProgressListener(
     static_cast<nsIWebProgressListener*>(this),
     nsIWebProgress::NOTIFY_STATE_REQUEST);
 
   mLoadCounter = 0;
   mDidLoadDataForPrinting = false;
 
   if (aIsPrintPreview) {
@@ -750,17 +765,17 @@ nsPrintEngine::DoCommonPrint(bool       
     } else {
       rv = NS_OK;
     }
   } else {
     bool doNotify;
     ShowPrintProgress(true, doNotify);
     if (!doNotify) {
       // Print listener setup...
-      mPrt->OnStartPrinting();
+      printData->OnStartPrinting();
 
       rv = InitPrintDocConstruction(false);
     }
   }
 
   // We will enable scripting later after printing has finished.
   scriptSuppressor.Disconnect();
 
@@ -861,29 +876,29 @@ nsPrintEngine::GetIsFramesetFrameSelecte
 }
 
 //----------------------------------------------------------------------------------
 NS_IMETHODIMP
 nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
 {
   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
 
-  nsPrintData* prt = nullptr;
   nsIFrame* seqFrame  = nullptr;
   *aPrintPreviewNumPages = 0;
 
   // When calling this function, the FinishPrintPreview() function might not
   // been called as there are still some
-  if (mPrtPreview) {
-    prt = mPrtPreview.get();
-  } else {
-    prt = mPrt.get();
+  RefPtr<nsPrintData> printData = mPrtPreview ? mPrtPreview : mPrt;
+  if (NS_WARN_IF(!printData)) {
+    return NS_ERROR_FAILURE;
   }
-  if ((!prt) ||
-      NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
+  nsresult rv =
+    GetSeqFrameAndCountPagesInternal(printData->mPrintObject, seqFrame,
+                                     *aPrintPreviewNumPages);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 //----------------------------------------------------------------------------------
 // Enumerate all the documents for their titles
 NS_IMETHODIMP
@@ -1031,21 +1046,26 @@ nsPrintEngine::ShowPrintProgress(bool aI
   bool showProgresssDialog = false;
 
   // if it is already being shown then don't bother to find out if it should be
   // so skip this and leave mShowProgressDialog set to FALSE
   if (!mProgressDialogIsShown) {
     showProgresssDialog = Preferences::GetBool("print.show_print_progress");
   }
 
+  // Guarantee that mPrt and the objects it owns won't be deleted.  If this
+  // method shows a progress dialog and spins the event loop.  So, mPrt may be
+  // cleared or recreated.
+  RefPtr<nsPrintData> printData = mPrt;
+
   // Turning off the showing of Print Progress in Prefs overrides
   // whether the calling PS desire to have it on or off, so only check PS if
   // prefs says it's ok to be on.
   if (showProgresssDialog) {
-    mPrt->mPrintSettings->GetShowPrintProgress(&showProgresssDialog);
+    printData->mPrintSettings->GetShowPrintProgress(&showProgresssDialog);
   }
 
   // Now open the service to get the progress dialog
   // If we don't get a service, that's ok, then just don't show progress
   if (showProgresssDialog) {
     nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
     if (printPromptService) {
       nsPIDOMWindowOuter* domWin = mDocument->GetWindow();
@@ -1063,27 +1083,32 @@ nsPrintEngine::ShowPrintProgress(bool aI
         // Showing a print progress dialog when printing a modal window
         // isn't supported. See bug 301560.
         return;
       }
 
       nsCOMPtr<nsIWebProgressListener> printProgressListener;
 
       nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
-      nsresult rv = printPromptService->ShowProgress(domWin, wbp, mPrt->mPrintSettings, this, aIsForPrinting,
-                                                     getter_AddRefs(printProgressListener),
-                                                     getter_AddRefs(mPrt->mPrintProgressParams),
-                                                     &aDoNotify);
+      nsresult rv =
+        printPromptService->ShowProgress(
+                              domWin, wbp, printData->mPrintSettings, this,
+                              aIsForPrinting,
+                              getter_AddRefs(printProgressListener),
+                              getter_AddRefs(printData->mPrintProgressParams),
+                              &aDoNotify);
       if (NS_SUCCEEDED(rv)) {
         if (printProgressListener) {
-          mPrt->mPrintProgressListeners.AppendObject(printProgressListener);
+          printData->mPrintProgressListeners.AppendObject(
+                                               printProgressListener);
         }
 
-        if (mPrt->mPrintProgressParams) {
-          SetDocAndURLIntoProgress(mPrt->mPrintObject, mPrt->mPrintProgressParams);
+        if (printData->mPrintProgressParams) {
+          SetDocAndURLIntoProgress(printData->mPrintObject,
+                                   printData->mPrintProgressParams);
         }
       }
     }
   }
 }
 
 //---------------------------------------------------------------------
 bool
@@ -1477,17 +1502,20 @@ nsPrintEngine::GetDisplayTitleAndURL(con
     }
   }
 }
 
 //---------------------------------------------------------------------
 nsresult nsPrintEngine::DocumentReadyForPrinting()
 {
   if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
-    CheckForChildFrameSets(mPrt->mPrintObject);
+    // Guarantee that mPrt->mPrintObject won't be deleted during a call of
+    // CheckForChildFrameSets().
+    RefPtr<nsPrintData> printData = mPrt;
+    CheckForChildFrameSets(printData->mPrintObject);
   }
 
   //
   // Send the document to the printer...
   //
   nsresult rv = SetupToPrintContent();
   if (NS_FAILED(rv)) {
     // The print job was canceled or there was a problem
@@ -1560,56 +1588,73 @@ nsPrintEngine::FirePrintingErrorEvent(ns
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(doc, event);
   asyncDispatcher->mOnlyChromeDispatch = true;
   asyncDispatcher->RunDOMEventWhenSafe();
 
   // Inform any progress listeners of the Error.
   if (mPrt) {
-    mPrt->DoOnStatusChange(aPrintError);
+    // Note that nsPrintData::DoOnStatusChange() will call some listeners.
+    // So, mPrt can be cleared or recreated.
+    RefPtr<nsPrintData> printData = mPrt;
+    printData->DoOnStatusChange(aPrintError);
   }
 }
 
 //-----------------------------------------------------------------
 //-- Section: Reflow Methods
 //-----------------------------------------------------------------
 
 nsresult
 nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
 {
+  if (NS_WARN_IF(!mPrt)) {
+    return NS_ERROR_FAILURE;
+  }
+
 #if defined(XP_WIN) && defined(EXTENDED_DEBUG_PRINTING)
   // We need to clear all the output files here
   // because they will be re-created with second reflow of the docs
   if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
     RemoveFilesInDir(".\\");
     gDumpFileNameCnt   = 0;
     gDumpLOFileNameCnt = 0;
   }
 #endif
 
-  for (uint32_t i = 0; i < mPrt->mPrintDocList.Length(); ++i) {
-    nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
+  // In this loop, it's conceivable that one of our helpers might clear mPrt,
+  // while we're using it & its members!  So we capture it in an owning local
+  // reference & use that instead of using mPrt directly.
+  RefPtr<nsPrintData> printData = mPrt;
+  for (uint32_t i = 0; i < printData->mPrintDocList.Length(); ++i) {
+    nsPrintObject* po = printData->mPrintDocList.ElementAt(i);
     NS_ASSERTION(po, "nsPrintObject can't be null!");
 
     if (po->mDontPrint || po->mInvisible) {
       continue;
     }
 
     UpdateZoomRatio(po, doSetPixelScale);
 
     po->mPresContext->SetPageScale(po->mZoomRatio);
 
     // Calculate scale factor from printer to screen
-    float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
-                     float(mPrt->mPrintDC->AppUnitsPerDevPixel());
+    float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) /
+                       float(printData->mPrintDC->AppUnitsPerDevPixel());
     po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
 
     po->mPresShell->ReconstructFrames();
 
+    // If the printing was canceled or restarted with different data,
+    // let's stop doing this printing.
+    if (NS_WARN_IF(mPrt != printData)) {
+      return NS_ERROR_FAILURE;
+    }
+
     // For all views except the first one, setup the root view.
     // ??? Can there be multiple po for the top-level-document?
     bool documentIsTopLevel = true;
     if (i != 0) {
       nsSize adjSize;
       bool doReturn;
       nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize);
 
@@ -1617,161 +1662,203 @@ nsPrintEngine::ReconstructAndReflow(bool
 
       if (NS_FAILED(rv) || doReturn) {
         return rv;
       }
     }
 
     po->mPresShell->FlushPendingNotifications(FlushType::Layout);
 
+    // If the printing was canceled or restarted with different data,
+    // let's stop doing this printing.
+    if (NS_WARN_IF(mPrt != printData)) {
+      return NS_ERROR_FAILURE;
+    }
+
     nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 //-------------------------------------------------------
 nsresult
 nsPrintEngine::SetupToPrintContent()
 {
-  nsresult rv;
+  if (NS_WARN_IF(!mPrt)) {
+    return NS_ERROR_FAILURE;
+  }
 
   bool didReconstruction = false;
 
+  // This method works with mPrt->mPrintObject.  So, we need to guarantee that
+  // it won't be deleted in this method.  We achieve this by holding a strong
+  // local reference to mPrt, which in turn keeps mPrintObject alive.
+  RefPtr<nsPrintData> printData = mPrt;
+
   // If some new content got loaded since the initial reflow rebuild
   // everything.
   if (mDidLoadDataForPrinting) {
-    rv = ReconstructAndReflow(DoSetPixelScale());
+    nsresult rv = ReconstructAndReflow(DoSetPixelScale());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    // If the printing was canceled or restarted with different data,
+    // let's stop doing this printing.
+    if (NS_WARN_IF(mPrt != printData)) {
+      return NS_ERROR_FAILURE;
+    }
     didReconstruction = true;
-    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Here is where we figure out if extra reflow for shrinking the content
   // is required.
   // But skip this step if we are in PrintPreview
   bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
-  if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
+  if (printData->mShrinkToFit && !ppIsShrinkToFit) {
     // Now look for the PO that has the smallest percent for shrink to fit
-    if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
+    if (printData->mPrintDocList.Length() > 1 &&
+        printData->mPrintObject->mFrameType == eFrameSet) {
       nsPrintObject* smallestPO = FindSmallestSTF();
       NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
       if (smallestPO) {
         // Calc the shrinkage based on the entire content area
-        mPrt->mShrinkRatio = smallestPO->mShrinkRatio;
+        printData->mShrinkRatio = smallestPO->mShrinkRatio;
       }
     } else {
       // Single document so use the Shrink as calculated for the PO
-      mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
+      printData->mShrinkRatio = printData->mPrintObject->mShrinkRatio;
     }
 
-    if (mPrt->mShrinkRatio < 0.998f) {
-      rv = ReconstructAndReflow(true);
+    if (printData->mShrinkRatio < 0.998f) {
+      nsresult rv = ReconstructAndReflow(true);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      // If the printing was canceled or restarted with different data,
+      // let's stop doing this printing.
+      if (NS_WARN_IF(mPrt != printData)) {
+        return NS_ERROR_FAILURE;
+      }
       didReconstruction = true;
-      NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (MOZ_LOG_TEST(gPrintingLog, LogLevel::Debug)) {
       float calcRatio = 0.0f;
-      if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
+      if (printData->mPrintDocList.Length() > 1 &&
+          printData->mPrintObject->mFrameType == eFrameSet) {
         nsPrintObject* smallestPO = FindSmallestSTF();
         NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
         if (smallestPO) {
           // Calc the shrinkage based on the entire content area
           calcRatio = smallestPO->mShrinkRatio;
         }
       } else {
         // Single document so use the Shrink as calculated for the PO
-        calcRatio = mPrt->mPrintObject->mShrinkRatio;
+        calcRatio = printData->mPrintObject->mShrinkRatio;
       }
       PR_PL(("**************************************************************************\n"));
-      PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio,  mPrt->mShrinkRatio-calcRatio));
+      PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n",
+             printData->mShrinkRatio, calcRatio,
+             printData->mShrinkRatio-calcRatio));
       PR_PL(("**************************************************************************\n"));
     }
   }
 
   // If the frames got reconstructed and reflowed the number of pages might
   // has changed.
   if (didReconstruction) {
     FirePrintPreviewUpdateEvent();
+    // If the printing was canceled or restarted with different data,
+    // let's stop doing this printing.
+    if (NS_WARN_IF(mPrt != printData)) {
+      return NS_ERROR_FAILURE;
+    }
   }
 
   DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
   PR_PL(("\n"));
   PR_PL(("-------------------------------------------------------\n"));
   PR_PL(("\n"));
 
-  CalcNumPrintablePages(mPrt->mNumPrintablePages);
-
-  PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
+  CalcNumPrintablePages(printData->mNumPrintablePages);
+
+  PR_PL(("--- Printing %d pages\n", printData->mNumPrintablePages));
   DUMP_DOC_TREELAYOUT;
 
   // Print listener setup...
-  if (mPrt != nullptr) {
-    mPrt->OnStartPrinting();
+  printData->OnStartPrinting();
+
+  // If the printing was canceled or restarted with different data,
+  // let's stop doing this printing.
+  if (NS_WARN_IF(mPrt != printData)) {
+    return NS_ERROR_FAILURE;
   }
 
   nsAutoString fileNameStr;
   // check to see if we are printing to a file
   bool isPrintToFile = false;
-  mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
+  printData->mPrintSettings->GetPrintToFile(&isPrintToFile);
   if (isPrintToFile) {
     // On some platforms The BeginDocument needs to know the name of the file.
     char16_t* fileName = nullptr;
-    mPrt->mPrintSettings->GetToFileName(&fileName);
+    printData->mPrintSettings->GetToFileName(&fileName);
     fileNameStr = fileName;
   }
 
   nsAutoString docTitleStr;
   nsAutoString docURLStr;
-  GetDisplayTitleAndURL(mPrt->mPrintObject, docTitleStr, docURLStr, eDocTitleDefURLDoc);
+  GetDisplayTitleAndURL(printData->mPrintObject, docTitleStr, docURLStr,
+                        eDocTitleDefURLDoc);
 
   int32_t startPage = 1;
-  int32_t endPage   = mPrt->mNumPrintablePages;
+  int32_t endPage = printData->mNumPrintablePages;
 
   int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
-  mPrt->mPrintSettings->GetPrintRange(&printRangeType);
+  printData->mPrintSettings->GetPrintRange(&printRangeType);
   if (printRangeType == nsIPrintSettings::kRangeSpecifiedPageRange) {
-    mPrt->mPrintSettings->GetStartPageRange(&startPage);
-    mPrt->mPrintSettings->GetEndPageRange(&endPage);
-    if (endPage > mPrt->mNumPrintablePages) {
-      endPage = mPrt->mNumPrintablePages;
+    printData->mPrintSettings->GetStartPageRange(&startPage);
+    printData->mPrintSettings->GetEndPageRange(&endPage);
+    if (endPage > printData->mNumPrintablePages) {
+      endPage = printData->mNumPrintablePages;
     }
   }
 
-  rv = NS_OK;
+  nsresult rv = NS_OK;
   // BeginDocument may pass back a FAILURE code
   // i.e. On Windows, if you are printing to a file and hit "Cancel"
   //      to the "File Name" dialog, this comes back as an error
   // Don't start printing when regression test are executed
-  if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
-    rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileNameStr, startPage,
-                                       endPage);
+  if (!printData->mDebugFilePtr && mIsDoingPrinting) {
+    rv = printData->mPrintDC->BeginDocument(docTitleStr, fileNameStr, startPage,
+                                            endPage);
   }
 
   if (mIsCreatingPrintPreview) {
     // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed
     // in the header
-    nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame();
+    nsIPageSequenceFrame* seqFrame =
+      printData->mPrintObject->mPresShell->GetPageSequenceFrame();
     if (seqFrame) {
-      seqFrame->StartPrint(mPrt->mPrintObject->mPresContext,
-                           mPrt->mPrintSettings, docTitleStr, docURLStr);
+      seqFrame->StartPrint(printData->mPrintObject->mPresContext,
+                           printData->mPrintSettings, docTitleStr, docURLStr);
     }
   }
 
   PR_PL(("****************** Begin Document ************************\n"));
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // This will print the docshell document
   // when it completes asynchronously in the DonePrintingPages method
   // it will check to see if there are more docshells to be printed and
   // then PrintDocContent will be called again.
 
   if (mIsDoingPrinting) {
-    PrintDocContent(mPrt->mPrintObject, rv); // ignore return value
+    PrintDocContent(printData->mPrintObject, rv); // ignore return value
   }
 
   return rv;
 }
 
 //-------------------------------------------------------
 // Recursively reflow each sub-doc and then calc
 // all the frame locations of the sub-docs
@@ -1817,17 +1904,20 @@ nsPrintEngine::FirePrintPreviewUpdateEve
     )->RunDOMEventWhenSafe();
   }
 }
 
 nsresult
 nsPrintEngine::InitPrintDocConstruction(bool aHandleError)
 {
   nsresult rv;
-  rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale());
+  // Guarantee that mPrt->mPrintObject won't be deleted.  It's owned by mPrt.
+  // So, we should grab it with local variable.
+  RefPtr<nsPrintData> printData = mPrt;
+  rv = ReflowDocList(printData->mPrintObject, DoSetPixelScale());
   NS_ENSURE_SUCCESS(rv, rv);
 
   FirePrintPreviewUpdateEvent();
 
   if (mLoadCounter == 0) {
     AfterNetworkPrint(aHandleError);
   }
   return rv;
@@ -2111,42 +2201,47 @@ nsPrintEngine::ReflowPrintObject(const U
   NS_ENSURE_STATE(aPO);
 
   if (!aPO->IsPrintable()) {
     return NS_OK;
   }
 
   NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
 
+  // Guarantee that mPrt and the objects it owns won't be deleted in this method
+  // because it might be cleared if other modules called from here may fire
+  // events, notifying observers and/or listeners.
+  RefPtr<nsPrintData> printData = mPrt;
+
   // create the PresContext
   nsPresContext::nsPresContextType type =
       mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
                                 nsPresContext::eContext_Print;
   nsView* parentView =
     aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot();
   aPO->mPresContext = parentView ?
       new nsPresContext(aPO->mDocument, type) :
       new nsRootPresContext(aPO->mDocument, type);
   NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
-  aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
+  aPO->mPresContext->SetPrintSettings(printData->mPrintSettings);
 
   // set the presentation context to the value in the print settings
   bool printBGColors;
-  mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
+  printData->mPrintSettings->GetPrintBGColors(&printBGColors);
   aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
-  mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
+  printData->mPrintSettings->GetPrintBGImages(&printBGColors);
   aPO->mPresContext->SetBackgroundImageDraw(printBGColors);
 
   // init it with the DC
-  nsresult rv = aPO->mPresContext->Init(mPrt->mPrintDC);
+  nsresult rv = aPO->mPresContext->Init(printData->mPrintDC);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aPO->mViewManager = new nsViewManager();
 
-  rv = aPO->mViewManager->Init(mPrt->mPrintDC);
+  rv = aPO->mViewManager->Init(printData->mPrintDC);
   NS_ENSURE_SUCCESS(rv,rv);
 
   StyleSetHandle styleSet = mDocViewerPrint->CreateStyleSet(aPO->mDocument);
 
   aPO->mPresShell = aPO->mDocument->CreateShell(aPO->mPresContext,
                                                 aPO->mViewManager, styleSet);
   if (!aPO->mPresShell) {
     styleSet->Delete();
@@ -2178,18 +2273,18 @@ nsPrintEngine::ReflowPrintObject(const U
   aPO->mPresContext->SetContainer(aPO->mDocShell);
 
   aPO->mPresShell->BeginObservingDocument();
 
   aPO->mPresContext->SetPageSize(adjSize);
   aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
   aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
   // Calculate scale factor from printer to screen
-  float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
-                   float(mPrt->mPrintDC->AppUnitsPerDevPixel());
+  float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) /
+                     float(printData->mPrintDC->AppUnitsPerDevPixel());
   aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
 
   if (mIsCreatingPrintPreview && documentIsTopLevel) {
     mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager,
                                                  aPO->mPresContext,
                                                  aPO->mPresShell);
   }
 
@@ -2215,17 +2310,17 @@ nsPrintEngine::ReflowPrintObject(const U
       FILE * fd = fopen(filename, "w");
       if (fd) {
         nsIFrame *theRootFrame =
           aPO->mPresShell->FrameManager()->GetRootFrame();
         fprintf(fd, "Title: %s\n", docStr.get());
         fprintf(fd, "URL:   %s\n", urlStr.get());
         fprintf(fd, "--------------- Frames ----------------\n");
         //RefPtr<gfxContext> renderingContext =
-        //  mPrt->mPrintDocDC->CreateRenderingContext();
+        //  printData->mPrintDocDC->CreateRenderingContext();
         RootFrameList(aPO->mPresContext, fd, 0);
         //DumpFrames(fd, aPO->mPresContext, renderingContext, theRootFrame, 0);
         fprintf(fd, "---------------------------------------\n\n");
         fprintf(fd, "--------------- Views From Root Frame----------------\n");
         nsView* v = theRootFrame->GetView();
         if (v) {
           v->List(fd);
         } else {
@@ -2396,55 +2491,62 @@ nsPrintEngine::DoPrint(const UniquePtr<n
 
   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?");
 
-  if (mPrt->mPrintProgressParams) {
-    SetDocAndURLIntoProgress(aPO, mPrt->mPrintProgressParams);
+  // Guarantee that mPrt and the objects it owns won't be deleted in this method
+  // because it might be cleared if other modules called from here may fire
+  // events, notifying observers and/or listeners.
+  RefPtr<nsPrintData> printData = mPrt;
+
+  if (printData->mPrintProgressParams) {
+    SetDocAndURLIntoProgress(aPO, printData->mPrintProgressParams);
   }
 
   {
     int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
     nsresult rv;
-    if (mPrt->mPrintSettings != nullptr) {
-      mPrt->mPrintSettings->GetPrintRange(&printRangeType);
+    if (printData->mPrintSettings) {
+      printData->mPrintSettings->GetPrintRange(&printRangeType);
     }
 
     // Ask the page sequence frame to print all the pages
     nsIPageSequenceFrame* pageSequence = poPresShell->GetPageSequenceFrame();
     NS_ASSERTION(nullptr != pageSequence, "no page sequence frame");
 
     // We are done preparing for printing, so we can turn this off
-    mPrt->mPreparingForPrint = false;
-
-    // mPrt->mDebugFilePtr this is onlu non-null when compiled for debugging
-    if (nullptr != mPrt->mDebugFilePtr) {
+    printData->mPreparingForPrint = false;
+
+    // printData->mDebugFilePtr this is onlu non-null when compiled for
+    // debugging
+    if (printData->mDebugFilePtr) {
 #ifdef DEBUG
       // output the regression test
       nsIFrame* root = poPresShell->FrameManager()->GetRootFrame();
-      root->DumpRegressionData(poPresContext, mPrt->mDebugFilePtr, 0);
-      fclose(mPrt->mDebugFilePtr);
+      root->DumpRegressionData(poPresContext, printData->mDebugFilePtr, 0);
+      fclose(printData->mDebugFilePtr);
       SetIsPrinting(false);
 #endif
     } else {
 #ifdef EXTENDED_DEBUG_PRINTING
       nsIFrame* rootFrame = poPresShell->FrameManager()->GetRootFrame();
       if (aPO->IsPrintable()) {
         nsAutoCString docStr;
         nsAutoCString urlStr;
         GetDocTitleAndURL(aPO, docStr, urlStr);
-        DumpLayoutData(docStr.get(), urlStr.get(), poPresContext, mPrt->mPrintDocDC, rootFrame, docShell, nullptr);
+        DumpLayoutData(docStr.get(), urlStr.get(), poPresContext,
+                       printData->mPrintDocDC, rootFrame, docShell, nullptr);
       }
 #endif
 
-      if (!mPrt->mPrintSettings) {
+      if (!printData->mPrintSettings) {
         // not sure what to do here!
         SetIsPrinting(false);
         return NS_ERROR_FAILURE;
       }
 
       nsAutoString docTitleStr;
       nsAutoString docURLStr;
       GetDisplayTitleAndURL(aPO, docTitleStr, docURLStr, eDocTitleDefBlank);
@@ -2465,22 +2567,23 @@ nsPrintEngine::DoPrint(const UniquePtr<n
         int32_t   endPageNum;
         nsRect    startRect;
         nsRect    endRect;
 
         rv = GetPageRangeForSelection(pageSequence,
                                       &startFrame, startPageNum, startRect,
                                       &endFrame, endPageNum, endRect);
         if (NS_SUCCEEDED(rv)) {
-          mPrt->mPrintSettings->SetStartPageRange(startPageNum);
-          mPrt->mPrintSettings->SetEndPageRange(endPageNum);
+          printData->mPrintSettings->SetStartPageRange(startPageNum);
+          printData->mPrintSettings->SetEndPageRange(endPageNum);
           nsIntMargin marginTwips(0,0,0,0);
           nsIntMargin unwrtMarginTwips(0,0,0,0);
-          mPrt->mPrintSettings->GetMarginInTwips(marginTwips);
-          mPrt->mPrintSettings->GetUnwriteableMarginInTwips(unwrtMarginTwips);
+          printData->mPrintSettings->GetMarginInTwips(marginTwips);
+          printData->mPrintSettings->GetUnwriteableMarginInTwips(
+                                       unwrtMarginTwips);
           nsMargin totalMargin = poPresContext->CSSTwipsToAppUnits(marginTwips +
                                                                    unwrtMarginTwips);
           if (startPageNum == endPageNum) {
             startRect.y -= totalMargin.top;
             endRect.y   -= totalMargin.top;
 
             // Clip out selection regions above the top of the first page
             if (startRect.y < 0) {
@@ -2505,32 +2608,34 @@ nsPrintEngine::DoPrint(const UniquePtr<n
             nscoord selectionHgt = endRect.y + endRect.height - startRect.y;
             // XXX This is temporary fix for printing more than one page of a selection
             pageSequence->SetSelectionHeight(startRect.y * aPO->mZoomRatio,
                                              selectionHgt * aPO->mZoomRatio);
 
             // calc total pages by getting calculating the selection's height
             // and then dividing it by how page content frames will fit.
             nscoord pageWidth, pageHeight;
-            mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
+            printData->mPrintDC->GetDeviceSurfaceDimensions(pageWidth,
+                                                            pageHeight);
             pageHeight -= totalMargin.top + totalMargin.bottom;
             int32_t totalPages = NSToIntCeil(float(selectionHgt) * aPO->mZoomRatio / float(pageHeight));
             pageSequence->SetTotalNumPages(totalPages);
           }
         }
       }
 
       nsIFrame * seqFrame = do_QueryFrame(pageSequence);
       if (!seqFrame) {
         SetIsPrinting(false);
         return NS_ERROR_FAILURE;
       }
 
       mPageSeqFrame = seqFrame;
-      pageSequence->StartPrint(poPresContext, mPrt->mPrintSettings, docTitleStr, docURLStr);
+      pageSequence->StartPrint(poPresContext, printData->mPrintSettings,
+                               docTitleStr, docURLStr);
 
       // Schedule Page to Print
       PR_PL(("Scheduling Print of PO: %p (%s) \n", aPO.get(), gFrameTypesStr[aPO->mFrameType]));
       StartPagePrintTimer(aPO);
     }
   }
 
   return NS_OK;
@@ -2639,35 +2744,39 @@ nsPrintEngine::PrePrintPage()
   NS_ASSERTION(mPrt,           "mPrt is null!");
 
   // Although these should NEVER be nullptr
   // This is added insurance, to make sure we don't crash in optimized builds
   if (!mPrt || !mPageSeqFrame.IsAlive()) {
     return true; // means we are done preparing the page.
   }
 
+  // Guarantee that mPrt won't be deleted during a call of
+  // FirePrintingErrorEvent().
+  RefPtr<nsPrintData> printData = mPrt;
+
   // Check setting to see if someone request it be cancelled
   bool isCancelled = false;
-  mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
+  printData->mPrintSettings->GetIsCancelled(&isCancelled);
   if (isCancelled)
     return true;
 
   // Ask mPageSeqFrame if the page is ready to be printed.
   // If the page doesn't get printed at all, the |done| will be |true|.
   bool done = false;
   nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame());
   nsresult rv = pageSeqFrame->PrePrintNextPage(mPagePrintTimer, &done);
   if (NS_FAILED(rv)) {
-    // ??? ::PrintPage doesn't set |mPrt->mIsAborted = true| if rv != NS_ERROR_ABORT,
-    // but I don't really understand why this should be the right thing to do?
-    // Shouldn't |mPrt->mIsAborted| set to true all the time if something
-    // wents wrong?
+    // ??? ::PrintPage doesn't set |printData->mIsAborted = true| if
+    // rv != NS_ERROR_ABORT, but I don't really understand why this should be
+    // the right thing to do?  Shouldn't |printData->mIsAborted| set to true
+    // all the time if something went wrong?
     if (rv != NS_ERROR_ABORT) {
       FirePrintingErrorEvent(rv);
-      mPrt->mIsAborted = true;
+      printData->mIsAborted = true;
     }
     done = true;
   }
   return done;
 }
 
 bool
 nsPrintEngine::PrintPage(nsPrintObject*    aPO,
@@ -2679,24 +2788,30 @@ nsPrintEngine::PrintPage(nsPrintObject* 
 
   // Although these should NEVER be nullptr
   // This is added insurance, to make sure we don't crash in optimized builds
   if (!mPrt || !aPO || !mPageSeqFrame.IsAlive()) {
     FirePrintingErrorEvent(NS_ERROR_FAILURE);
     return true; // means we are done printing
   }
 
+  // Guarantee that mPrt won't be deleted during a call of
+  // nsPrintData::DoOnProgressChange() which runs some listeners,
+  // which may clear (& might otherwise destroy).
+  RefPtr<nsPrintData> printData = mPrt;
+
   PR_PL(("-----------------------------------\n"));
   PR_PL(("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]));
 
   // Check setting to see if someone request it be cancelled
   bool isCancelled = false;
-  mPrt->mPrintSettings->GetIsCancelled(&isCancelled);
-  if (isCancelled || mPrt->mIsAborted)
+  printData->mPrintSettings->GetIsCancelled(&isCancelled);
+  if (isCancelled || printData->mIsAborted) {
     return true;
+  }
 
   int32_t pageNum, numPages, endPage;
   nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame());
   pageSeqFrame->GetCurrentPageNum(&pageNum);
   pageSeqFrame->GetNumPages(&numPages);
 
   bool donePrinting;
   bool isDoingPrintRange;
@@ -2723,33 +2838,40 @@ nsPrintEngine::PrintPage(nsPrintObject* 
 
     donePrinting = pageNum >= numPages;
     endPage = numPages;
     aInRange = true;
   }
 
   // XXX This is wrong, but the actual behavior in the presence of a print
   // range sucks.
-  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep)
-    endPage = mPrt->mNumPrintablePages;
-
-  mPrt->DoOnProgressChange(++mPrt->mNumPagesPrinted, endPage, false, 0);
+  if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
+    endPage = printData->mNumPrintablePages;
+  }
+
+  printData->DoOnProgressChange(++printData->mNumPagesPrinted,
+                                endPage, false, 0);
+  if (NS_WARN_IF(mPrt != printData)) {
+    // If current printing is canceled or new print is started, let's return
+    // true to notify the caller of current printing is done.
+    return true;
+  }
 
   // Print the Page
   // if a print job was cancelled externally, an EndPage or BeginPage may
   // fail and the failure is passed back here.
   // Returning true means we are done printing.
   //
   // When rv == NS_ERROR_ABORT, it means we want out of the
   // print job without displaying any error messages
   nsresult rv = pageSeqFrame->PrintNextPage();
   if (NS_FAILED(rv)) {
     if (rv != NS_ERROR_ABORT) {
       FirePrintingErrorEvent(rv);
-      mPrt->mIsAborted = true;
+      printData->mIsAborted = true;
     }
     return true;
   }
 
   pageSeqFrame->DoPageEnd();
 
   return donePrinting;
 }
@@ -3056,28 +3178,35 @@ nsPrintEngine::DonePrintingPages(nsPrint
   // If there is a pageSeqFrame, make sure there are no more printCanvas active
   // that might call |Notify| on the pagePrintTimer after things are cleaned up
   // and printing was marked as being done.
   if (mPageSeqFrame.IsAlive()) {
     nsIPageSequenceFrame* pageSeqFrame = do_QueryFrame(mPageSeqFrame.GetFrame());
     pageSeqFrame->ResetPrintCanvasList();
   }
 
-  if (aPO && !mPrt->mIsAborted) {
+  // Guarantee that mPrt and mPrt->mPrintObject won't be deleted during a
+  // call of PrintDocContent() and FirePrintCompletionEvent().
+  RefPtr<nsPrintData> printData = mPrt;
+
+  if (aPO && !printData->mIsAborted) {
     aPO->mHasBeenPrinted = true;
     nsresult rv;
-    bool didPrint = PrintDocContent(mPrt->mPrintObject, rv);
+    bool didPrint = PrintDocContent(printData->mPrintObject, rv);
     if (NS_SUCCEEDED(rv) && didPrint) {
       PR_PL(("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)));
       return false;
     }
   }
 
   if (NS_SUCCEEDED(aResult)) {
     FirePrintCompletionEvent();
+    // XXX mPrt may be cleared or replaced with new instance here.
+    //     However, the following methods will clean up with new mPrt or will
+    //     do nothing due to no proper nsPrintData instance.
   }
 
   TurnScriptingOn(true);
   SetIsPrinting(false);
 
   // Release reference to mPagePrintTimer; the timer object destroys itself
   // after this returns true
   DisconnectPagePrintTimer();
@@ -3127,87 +3256,94 @@ nsPrintEngine::FindPrintObjectByDOMWin(n
 
   return nullptr;
 }
 
 //-------------------------------------------------------
 nsresult
 nsPrintEngine::EnablePOsForPrinting()
 {
+  // Guarantee that mPrt and the objects it owns won't be deleted.
+  RefPtr<nsPrintData> printData = mPrt;
+
   // NOTE: All POs have been "turned off" for printing
   // this is where we decided which POs get printed.
-  mPrt->mSelectedPO = nullptr;
-
-  if (mPrt->mPrintSettings == nullptr) {
+  printData->mSelectedPO = nullptr;
+
+  if (!printData->mPrintSettings) {
     return NS_ERROR_FAILURE;
   }
 
-  mPrt->mPrintFrameType = nsIPrintSettings::kNoFrames;
-  mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
+  printData->mPrintFrameType = nsIPrintSettings::kNoFrames;
+  printData->mPrintSettings->GetPrintFrameType(&printData->mPrintFrameType);
 
   int16_t printHowEnable = nsIPrintSettings::kFrameEnableNone;
-  mPrt->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
+  printData->mPrintSettings->GetHowToEnableFrameUI(&printHowEnable);
 
   int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
-  mPrt->mPrintSettings->GetPrintRange(&printRangeType);
+  printData->mPrintSettings->GetPrintRange(&printRangeType);
 
   PR_PL(("\n"));
   PR_PL(("********* nsPrintEngine::EnablePOsForPrinting *********\n"));
-  PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
+  PR_PL(("PrintFrameType:     %s \n",
+         gPrintFrameTypeStr[printData->mPrintFrameType]));
   PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
   PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
   PR_PL(("----\n"));
 
   // ***** This is the ultimate override *****
   // if we are printing the selection (either an IFrame or selection range)
   // then set the mPrintFrameType as if it were the selected frame
   if (printRangeType == nsIPrintSettings::kRangeSelection) {
-    mPrt->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
-    printHowEnable        = nsIPrintSettings::kFrameEnableNone;
+    printData->mPrintFrameType = nsIPrintSettings::kSelectedFrame;
+    printHowEnable = nsIPrintSettings::kFrameEnableNone;
   }
 
   // This tells us that the "Frame" UI has turned off,
   // so therefore there are no FrameSets/Frames/IFrames to be printed
   //
   // 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.get(), true);
+      SetPrintPO(printData->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 (const UniquePtr<nsPrintObject>& po : mPrt->mPrintObject->mKids) {
+      if (printData->mPrintObject->mKids.Length() > 0) {
+        for (const UniquePtr<nsPrintObject>& po :
+               printData->mPrintObject->mKids) {
           NS_ASSERTION(po, "nsPrintObject can't be null!");
           SetPrintAsIs(po.get());
         }
 
         // ***** Another override *****
-        mPrt->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
+        printData->mPrintFrameType = nsIPrintSettings::kFramesAsIs;
       }
-      PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
-      PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
+      PR_PL(("PrintFrameType:     %s \n",
+             gPrintFrameTypeStr[printData->mPrintFrameType]));
+      PR_PL(("HowToEnableFrameUI: %s \n",
+             gFrameHowToEnableStr[printHowEnable]));
       PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
       return NS_OK;
     }
 
     // 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) {
+      if (printData->mCurrentFocusWin) {
         // Find the selected IFrame
-        nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), mPrt->mCurrentFocusWin);
-        if (po != nullptr) {
-          mPrt->mSelectedPO = po;
+        nsPrintObject* po =
+          FindPrintObjectByDOMWin(printData->mPrintObject.get(),
+                                  printData->mCurrentFocusWin);
+        if (po) {
+          printData->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);
 
           // check to see if we have a range selection,
           // as oppose to a insert selection
@@ -3215,89 +3351,98 @@ nsPrintEngine::EnablePOsForPrinting()
           // there will not be a selection so we want the entire page to print
           //
           // XXX this is sort of a hack right here to make the page
           // not try to reposition itself when printing selection
           nsPIDOMWindowOuter* domWin =
             po->mDocument->GetOriginalDocument()->GetWindow();
           if (!IsThereARangeSelection(domWin)) {
             printRangeType = nsIPrintSettings::kRangeAllPages;
-            mPrt->mPrintSettings->SetPrintRange(printRangeType);
+            printData->mPrintSettings->SetPrintRange(printRangeType);
           }
-          PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
-          PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
-          PR_PL(("PrintRange:         %s \n", gPrintRangeStr[printRangeType]));
+          PR_PL(("PrintFrameType:     %s \n",
+                 gPrintFrameTypeStr[printData->mPrintFrameType]));
+          PR_PL(("HowToEnableFrameUI: %s \n",
+                 gFrameHowToEnableStr[printHowEnable]));
+          PR_PL(("PrintRange:         %s \n",
+                 gPrintRangeStr[printRangeType]));
           return NS_OK;
         }
       } else {
-        for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) {
-          nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
+        for (uint32_t i = 0; i < printData->mPrintDocList.Length(); i++) {
+          nsPrintObject* po = printData->mPrintDocList.ElementAt(i);
           NS_ASSERTION(po, "nsPrintObject can't be null!");
           nsCOMPtr<nsPIDOMWindowOuter> domWin = po->mDocShell->GetWindow();
           if (IsThereARangeSelection(domWin)) {
-            mPrt->mCurrentFocusWin = domWin.forget();
+            printData->mCurrentFocusWin = domWin.forget();
             SetPrintPO(po, true);
             break;
           }
         }
         return NS_OK;
       }
     }
   }
 
   // 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) {
+    if (printData->mCurrentFocusWin) {
       // Find the selected IFrame
-      nsPrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject.get(), mPrt->mCurrentFocusWin);
-      if (po != nullptr) {
-        mPrt->mSelectedPO = po;
+      nsPrintObject* po =
+        FindPrintObjectByDOMWin(printData->mPrintObject.get(),
+                                printData->mCurrentFocusWin);
+      if (po) {
+        printData->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);
 
         // check to see if we have a range selection,
         // as oppose to a insert selection
         // this means if the user just clicked on the IFrame then
         // there will not be a selection so we want the entire page to print
         //
         // XXX this is sort of a hack right here to make the page
         // not try to reposition itself when printing selection
         nsCOMPtr<nsPIDOMWindowOuter> domWin = po->mDocument->GetOriginalDocument()->GetWindow();
         if (!IsThereARangeSelection(domWin)) {
           printRangeType = nsIPrintSettings::kRangeAllPages;
-          mPrt->mPrintSettings->SetPrintRange(printRangeType);
+          printData->mPrintSettings->SetPrintRange(printRangeType);
         }
-        PR_PL(("PrintFrameType:     %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]));
-        PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]));
+        PR_PL(("PrintFrameType:     %s \n",
+               gPrintFrameTypeStr[printData->mPrintFrameType]));
+        PR_PL(("HowToEnableFrameUI: %s \n",
+               gFrameHowToEnableStr[printHowEnable]));
         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.get());
-    SetPrintPO(mPrt->mPrintObject.get(), true);
+  if (printData->mPrintFrameType == nsIPrintSettings::kFramesAsIs) {
+    SetPrintAsIs(printData->mPrintObject.get());
+    SetPrintPO(printData->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.get(), mPrt->mCurrentFocusWin);
-      if (po != nullptr) {
-        mPrt->mSelectedPO = po;
+  if (printData->mPrintFrameType == nsIPrintSettings::kSelectedFrame) {
+    if ((printData->mIsParentAFrameSet && printData->mCurrentFocusWin) ||
+        printData->mIsIFrameSelected) {
+      nsPrintObject* po =
+        FindPrintObjectByDOMWin(printData->mPrintObject.get(),
+                                printData->mCurrentFocusWin);
+      if (po) {
+        printData->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);
         }
 
@@ -3305,21 +3450,21 @@ nsPrintEngine::EnablePOsForPrinting()
         SetPrintPO(po, true);
       }
     }
     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.get(), true);
-    int32_t cnt = mPrt->mPrintDocList.Length();
+  if (printData->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
+    SetPrintPO(printData->mPrintObject.get(), true);
+    int32_t cnt = printData->mPrintDocList.Length();
     for (int32_t i=0;i<cnt;i++) {
-      nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
+      nsPrintObject* po = printData->mPrintDocList.ElementAt(i);
       NS_ASSERTION(po, "nsPrintObject can't be null!");
       if (po->mFrameType == eFrameSet) {
         po->mDontPrint = true;
       }
     }
   }
 
   return NS_OK;
@@ -3357,32 +3502,30 @@ nsPrintEngine::TurnScriptingOn(bool aDoT
 {
   if (mIsDoingPrinting && aDoTurnOn && mDocViewerPrint &&
       mDocViewerPrint->GetIsPrintPreview()) {
     // We don't want to turn scripting on if print preview is shown still after
     // printing.
     return;
   }
 
-  nsPrintData* prt = mPrt.get();
-#ifdef NS_PRINT_PREVIEW
-  if (!prt) {
-    prt = mPrtPreview.get();
-  }
-#endif
-  if (!prt) {
+  // The following for loop uses nsPrintObject instances that are owned by
+  // mPrt or mPrtPreview.  Therefore, this method needs to guarantee that
+  // they won't be deleted in this method.
+  RefPtr<nsPrintData> printData = mPrt ? mPrt : mPrtPreview;
+  if (!printData) {
     return;
   }
 
   NS_ASSERTION(mDocument, "We MUST have a document.");
   // First, get the script global object from the document...
 
-  for (uint32_t i=0;i<prt->mPrintDocList.Length();i++) {
-    nsPrintObject* po = prt->mPrintDocList.ElementAt(i);
-    NS_ASSERTION(po, "nsPrintObject can't be null!");
+  for (uint32_t i = 0; i < printData->mPrintDocList.Length(); i++) {
+    nsPrintObject* po = printData->mPrintDocList.ElementAt(i);
+    MOZ_ASSERT(po);
 
     nsIDocument* doc = po->mDocument;
     if (!doc) {
       continue;
     }
 
     if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) {
       nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
@@ -3447,37 +3590,41 @@ nsPrintEngine::FinishPrintPreview()
     /* we're already finished with print preview */
     return rv;
   }
 
   rv = DocumentReadyForPrinting();
 
   SetIsCreatingPrintPreview(false);
 
-  /* cleaup on failure + notify user */
+  // mPrt may be cleared during a call of nsPrintData::OnEndPrinting()
+  // because that method invokes some arbitrary listeners.
+  RefPtr<nsPrintData> printData = mPrt;
   if (NS_FAILED(rv)) {
     /* cleanup done, let's fire-up an error dialog to notify the user
      * what went wrong...
      */
-    mPrt->OnEndPrinting();
+    printData->OnEndPrinting();
+    // XXX mPrt may be nullptr here.  So, Shouldn't TurnScriptingOn() take
+    //     nsPrintData as an argument?
     TurnScriptingOn(true);
 
     return rv;
   }
 
   // At this point we are done preparing everything
   // before it is to be created
 
-
   if (mIsDoingPrintPreview && mOldPrtPreview) {
     mOldPrtPreview = nullptr;
   }
 
-
-  mPrt->OnEndPrinting();
+  printData->OnEndPrinting();
+  // XXX If mPrt becomes nullptr or different instance here, what should we
+  //     do?
 
   // PrintPreview was built using the mPrt (code reuse)
   // then we assign it over
   mPrtPreview = Move(mPrt);
 
 #endif // NS_PRINT_PREVIEW
 
   return NS_OK;
@@ -3525,17 +3672,18 @@ nsPrintEngine::StartPagePrintTimer(const
 /*=============== nsIObserver Interface ======================*/
 NS_IMETHODIMP
 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
   rv = InitPrintDocConstruction(true);
   if (!mIsDoingPrinting && mPrtPreview) {
-      mPrtPreview->OnEndPrinting();
+    RefPtr<nsPrintData> printDataOfPrintPreview = mPrtPreview;
+    printDataOfPrintPreview->OnEndPrinting();
   }
 
   return rv;
 
 }
 
 //---------------------------------------------------------------
 //-- PLEvent Notification
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -260,23 +260,29 @@ protected:
   bool mIsDoingPrinting;
   bool mIsDoingPrintPreview; // per DocumentViewer
   bool mProgressDialogIsShown;
 
   nsCOMPtr<nsIDocumentViewerPrint> mDocViewerPrint;
   nsWeakPtr               mContainer;
   float                   mScreenDPI;
 
-  mozilla::UniquePtr<nsPrintData> mPrt;
+  // We are the primary owner of our nsPrintData member vars.  These vars
+  // are refcounted so that functions (e.g. nsPrintData methods) can create
+  // temporary owning references when they need to fire a callback that
+  // could conceivably destroy this nsPrintEngine owner object and all its
+  // member-data.
+  RefPtr<nsPrintData> mPrt;
+
   nsPagePrintTimer*       mPagePrintTimer;
   WeakFrame               mPageSeqFrame;
 
   // Print Preview
-  mozilla::UniquePtr<nsPrintData> mPrtPreview;
-  mozilla::UniquePtr<nsPrintData> mOldPrtPreview;
+  RefPtr<nsPrintData> mPrtPreview;
+  RefPtr<nsPrintData> mOldPrtPreview;
 
   nsCOMPtr<nsIDocument>   mDocument;
 
   FILE* mDebugFile;
 
   int32_t mLoadCounter;
   bool mDidLoadDataForPrinting;
   bool mIsDestroying;
--- a/xpcom/tests/gtest/TestArenaAllocator.cpp
+++ b/xpcom/tests/gtest/TestArenaAllocator.cpp
@@ -115,16 +115,17 @@ TEST(ArenaAllocator, AllocateLargerThanA
   EXPECT_TRUE(y);
 
   // Now try a normal allocation, it should behave as expected.
   x = a.Allocate(8);
   y = a.Allocate(8);
   EXPECT_EQ(uintptr_t(x) + 8, uintptr_t(y));
 }
 
+#ifndef MOZ_CODE_COVERAGE
 TEST(ArenaAllocator, AllocationsPerChunk)
 {
   // Test that expected number of allocations fit in one chunk.
   // We use an alignment of 64-bytes to avoid worrying about differences in
   // the header size on 32 and 64-bit platforms.
   const size_t kArenaSize = 1024;
   const size_t kAlignment = 64;
   ArenaAllocator<kArenaSize, kAlignment> a;
@@ -188,16 +189,17 @@ TEST(ArenaAllocator, MemoryIsValid)
   // Repeat, this should actually end up in a new chunk.
   x = (char*)a.Allocate(sz);
   EXPECT_EQ(uintptr_t(x) % kAlignment, uintptr_t(0));
   memset(x, kMark, sz);
   for (size_t i = 0; i < sz; i++) {
     EXPECT_EQ(x[i], kMark);
   }
 }
+#endif
 
 MOZ_DEFINE_MALLOC_SIZE_OF(TestSizeOf);
 
 TEST(ArenaAllocator, SizeOf)
 {
   // This tests the sizeof functionality. We can't test for equality as we
   // can't reliably guarantee what sizes the underlying allocator is going to
   // choose, so we just test that things grow (or not) as expected.
--- a/xpcom/tests/gtest/moz.build
+++ b/xpcom/tests/gtest/moz.build
@@ -59,16 +59,19 @@ if CONFIG['MOZ_DEBUG'] and CONFIG['OS_AR
         'TestDeadlockDetectorScalability.cpp',
     ]
 
 if CONFIG['WRAP_STL_INCLUDES'] and not CONFIG['CLANG_CL']:
     UNIFIED_SOURCES += [
         'TestSTLWrappers.cpp',
     ]
 
+if CONFIG['MOZ_CODE_COVERAGE']:
+    DEFINES['MOZ_CODE_COVERAGE'] = True
+
 # Compile TestAllocReplacement separately so Windows headers don't pollute
 # the global namespace for other files.
 SOURCES += [
     'TestAllocReplacement.cpp',
     'TestCOMArray.cpp',
     'TestCOMPtr.cpp', # Redefines IFoo and IBar
     'TestHashtables.cpp', # Redefines IFoo
     'TestNsRefPtr.cpp', # Redefines Foo