Bug 468568. Main patch: support downloading fonts in printing and print preview. r=smaug
authorJulian Viereck <jviereck.dev@gmail.com>
Tue, 04 Sep 2012 16:29:27 +0300
changeset 107710 84317c2f199c22a56ee39c86471d537d2a9de78d
parent 107709 d7a64a0020698c94b814037a525fc15ea59c5779
child 107711 9404e57a5ce6000a4d8d9af1d0f7d9b6db6f45f3
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewerssmaug
bugs468568
milestone18.0a1
Bug 468568. Main patch: support downloading fonts in printing and print preview. r=smaug
content/base/src/nsDataDocumentContentPolicy.cpp
content/base/src/nsDocument.cpp
layout/base/nsDocumentViewer.cpp
layout/printing/Makefile.in
layout/printing/nsPrintEngine.cpp
layout/printing/nsPrintEngine.h
--- a/content/base/src/nsDataDocumentContentPolicy.cpp
+++ b/content/base/src/nsDataDocumentContentPolicy.cpp
@@ -57,18 +57,21 @@ nsDataDocumentContentPolicy::ShouldLoad(
 
   // DTDs are always OK to load
   if (!doc || aContentType == nsIContentPolicy::TYPE_DTD) {
     return NS_OK;
   }
 
   // Nothing else is OK to load for data documents
   if (doc->IsLoadedAsData()) {
-    *aDecision = nsIContentPolicy::REJECT_TYPE;
-    return NS_OK;
+    // ...but let static (print/print preview) documents to load fonts.
+    if (!doc->IsStaticDocument() || aContentType != nsIContentPolicy::TYPE_FONT) {
+      *aDecision = nsIContentPolicy::REJECT_TYPE;
+      return NS_OK;
+    }
   }
 
   if (doc->IsBeingUsedAsImage()) {
     // We only allow SVG images to load content from URIs that are local and
     // also satisfy one of the following conditions:
     //  - URI inherits security context, e.g. data URIs
     //   OR
     //  - URI loadable by subsumers, e.g. blob URIs
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -122,16 +122,17 @@
 #include "nsIJSContextStack.h"
 #include "nsIXPConnect.h"
 #include "nsCycleCollector.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsICategoryManager.h"
 #include "nsIDocumentLoaderFactory.h"
+#include "nsIDocumentLoader.h"
 #include "nsIContentViewer.h"
 #include "nsIXMLContentSink.h"
 #include "nsIXULDocument.h"
 #include "nsIPrompt.h"
 #include "nsIPropertyBag2.h"
 #include "nsIDOMPageTransitionEvent.h"
 #include "nsFrameLoader.h"
 #include "nsEscape.h"
@@ -7623,18 +7624,25 @@ nsDocument::CloneDocHelper(nsDocument* c
 
   // Set URI/principal
   clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
   // Must set the principal first, since SetBaseURI checks it.
   clone->SetPrincipal(NodePrincipal());
   clone->mDocumentBaseURI = mDocumentBaseURI;
 
   if (mCreatingStaticClone) {
+    nsCOMPtr<nsILoadGroup> loadGroup;
+    
+    // |mDocumentContainer| is the container of the document that is being
+    // created and not the original container. See CreateStaticClone function().
+    nsCOMPtr<nsIDocumentLoader> docLoader = do_QueryReferent(mDocumentContainer);
+    if (docLoader) {
+      docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
+    }
     nsCOMPtr<nsIChannel> channel = GetChannel();
-    nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
     if (channel && loadGroup) {
       clone->Reset(channel, loadGroup);
     } else {
       nsIURI* uri = static_cast<const nsIDocument*>(this)->GetDocumentURI();
       if (uri) {
         clone->ResetToURI(uri, loadGroup, NodePrincipal());
       }
     }
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -428,17 +428,17 @@ protected:
   unsigned                         mPrintPreviewZoomed : 1;
 
   // These data members support delayed printing when the document is loading
   unsigned                         mPrintIsPending : 1;
   unsigned                         mPrintDocIsFullyLoaded : 1;
   nsCOMPtr<nsIPrintSettings>       mCachedPrintSettings;
   nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
 
-  nsCOMPtr<nsPrintEngine>          mPrintEngine;
+  nsRefPtr<nsPrintEngine>          mPrintEngine;
   float                            mOriginalPrintPreviewScale;
   float                            mPrintPreviewZoom;
   nsAutoPtr<nsPrintEventDispatcher> mBeforeAndAfterPrint;
 #endif // NS_PRINT_PREVIEW
 
 #ifdef DEBUG
   FILE* mDebugFile;
 #endif // DEBUG
--- a/layout/printing/Makefile.in
+++ b/layout/printing/Makefile.in
@@ -32,11 +32,12 @@ CPPSRCS		= \
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
 		-I$(srcdir)/../base \
 		-I$(srcdir)/../../content/base/src \
+		-I$(srcdir)/../../view/src \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -13,16 +13,19 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIFrame.h"
 #include "nsIURI.h"
 #include "nsITextToSubURI.h"
 #include "nsError.h"
 
+#include "nsView.h"
+#include "nsAsyncDOMEvent.h"
+
 // Print Options
 #include "nsIPrintSettings.h"
 #include "nsIPrintSettingsService.h"
 #include "nsIPrintOptions.h"
 #include "nsIPrintSession.h"
 #include "nsGfxCIID.h"
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
@@ -204,33 +207,36 @@ public:
 protected:
   nsRefPtr<nsPrintEngine> mPrintEngine;
   bool                    mSuppressed;
 };
 
 // Class IDs
 static NS_DEFINE_CID(kViewManagerCID,       NS_VIEW_MANAGER_CID);
 
-NS_IMPL_ISUPPORTS1(nsPrintEngine, nsIObserver)
+NS_IMPL_ISUPPORTS3(nsPrintEngine, nsIWebProgressListener,
+                   nsISupportsWeakReference, nsIObserver)
 
 //---------------------------------------------------
 //-- nsPrintEngine Class Impl
 //---------------------------------------------------
 nsPrintEngine::nsPrintEngine() :
   mIsCreatingPrintPreview(false),
   mIsDoingPrinting(false),
   mIsDoingPrintPreview(false),
   mProgressDialogIsShown(false),
   mScreenDPI(115.0f),
   mPrt(nullptr),
   mPagePrintTimer(nullptr),
   mPageSeqFrame(nullptr),
   mPrtPreview(nullptr),
   mOldPrtPreview(nullptr),
-  mDebugFile(nullptr)
+  mDebugFile(nullptr),
+  mLoadCounter(0),
+  mDidLoadDataForPrinting(false)
 {
 }
 
 //-------------------------------------------------------
 nsPrintEngine::~nsPrintEngine()
 {
   Destroy(); // for insurance
 }
@@ -667,37 +673,54 @@ nsPrintEngine::DoCommonPrint(bool       
           mPrt->mPrintSettings->SetPrintFrameType(mPrt->mPrintFrameType);
         }
       }
     } else {
       mPrt->mPrintSettings->GetPrintFrameType(&mPrt->mPrintFrameType);
     }
   }
 
+  if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
+    CheckForChildFrameSets(mPrt->mPrintObject);
+  }
+
+  if (NS_FAILED(EnablePOsForPrinting())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Attach progressListener to catch network requests.
+  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
+  webProgress->AddProgressListener(
+    static_cast<nsIWebProgressListener*>(this),
+    nsIWebProgress::NOTIFY_STATE_REQUEST);
+
+  mLoadCounter = 0;
+  mDidLoadDataForPrinting = false;
+
   if (aIsPrintPreview) {
     bool notifyOnInit = false;
     ShowPrintProgress(false, notifyOnInit);
 
     // Very important! Turn Off scripting
     TurnScriptingOn(false);
 
     if (!notifyOnInit) {
-      rv = FinishPrintPreview();
+      InstallPrintPreviewListener();
+      rv = InitPrintDocConstruction(false);
     } else {
       rv = NS_OK;
     }
-    NS_ENSURE_SUCCESS(rv, rv);
   } else {
     bool doNotify;
     ShowPrintProgress(true, doNotify);
     if (!doNotify) {
       // Print listener setup...
       mPrt->OnStartPrinting();
-      rv = DocumentReadyForPrinting();
-      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = InitPrintDocConstruction(false);
     }
   }
 
   // We will enable scripting later after printing has finished.
   scriptSuppressor.Disconnect();
 
   return NS_OK;
 }
@@ -799,20 +822,29 @@ nsPrintEngine::GetIsFramesetFrameSelecte
 
 //----------------------------------------------------------------------------------
 /* readonly attribute long printPreviewNumPages; */
 NS_IMETHODIMP
 nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
 {
   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
 
+  nsPrintData* prt = nullptr;
   nsIFrame* seqFrame  = nullptr;
   *aPrintPreviewNumPages = 0;
-  if (!mPrtPreview ||
-      NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
+
+  // When calling this function, the FinishPrintPreview() function might not
+  // been called as there are still some 
+  if (mPrtPreview) {
+    prt = mPrtPreview;
+  } else {
+    prt = mPrt;
+  }
+  if ((!prt) ||
+      NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 //----------------------------------------------------------------------------------
 // Enumerate all the documents for their titles
 NS_IMETHODIMP
@@ -1593,111 +1625,136 @@ nsPrintEngine::ShowPrintErrorDialog(nsre
   dialog->Alert(title.get(), msg.get());
   PR_PL(("ShowPrintErrorDialog(): alert displayed successfully.\n"));
 }
 
 //-----------------------------------------------------------------
 //-- Section: Reflow Methods
 //-----------------------------------------------------------------
 
+nsresult
+nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
+{
+#if (defined(XP_WIN) || defined(XP_OS2)) && 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);
+    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());
+    po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
+
+    po->mPresShell->ReconstructFrames();
+
+    // 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);
+
+      MOZ_ASSERT(!documentIsTopLevel, "How could this happen?");
+      
+      if (NS_FAILED(rv) || doReturn) {
+        return rv; 
+      }
+    }
+
+    po->mPresShell->FlushPendingNotifications(Flush_Layout);
+
+    nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  return NS_OK;
+}
+
 //-------------------------------------------------------
 nsresult
 nsPrintEngine::SetupToPrintContent()
 {
-  // In this step we figure out which documents should be printed
-  // i.e. if we are printing the selection then only enable that nsPrintObject
-  // for printing
-  if (NS_FAILED(EnablePOsForPrinting())) {
-    return NS_ERROR_FAILURE;
+  nsresult rv;
+
+  bool didReconstruction = false;
+  
+  // If some new content got loaded since the initial reflow rebuild
+  // everything.
+  if (mDidLoadDataForPrinting) {
+    rv = ReconstructAndReflow(DoSetPixelScale());
+    didReconstruction = true;
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-  DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
-
-  // This is an Optimization
-  // If we are in PP then we already know all the shrinkage information
-  // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
-  //
-  // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
-  // The first time we do not want to do this, the second time through we do
-  bool doSetPixelScale = false;
+
+  // 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 (ppIsShrinkToFit) {
-    mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
-    doSetPixelScale = true;
-  }
-
-  // Here we reflow all the PrintObjects
-  nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Here is where we do the extra reflow for shrinking the content
-  // But skip this step if we are in PrintPreview
   if (mPrt->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) {
       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;
       }
     } else {
       // Single document so use the Shrink as calculated for the PO
       mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
     }
 
-    // Only Shrink if we are smaller
     if (mPrt->mShrinkRatio < 0.998f) {
-      for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) {
-        nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
-        NS_ASSERTION(po, "nsPrintObject can't be null!");
-        // Wipe out the presentation before we reflow
-        po->DestroyPresentation();
-      }
-
-#if (defined(XP_WIN) || defined(XP_OS2)) && 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
-
-      // Here we reflow all the PrintObjects a second time
-      // this time using the shrinkage values
-      // The last param here tells reflow to NOT calc the shrinkage values
-      if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, true))) {
-        return NS_ERROR_FAILURE;
-      }
+      rv = ReconstructAndReflow(true);
+      didReconstruction = true;
+      NS_ENSURE_SUCCESS(rv, rv);
     }
 
 #ifdef PR_LOGGING
-    {
-      float calcRatio = 0.0f;
-      if (mPrt->mPrintDocList.Length() > 1 && mPrt->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;
+    float calcRatio = 0.0f;
+    if (mPrt->mPrintDocList.Length() > 1 && mPrt->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;
       }
-      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(("**************************************************************************\n"));
+    } else {
+      // Single document so use the Shrink as calculated for the PO
+      calcRatio = mPrt->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(("**************************************************************************\n"));
 #endif
   }
-
+  
+  // If the frames got reconstructed and reflowed the number of pages might
+  // has changed.
+  if (didReconstruction) {
+    FirePrintPreviewUpdateEvent();
+  }
+  
   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));
@@ -1787,67 +1844,273 @@ nsPrintEngine::ReflowDocList(nsPrintObje
     nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
     if (!frame || !frame->GetStyleVisibility()->IsVisible()) {
       aPO->mDontPrint = true;
       aPO->mInvisible = true;
       return NS_OK;
     }
   }
 
+  UpdateZoomRatio(aPO, 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);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  return NS_OK;
+}
+
+void
+nsPrintEngine::FirePrintPreviewUpdateEvent()
+{
+  // Dispatch the event only while in PrintPreview. When printing, there is no
+  // listener bound to this event and therefore no need to dispatch it.
+  if (mIsDoingPrintPreview && !mIsDoingPrinting) {
+    nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
+    (new nsAsyncDOMEvent(
+       cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true)
+    )->RunDOMEventWhenSafe();
+  }
+}
+
+nsresult
+nsPrintEngine::InitPrintDocConstruction(bool aHandleError)
+{
+  nsresult rv;
+  rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  FirePrintPreviewUpdateEvent();
+
+  if (mLoadCounter == 0) {
+    AfterNetworkPrint(aHandleError);
+  }
+  return rv;
+}
+
+nsresult
+nsPrintEngine::AfterNetworkPrint(bool aHandleError)
+{
+  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
+
+  webProgress->RemoveProgressListener(
+    static_cast<nsIWebProgressListener*>(this));
+
+  nsresult rv;
+  if (mIsDoingPrinting) {
+    rv = DocumentReadyForPrinting();
+  } else {
+    rv = FinishPrintPreview();
+  }
+
+  /* cleaup on failure + notify user */
+  if (aHandleError && NS_FAILED(rv)) {
+    CleanupOnFailure(rv, !mIsDoingPrinting);
+  }
+
+  return rv;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIWebProgressListener
+
+NS_IMETHODIMP
+nsPrintEngine::OnStateChange(nsIWebProgress* aWebProgress,
+                             nsIRequest* aRequest,
+                             uint32_t aStateFlags,
+                             nsresult aStatus)
+{
+  nsAutoCString name;
+  aRequest->GetName(name);
+  if (name.Equals("about:document-onload-blocker")) {
+    return NS_OK;
+  }
+  if (aStateFlags & STATE_START) {
+    nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+
+    ++mLoadCounter;
+  } else if (aStateFlags & STATE_STOP) {
+    mDidLoadDataForPrinting = true;
+    --mLoadCounter;
+   
+    // If all resources are loaded, then do a small timeout and if there
+    // are still no new requests, then another reflow.
+    if (mLoadCounter == 0) {
+      AfterNetworkPrint(true);
+    }
+  }
+  return NS_OK;
+}
+
+
+
+NS_IMETHODIMP
+nsPrintEngine::OnProgressChange(nsIWebProgress* aWebProgress,
+                                 nsIRequest* aRequest,
+                                 int32_t aCurSelfProgress,
+                                 int32_t aMaxSelfProgress,
+                                 int32_t aCurTotalProgress,
+                                 int32_t aMaxTotalProgress)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintEngine::OnLocationChange(nsIWebProgress* aWebProgress,
+                                nsIRequest* aRequest,
+                                nsIURI* aLocation,
+                                uint32_t aFlags)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintEngine::OnStatusChange(nsIWebProgress *aWebProgress,
+                              nsIRequest *aRequest,
+                              nsresult aStatus,
+                              const PRUnichar *aMessage)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintEngine::OnSecurityChange(nsIWebProgress *aWebProgress,
+                                  nsIRequest *aRequest,
+                                  uint32_t aState)
+{
+  NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+  return NS_OK;
+}
+
+//-------------------------------------------------------
+
+void
+nsPrintEngine::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale)
+{
   // Here is where we set the shrinkage value into the DC
   // and this is what actually makes it shrink
   if (aSetPixelScale && aPO->mFrameType != eIFrame) {
     float ratio;
     if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
       ratio = mPrt->mShrinkRatio - 0.005f; // round down
     } else {
       ratio = aPO->mShrinkRatio - 0.005f; // round down
     }
     aPO->mZoomRatio = ratio;
   } else if (!mPrt->mShrinkToFit) {
     double scaling;
     mPrt->mPrintSettings->GetScaling(&scaling);
     aPO->mZoomRatio = float(scaling);
+  } 
+}
+
+nsresult
+nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
+                                                   bool aDocumentIsTopLevel)
+{
+  nsCOMPtr<nsIPresShell> displayShell;
+  aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
+  // Transfer Selection Ranges to the new Print PresShell
+  nsCOMPtr<nsISelection> selection, selectionPS;
+  // It's okay if there is no display shell, just skip copying the selection
+  if (displayShell) {
+    selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
   }
-
-  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);
-    NS_ENSURE_SUCCESS(rv, rv);
+  selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
+
+  // Reset all existing selection ranges that might have been added by calling
+  // this function before.
+  if (selectionPS) {
+    selectionPS->RemoveAllRanges();
+  }
+  if (selection && selectionPS) {
+    int32_t cnt;
+    selection->GetRangeCount(&cnt);
+    int32_t inx;
+    for (inx = 0; inx < cnt; ++inx) {
+      nsCOMPtr<nsIDOMRange> range;
+      if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
+        selectionPS->AddRange(range);
+    }
+  }
+
+  // If we are trying to shrink the contents to fit on the page
+  // we must first locate the "pageContent" frame
+  // Then we walk the frame tree and look for the "xmost" frame
+  // this is the frame where the right-hand side of the frame extends
+  // the furthest
+  if (mPrt->mShrinkToFit && aDocumentIsTopLevel) {
+    nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
+    NS_ENSURE_STATE(pageSequence);
+    pageSequence->GetSTFPercent(aPO->mShrinkRatio);
   }
   return NS_OK;
 }
 
-//-------------------------------------------------------
-// Reflow a nsPrintObject
-nsresult
-nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
+bool
+nsPrintEngine::DoSetPixelScale()
+{
+  // This is an Optimization
+  // If we are in PP then we already know all the shrinkage information
+  // so just transfer it to the PrintData and we will skip the extra shrinkage reflow
+  //
+  // doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
+  // The first time we do not want to do this, the second time through we do
+  bool doSetPixelScale = false;
+  bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
+  if (ppIsShrinkToFit) {
+    mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
+    doSetPixelScale = true;
+  }
+  return doSetPixelScale;
+}
+
+nsIView*
+nsPrintEngine::GetParentViewForRoot()
 {
-  NS_ASSERTION(aPO, "Pointer is null!");
-  if (!aPO) return NS_ERROR_FAILURE;
-
-  nsSize adjSize;
-  bool documentIsTopLevel;
-  if (!aPO->IsPrintable())
-    return NS_OK;
-
+  if (mIsCreatingPrintPreview) {
+    nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
+    if (cv) {
+      return cv->FindContainerView();
+    }
+  }
+  return nullptr;
+}
+
+nsresult
+nsPrintEngine::SetRootView(
+    nsPrintObject* aPO, 
+    bool& doReturn, 
+    bool& documentIsTopLevel, 
+    nsSize& adjSize
+)
+{
   bool canCreateScrollbars = true;
+
+  nsIView* rootView;
   nsIView* parentView = nullptr;
 
+  doReturn = false;
+
   if (aPO->mParent && aPO->mParent->IsPrintable()) {
     nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
     // Without a frame, this document can't be displayed; therefore, there is no
     // point to reflowing it
     if (!frame) {
       SetPrintPO(aPO, false);
+      doReturn = true;
       return NS_OK;
     }
 
     //XXX If printing supported printing document hierarchies with non-constant
     // zoom this would be wrong as we use the same mPrt->mPrintDC for all
     // subdocuments.
     adjSize = frame->GetContentRect().Size();
     documentIsTopLevel = false;
@@ -1862,31 +2125,61 @@ nsPrintEngine::ReflowPrintObject(nsPrint
       parentView = view;
       canCreateScrollbars = false;
     }
   } else {
     nscoord pageWidth, pageHeight;
     mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
     adjSize = nsSize(pageWidth, pageHeight);
     documentIsTopLevel = true;
-
-    if (mIsCreatingPrintPreview) {
-      nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
-      if (cv) {
-        parentView = cv->FindContainerView();
-      }
-    }
+    parentView = GetParentViewForRoot();
+  }
+
+  if (aPO->mPresShell->GetViewManager()->GetRootView()) {
+    // Reuse the root view that is already on the root frame.
+    rootView = aPO->mPresShell->GetRootFrame()->GetView();
+    reinterpret_cast<nsView*>(rootView)->SetParent(reinterpret_cast<nsView*>(parentView));
+  } else {
+    // Create a child window of the parent that is our "root view/window"
+    nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
+    rootView = aPO->mViewManager->CreateView(tbounds, parentView);
+    NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
+  }
+    
+  if (mIsCreatingPrintPreview && documentIsTopLevel) {
+    aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
   }
 
+  // Setup hierarchical relationship in view manager
+  aPO->mViewManager->SetRootView(rootView);
+
+  return NS_OK;
+}
+
+// Reflow a nsPrintObject
+nsresult
+nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
+{
+  NS_ENSURE_STATE(aPO);
+
+  if (!aPO->IsPrintable()) {
+    return NS_OK;
+  }
+  
   NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
 
   // create the PresContext
-  aPO->mPresContext = new nsPresContext(aPO->mDocument,
-    mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
-                              nsPresContext::eContext_Print);
+  nsPresContext::nsPresContextType type =
+      mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
+                                nsPresContext::eContext_Print;
+  nsIView* 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);
 
   // set the presentation context to the value in the print settings
   bool printBGColors;
   mPrt->mPrintSettings->GetPrintBGColors(&printBGColors);
   aPO->mPresContext->SetBackgroundColorDraw(printBGColors);
   mPrt->mPrintSettings->GetPrintBGImages(&printBGColors);
@@ -1912,30 +2205,30 @@ nsPrintEngine::ReflowPrintObject(nsPrint
     delete styleSet;
     return rv;
   }
 
   styleSet->EndUpdate();
   
   // The pres shell now owns the style set object.
 
-  PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO,
+
+  bool doReturn = false;;
+  bool documentIsTopLevel = false;
+  nsSize adjSize; 
+
+  rv = SetRootView(aPO, 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(),
          gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
 
-  // Create a child window of the parent that is our "root view/window"
-  nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
-  nsIView* rootView = aPO->mViewManager->CreateView(tbounds, parentView);
-  NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
-
-  if (mIsCreatingPrintPreview && documentIsTopLevel) {
-    aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
-  }
-
-  // Setup hierarchical relationship in view manager
-  aPO->mViewManager->SetRootView(rootView);
 
   // This docshell stuff is weird; will go away when we stop having multiple
   // presentations per document
   nsCOMPtr<nsISupports> supps(do_QueryInterface(aPO->mDocShell));
   aPO->mPresContext->SetContainer(supps);
 
   aPO->mPresShell->BeginObservingDocument();
 
@@ -1956,46 +2249,18 @@ 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(Flush_Layout);
 
-  nsCOMPtr<nsIPresShell> displayShell;
-  aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
-  // Transfer Selection Ranges to the new Print PresShell
-  nsCOMPtr<nsISelection> selection, selectionPS;
-  // It's okay if there is no display shell, just skip copying the selection
-  if (displayShell) {
-    selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
-  }
-  selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
-  if (selection && selectionPS) {
-    int32_t cnt;
-    selection->GetRangeCount(&cnt);
-    int32_t inx;
-    for (inx=0;inx<cnt;inx++) {
-      nsCOMPtr<nsIDOMRange> range;
-      if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
-        selectionPS->AddRange(range);
-    }
-  }
-
-  // If we are trying to shrink the contents to fit on the page
-  // we must first locate the "pageContent" frame
-  // Then we walk the frame tree and look for the "xmost" frame
-  // this is the frame where the right-hand side of the frame extends
-  // the furthest
-  if (mPrt->mShrinkToFit && documentIsTopLevel) {
-    nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
-    NS_ENSURE_STATE(pageSequence);
-    pageSequence->GetSTFPercent(aPO->mShrinkRatio);
-  }
+  rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel);
+  NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef EXTENDED_DEBUG_PRINTING
     if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
       char * docStr;
       char * urlStr;
       GetDocTitleAndURL(aPO, docStr, urlStr);
       char filename[256];
       sprintf(filename, "print_dump_%d.txt", gDumpFileNameCnt++);
@@ -3304,17 +3569,16 @@ nsPrintEngine::FinishPrintPreview()
   // before it is to be created
 
 
   if (mIsDoingPrintPreview && mOldPrtPreview) {
     delete mOldPrtPreview;
     mOldPrtPreview = nullptr;
   }
 
-  InstallPrintPreviewListener();
 
   mPrt->OnEndPrinting();
 
   // PrintPreview was built using the mPrt (code reuse)
   // then we assign it over
   mPrtPreview = mPrt;
   mPrt        = nullptr;
 
@@ -3347,32 +3611,19 @@ nsPrintEngine::StartPagePrintTimer(nsPri
 }
 
 /*=============== nsIObserver Interface ======================*/
 NS_IMETHODIMP 
 nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
-  if (mIsDoingPrinting) {
-    rv = DocumentReadyForPrinting();
- 
-    /* cleaup on failure + notify user */
-    if (NS_FAILED(rv)) {
-      CleanupOnFailure(rv, true);
-    }
-  } else {
-    rv = FinishPrintPreview();
-    if (NS_FAILED(rv)) {
-      CleanupOnFailure(rv, false);
-    }
-    if (mPrtPreview) {
+  rv = InitPrintDocConstruction(true);
+  if (!mIsDoingPrinting && mPrtPreview) {
       mPrtPreview->OnEndPrinting();
-    }
-    rv = NS_OK;
   }
 
   return rv;
 
 }
 
 //---------------------------------------------------------------
 //-- PLEvent Notification
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -8,17 +8,20 @@
 #include "mozilla/Attributes.h"
 
 #include "nsCOMPtr.h"
 
 #include "nsPrintObject.h"
 #include "nsPrintData.h"
 #include "nsFrameList.h"
 #include "mozilla/Attributes.h"
+#include "nsIWebProgress.h"
 #include "nsHTMLCanvasElement.h"
+#include "nsIWebProgressListener.h"
+#include "nsWeakReference.h"
 
 // Interfaces
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIObserver.h"
 
 // Classes
 class nsPagePrintTimer;
@@ -29,25 +32,29 @@ class nsPrintObject;
 class nsIDocShell;
 class nsIPageSequenceFrame;
 class nsIWeakReference;
 
 //------------------------------------------------------------------------
 // nsPrintEngine Class
 //
 //------------------------------------------------------------------------
-class nsPrintEngine MOZ_FINAL : public nsIObserver
+class nsPrintEngine MOZ_FINAL : public nsIObserver,
+                                public nsIWebProgressListener,
+                                public nsSupportsWeakReference
 {
 public:
   // nsISupports interface...
   NS_DECL_ISUPPORTS
 
   // nsIObserver
   NS_DECL_NSIOBSERVER
 
+  NS_DECL_NSIWEBPROGRESSLISTENER
+
   // Old nsIWebBrowserPrint methods; not cleaned up yet
   NS_IMETHOD Print(nsIPrintSettings*       aPrintSettings,
                    nsIWebProgressListener* aWebProgressListener);
   NS_IMETHOD PrintPreview(nsIPrintSettings* aPrintSettings,
                           nsIDOMWindow *aChildDOMWin,
                           nsIWebProgressListener* aWebProgressListener);
   NS_IMETHOD GetIsFramesetDocument(bool *aIsFramesetDocument);
   NS_IMETHOD GetIsIFrameSelected(bool *aIsIFrameSelected);
@@ -266,13 +273,30 @@ protected:
   // Print Preview
   nsPrintData*            mPrtPreview;
   nsPrintData*            mOldPrtPreview;
 
   nsCOMPtr<nsIDocument>   mDocument;
 
   FILE* mDebugFile;
 
+  int32_t mLoadCounter;
+  bool mDidLoadDataForPrinting;
+
+  nsresult AfterNetworkPrint(bool aHandleError);
+
+  nsresult SetRootView(nsPrintObject* aPO,
+                       bool& aDoReturn,
+                       bool& aDocumentIsTopLevel,
+                       nsSize& aAdjSize);
+  nsIView* GetParentViewForRoot();
+  bool DoSetPixelScale();
+  void UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale);
+  nsresult ReconstructAndReflow(bool aDoSetPixelScale);
+  nsresult UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
+                                               bool aDocumentIsTopLevel);
+  nsresult InitPrintDocConstruction(bool aHandleError);
+  void FirePrintPreviewUpdateEvent();
 private:
   nsPrintEngine& operator=(const nsPrintEngine& aOther) MOZ_DELETE;
 };
 
 #endif /* nsPrintEngine_h___ */