Bug 1339735 - send PDF file name and printing setting to Chrome process draft
authorFarmer Tseng <fatseng@mozilla.com>
Fri, 17 Feb 2017 15:26:00 +0800
changeset 487785 51b5eb7523788cc66527c048588ede8e39d50b78
parent 484392 0b8757291167e2a6ac8c02ca09b5e02c0b9dd4fc
child 546545 294ecf9c6331921754c31741b03822bbcb83c47f
push id46326
push userbmo:fatseng@mozilla.com
push dateWed, 22 Feb 2017 02:51:08 +0000
bugs1339735
milestone54.0a1
Bug 1339735 - send PDF file name and printing setting to Chrome process MozReview-Commit-ID: 8d1KhraU0N6
layout/base/nsDocumentViewer.cpp
layout/printing/ipc/PRemotePrintJob.ipdl
layout/printing/ipc/RemotePrintJobChild.cpp
layout/printing/ipc/RemotePrintJobChild.h
layout/printing/ipc/RemotePrintJobParent.cpp
layout/printing/ipc/RemotePrintJobParent.h
layout/printing/nsPrintEngine.cpp
layout/printing/nsPrintEngine.h
toolkit/components/printingui/ipc/PrintingParent.cpp
widget/android/nsDeviceContextAndroid.h
widget/cocoa/nsDeviceContextSpecX.h
widget/gtk/nsDeviceContextSpecG.h
widget/nsDeviceContextSpecProxy.cpp
widget/nsDeviceContextSpecProxy.h
widget/nsIDeviceContextSpec.h
widget/windows/nsDeviceContextSpecWin.h
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3799,16 +3799,66 @@ nsDocumentViewer::PrintPDF(const nsAStri
   nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
   if (xulDoc) {
     PR_PL(("Printing XUL documents is not supported"));
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = NS_ERROR_FAILURE;
 
+  // if we are printing another URL, then exit
+  // the reason we check here is because this method can be called while
+  // another is still in here (the printing dialog is a good example).
+  // the only time we can print more than one job at a time is the regression tests
+  if (GetIsPrinting()) {
+    // Let the user know we are not ready to print.
+    rv = NS_ERROR_NOT_AVAILABLE;
+
+    if (mPrintEngine) {
+      mPrintEngine->FirePrintingErrorEvent(rv);
+    }
+
+    return rv;
+  }
+
+  // Dispatch 'beforeprint' event and ensure 'afterprint' will be dispatched:
+  MOZ_ASSERT(!mAutoBeforeAndAfterPrint,
+             "We don't want to dispatch nested beforeprint/afterprint");
+  nsAutoPtr<AutoPrintEventDispatcher> autoBeforeAndAfterPrint(
+    new AutoPrintEventDispatcher(mDocument));
+  NS_ENSURE_STATE(!GetIsPrinting());
+
+  if (!mPrintEngine) {
+    NS_ENSURE_STATE(mDeviceContext);
+    mPrintEngine = new nsPrintEngine();
+
+    rv = mPrintEngine->Initialize(this, mContainer, mDocument,
+                                  float(mDeviceContext->AppUnitsPerCSSInch()) /
+                                  float(mDeviceContext->AppUnitsPerDevPixel()) /
+                                  mPageZoom,
+#ifdef DEBUG
+                                  mDebugFile
+#else
+                                  nullptr
+#endif
+                                  );
+    if (NS_FAILED(rv)) {
+      mPrintEngine->Destroy();
+      mPrintEngine = nullptr;
+      return rv;
+    }
+  }
+
+  mAutoBeforeAndAfterPrint = autoBeforeAndAfterPrint;
+  mPrintEngine->SetDisallowSelectionPrint(false);
+  rv = mPrintEngine->PrintPDF(aPDFFileName, aPrintSettings);
+  if (NS_FAILED(rv)) {
+    OnDonePrinting();
+  }
+
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::Print(nsIPrintSettings*       aPrintSettings,
                           nsIWebProgressListener* aWebProgressListener)
 {
   // Printing XUL documents is not supported.
--- a/layout/printing/ipc/PRemotePrintJob.ipdl
+++ b/layout/printing/ipc/PRemotePrintJob.ipdl
@@ -38,21 +38,27 @@ parent:
   async ProgressChange(long aCurSelfProgress,
                        long aMaxSelfProgress,
                        long aCurTotalProgress,
                        long aMaxTotalProgress);
 
   // Report a status change to listeners in the parent process.
   async StatusChange(nsresult aStatus);
 
+  // Send PDF file name to print
+  async ProcessPDF(nsCString aPDFFileName);
+
 child:
   // Inform the child that the print has been initialized in the parent or has
   // failed with result aRv.
   async PrintInitializationResult(nsresult aRv);
 
   // Inform the child that the latest page has been processed remotely.
   async PageProcessed();
 
+  // Inform the child that PDF has been printed remotely.
+  async PdfProcessed();
+
   async __delete__();
 };
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -58,16 +58,31 @@ mozilla::ipc::IPCResult
 RemotePrintJobChild::RecvPageProcessed()
 {
   MOZ_ASSERT(mPagePrintTimer);
 
   mPagePrintTimer->RemotePrintFinished();
   return IPC_OK();
 }
 
+void
+RemotePrintJobChild::ProcessPDF(const nsCString& aPDFFileName)
+{
+  Unused << SendProcessPDF(aPDFFileName);
+}
+
+mozilla::ipc::IPCResult
+RemotePrintJobChild::RecvPdfProcessed()
+{
+  MOZ_ASSERT(mPrintEngine);
+
+  mPrintEngine->DonePrintingPDF();
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult
 RemotePrintJobChild::RecvAbortPrint(const nsresult& aRv)
 {
   MOZ_ASSERT(mPrintEngine);
 
   mPrintEngine->CleanupOnFailure(aRv, true);
   return IPC_OK();
 }
--- a/layout/printing/ipc/RemotePrintJobChild.h
+++ b/layout/printing/ipc/RemotePrintJobChild.h
@@ -41,16 +41,20 @@ public:
   mozilla::ipc::IPCResult RecvPageProcessed() final;
 
   mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
 
   void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer);
 
   void SetPrintEngine(nsPrintEngine* aPrintEngine);
 
+  void ProcessPDF(const nsCString& aPDFFileName);
+
+  mozilla::ipc::IPCResult RecvPdfProcessed() final;
+
 private:
   ~RemotePrintJobChild() final;
 
   bool mPrintInitialized = false;
   nsresult mInitializationResult = NS_OK;
   RefPtr<nsPagePrintTimer> mPagePrintTimer;
   RefPtr<nsPrintEngine> mPrintEngine;
 };
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -139,16 +139,25 @@ RemotePrintJobParent::PrintPage(const ns
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 mozilla::ipc::IPCResult
+RemotePrintJobParent::RecvProcessPDF(const nsCString& aFileName)
+{
+  // XXX TODO: call this in correct place where finish printing
+  Unused << SendPdfProcessed();
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 RemotePrintJobParent::RecvFinalizePrint()
 {
   // EndDocument is sometimes called in the child even when BeginDocument has
   // not been called. See bug 1223332.
   if (mPrintDeviceContext) {
     DebugOnly<nsresult> rv = mPrintDeviceContext->EndDocument();
 
     // Too late to abort the child just log.
--- a/layout/printing/ipc/RemotePrintJobParent.h
+++ b/layout/printing/ipc/RemotePrintJobParent.h
@@ -31,16 +31,18 @@ public:
 
   mozilla::ipc::IPCResult RecvInitializePrint(const nsString& aDocumentTitle,
                                               const nsString& aPrintToFile,
                                               const int32_t& aStartPage,
                                               const int32_t& aEndPage) final;
 
   mozilla::ipc::IPCResult RecvProcessPage(const nsCString& aPageFileName) final;
 
+  mozilla::ipc::IPCResult RecvProcessPDF(const nsCString& aFileName) final;
+
   mozilla::ipc::IPCResult RecvFinalizePrint() final;
 
   mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
 
   mozilla::ipc::IPCResult RecvStateChange(const long& aStateFlags,
                                           const nsresult& aStatus) final;
 
   mozilla::ipc::IPCResult RecvProgressChange(const long& aCurSelfProgress,
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -237,16 +237,18 @@ void nsPrintEngine::Destroy()
 {
   if (mIsDestroying) {
     return;
   }
   mIsDestroying = true;
 
   mPrt = nullptr;
 
+  mDevspec = nullptr;
+
 #ifdef NS_PRINT_PREVIEW
   mPrtPreview = nullptr;
   mOldPrtPreview = nullptr;
 #endif
   mDocViewerPrint = nullptr;
 }
 
 //-------------------------------------------------------
@@ -756,16 +758,73 @@ nsPrintEngine::DoCommonPrint(bool       
   // We will enable scripting later after printing has finished.
   scriptSuppressor.Disconnect();
 
   return NS_OK;
 }
 
 //---------------------------------------------------------------------------------
 NS_IMETHODIMP
+nsPrintEngine::PrintPDF(const nsAString&  aPDFFileName,
+                        nsIPrintSettings* aPrintSettings)
+{
+  SetIsPrinting(true);
+
+  nsresult rv;
+  nsCOMPtr<nsIPrintSession> printSession;
+  rv = aPrintSettings->GetPrintSession(getter_AddRefs(printSession));
+  if (NS_FAILED(rv) || !printSession) {
+    printSession = do_CreateInstance("@mozilla.org/gfx/printsession;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    aPrintSettings->SetPrintSession(printSession);
+  }
+
+  bool printSilently = true;
+  aPrintSettings->SetPrintSilent(printSilently);
+
+  nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
+  NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
+  nsPIDOMWindowOuter* domWin = mDocument->GetWindow();
+  NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
+  if (printPromptService) {
+    rv = printPromptService->ShowPrintDialog(domWin, wbp, aPrintSettings);
+    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;
+  }
+
+  if (NS_FAILED(rv)) {
+    SetIsPrinting(false);
+    return rv;
+  }
+
+  RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
+  printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
+  if (NS_SUCCEEDED(rv) && remotePrintJob) {
+    remotePrintJob->SetPrintEngine(this);
+  } else {
+    SetIsPrinting(false);
+    return rv;
+  }
+
+  mDevspec = new nsDeviceContextSpecProxy();
+  mDevspec->Init(nullptr, aPrintSettings, false);
+  mDevspec->SendPDF(aPDFFileName);
+
+  return rv;
+}
+
+NS_IMETHODIMP
 nsPrintEngine::Print(nsIPrintSettings*       aPrintSettings,
                      nsIWebProgressListener* aWebProgressListener)
 {
   // If we have a print preview document, use that instead of the original
   // mDocument. That way animated images etc. get printed using the same state
   // as in print preview.
   nsCOMPtr<nsIDOMDocument> doc =
     do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ?
@@ -3073,16 +3132,27 @@ nsPrintEngine::DonePrintingPages(nsPrint
 
   // Release reference to mPagePrintTimer; the timer object destroys itself
   // after this returns true
   DisconnectPagePrintTimer();
 
   return true;
 }
 
+bool
+nsPrintEngine::DonePrintingPDF()
+{
+  PR_PL(("****** In DV::DonePrintingPDF \n"));
+
+  FirePrintCompletionEvent();
+  SetIsPrinting(false);
+
+  return true;
+}
+
 //-------------------------------------------------------
 // Recursively sets the PO items to be printed "As Is"
 // from the given item down into the tree
 void
 nsPrintEngine::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs)
 {
   NS_ASSERTION(aPO, "Pointer is null!");
 
--- a/layout/printing/nsPrintEngine.h
+++ b/layout/printing/nsPrintEngine.h
@@ -60,16 +60,18 @@ public:
   NS_IMETHOD GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected);
   NS_IMETHOD GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages);
   NS_IMETHOD EnumerateDocumentNames(uint32_t* aCount, char16_t*** aResult);
   static nsresult GetGlobalPrintSettings(nsIPrintSettings** aPrintSettings);
   NS_IMETHOD GetDoingPrint(bool *aDoingPrint);
   NS_IMETHOD GetDoingPrintPreview(bool *aDoingPrintPreview);
   NS_IMETHOD GetCurrentPrintSettings(nsIPrintSettings **aCurrentPrintSettings);
 
+  NS_IMETHOD PrintPDF(const nsAString&  aPDFFileName,
+                      nsIPrintSettings* aPrintSettings);
 
   // This enum tells indicates what the default should be for the title
   // if the title from the document is null
   enum eDocTitleDefault {
     eDocTitleDefBlank,
     eDocTitleDefURLDoc
   };
 
@@ -106,16 +108,17 @@ public:
   bool CheckDocumentForPPCaching();
   void InstallPrintPreviewListener();
 
   // nsIDocumentViewerPrint Printing Methods
   bool     HasPrintCallbackCanvas();
   bool     PrePrintPage();
   bool     PrintPage(nsPrintObject* aPOect, bool& aInRange);
   bool     DonePrintingPages(nsPrintObject* aPO, nsresult aResult);
+  bool     DonePrintingPDF();
 
   //---------------------------------------------------------------------
   void BuildDocTree(nsIDocShell *      aParentNode,
                     nsTArray<nsPrintObject*> * aDocList,
                     nsPrintObject *            aPO);
   nsresult ReflowDocList(nsPrintObject * aPO, bool aSetPixelScale);
 
   nsresult ReflowPrintObject(nsPrintObject * aPO);
@@ -273,16 +276,18 @@ protected:
 
   FILE* mDebugFile;
 
   int32_t mLoadCounter;
   bool mDidLoadDataForPrinting;
   bool mIsDestroying;
   bool mDisallowSelectionPrint;
 
+  nsCOMPtr<nsIDeviceContextSpec> mDevspec;
+
   nsresult AfterNetworkPrint(bool aHandleError);
 
   nsresult SetRootView(nsPrintObject* aPO,
                        bool& aDoReturn,
                        bool& aDocumentIsTopLevel,
                        nsSize& aAdjSize);
   nsView* GetParentViewForRoot();
   bool DoSetPixelScale();
--- a/toolkit/components/printingui/ipc/PrintingParent.cpp
+++ b/toolkit/components/printingui/ipc/PrintingParent.cpp
@@ -113,25 +113,22 @@ PrintingParent::ShowPrintDialog(PBrowser
   nsresult rv;
   if (remotePrintJob) {
     settings = remotePrintJob->GetPrintSettings();
   } else {
     rv = mPrintSettingsSvc->GetNewPrintSettings(getter_AddRefs(settings));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  // We only want to use the print silently setting from the parent.
-  bool printSilently;
-  rv = settings->GetPrintSilent(&printSilently);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = settings->SetPrintSilent(printSilently);
+  // We want to use the print silently setting from the child.
+  bool printSilently;
+  rv = settings->GetPrintSilent(&printSilently);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsXPIDLString printerName;
   settings->GetPrinterName(getter_Copies(printerName));
 #ifdef MOZ_X11
   // Requesting the default printer name on Linux has been removed in the child,
   // because it was causing a sandbox violation (see Bug 1329216).
   // If no printer name is set at this point, use the print settings service
--- a/widget/android/nsDeviceContextAndroid.h
+++ b/widget/android/nsDeviceContextAndroid.h
@@ -23,14 +23,15 @@ public:
                     bool aIsPrintPreview) override;
     NS_IMETHOD BeginDocument(const nsAString& aTitle,
                              const nsAString& aPrintToFileName,
                              int32_t aStartPage,
                              int32_t aEndPage) override;
     NS_IMETHOD EndDocument() override;
     NS_IMETHOD BeginPage() override { return NS_OK; }
     NS_IMETHOD EndPage() override { return NS_OK; }
+    NS_IMETHOD SendPDF(const nsAString& aPDFFileName) override { return NS_OK; }
 
 private:
     nsCOMPtr<nsIPrintSettings> mPrintSettings;
     nsCOMPtr<nsIFile> mTempFile;
 };
 #endif // nsDeviceContextAndroid_h__
--- a/widget/cocoa/nsDeviceContextSpecX.h
+++ b/widget/cocoa/nsDeviceContextSpecX.h
@@ -25,16 +25,19 @@ public:
                              int32_t          aEndPage) override;
     NS_IMETHOD EndDocument() override;
     NS_IMETHOD BeginPage() override {
       return NS_OK;
     };
     NS_IMETHOD EndPage() override {
       return NS_OK;
     };
+    NS_IMETHOD SendPDF(const nsAString& aPDFFileName) override {
+      return NS_OK;
+    };
 
     void GetPaperRect(double* aTop, double* aLeft, double* aBottom, double* aRight);
 
 protected:
     virtual ~nsDeviceContextSpecX();
 
 protected:
     PMPrintSession    mPrintSession;              // printing context.
--- a/widget/gtk/nsDeviceContextSpecG.h
+++ b/widget/gtk/nsDeviceContextSpecG.h
@@ -35,16 +35,17 @@ public:
   NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS,
                   bool aIsPrintPreview) override;
   NS_IMETHOD BeginDocument(const nsAString& aTitle,
                            const nsAString& aPrintToFileName,
                            int32_t aStartPage, int32_t aEndPage) override;
   NS_IMETHOD EndDocument() override;
   NS_IMETHOD BeginPage() override { return NS_OK; }
   NS_IMETHOD EndPage() override { return NS_OK; }
+  NS_IMETHOD SendPDF(const nsAString& aPDFFileName) override { return NS_OK; }
 
 protected:
   virtual ~nsDeviceContextSpecGTK();
   nsCOMPtr<nsPrintSettingsGTK> mPrintSettings;
   bool mToPrinter : 1;      /* If true, print to printer */
   bool mIsPPreview : 1;     /* If true, is print preview */
   char   mPath[PATH_MAX];     /* If toPrinter = false, dest file */
   char   mPrinter[256];       /* Printer name */
--- a/widget/nsDeviceContextSpecProxy.cpp
+++ b/widget/nsDeviceContextSpecProxy.cpp
@@ -225,8 +225,20 @@ NS_IMETHODIMP
 nsDeviceContextSpecProxy::EndPage()
 {
   // Send the page recording to the parent.
   mRecorder->Close();
   mRemotePrintJob->ProcessPage(mRecordingFileName);
 
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::SendPDF(const nsAString& aPDFFileName)
+{
+  nsCString pdfname;
+  AppendUTF16toUTF8(aPDFFileName, pdfname);
+  // Send the file name to the parent.
+  mRemotePrintJob->ProcessPDF(pdfname);
+
+  return NS_OK;
+}
+
--- a/widget/nsDeviceContextSpecProxy.h
+++ b/widget/nsDeviceContextSpecProxy.h
@@ -49,16 +49,18 @@ public:
   NS_IMETHOD EndDocument() final;
 
   NS_IMETHOD AbortDocument() final;
 
   NS_IMETHOD BeginPage() final;
 
   NS_IMETHOD EndPage() final;
 
+  NS_IMETHOD SendPDF(const nsAString& aPDFFileName) final;
+
 private:
   ~nsDeviceContextSpecProxy() {}
 
   nsresult CreateUniqueTempPath(nsACString& aFilePath);
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   nsCOMPtr<nsIPrintSession> mPrintSession;
   nsCOMPtr<nsIDeviceContextSpec> mRealDeviceContextSpec;
--- a/widget/nsIDeviceContextSpec.h
+++ b/widget/nsIDeviceContextSpec.h
@@ -73,13 +73,14 @@ public:
                             const nsAString& aPrintToFileName,
                             int32_t          aStartPage,
                             int32_t          aEndPage) = 0;
 
    NS_IMETHOD EndDocument() = 0;
    NS_IMETHOD AbortDocument() { return EndDocument(); }
    NS_IMETHOD BeginPage() = 0;
    NS_IMETHOD EndPage() = 0;
+   NS_IMETHOD SendPDF(const nsAString& aPDFFileName) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDeviceContextSpec,
                               NS_IDEVICE_CONTEXT_SPEC_IID)
 #endif
--- a/widget/windows/nsDeviceContextSpecWin.h
+++ b/widget/windows/nsDeviceContextSpecWin.h
@@ -27,16 +27,17 @@ public:
   virtual already_AddRefed<PrintTarget> MakePrintTarget() final;
   NS_IMETHOD BeginDocument(const nsAString& aTitle,
                            const nsAString& aPrintToFileName,
                            int32_t          aStartPage,
                            int32_t          aEndPage) override { return NS_OK; }
   NS_IMETHOD EndDocument() override { return NS_OK; }
   NS_IMETHOD BeginPage() override { return NS_OK; }
   NS_IMETHOD EndPage() override { return NS_OK; }
+  NS_IMETHOD SendPDF(const nsAString& aPDFFileName) override { return NS_OK; }
 
   NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
 
   float GetDPI() final;
 
   float GetPrintingScale() final;
 
   void GetDriverName(wchar_t *&aDriverName) const   { aDriverName = mDriverName;     }