Bug 1399787 - Part 6. Implement PDFiumParent. draft
authorcku <cku@mozilla.com>
Tue, 17 Oct 2017 15:53:14 +0800
changeset 686698 e54dde525f8d3c4c38028504ee8669a6f1a14851
parent 686697 1e9cf0c5635e1f94339f49adb30aa9164d173473
child 686699 488afc93b788a8f4984c2e5a81d7d0e4970cbbcb
push id86258
push usercku@mozilla.com
push dateThu, 26 Oct 2017 08:49:17 +0000
bugs1399787
milestone58.0a1
Bug 1399787 - Part 6. Implement PDFiumParent. MozReview-Commit-ID: 415xovMsiwN
widget/windows/PDFiumParent.cpp
widget/windows/PDFiumParent.h
widget/windows/PDFiumProcessParent.cpp
widget/windows/PDFiumProcessParent.h
widget/windows/nsDeviceContextSpecWin.cpp
widget/windows/nsDeviceContextSpecWin.h
--- a/widget/windows/PDFiumParent.cpp
+++ b/widget/windows/PDFiumParent.cpp
@@ -4,17 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PDFiumParent.h"
 #include "nsDeviceContextSpecWin.h"
 
 namespace mozilla {
 namespace widget {
 
-PDFiumParent::PDFiumParent()
+PDFiumParent::PDFiumParent(nsDeviceContextSpecWin* aDevSpec)
+  : mDevSpecWin(aDevSpec)
 {
 }
 
 PDFiumParent::~PDFiumParent()
 {
   Close();
 }
 
@@ -26,24 +27,27 @@ PDFiumParent::Init(IPC::Channel* aChanne
   }
 
   return true;
 }
 
 void
 PDFiumParent::ActorDestroy(ActorDestroyReason aWhy)
 {
+  mDevSpecWin->FinishPrint();
 }
 
 mozilla::ipc::IPCResult
 PDFiumParent::RecvFinishedEMFConversions()
 {
+  mDevSpecWin->FinishPrint();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 PDFiumParent::RecvDoneConvertingToEMF(const nsString& aEMFFilePath)
 {
+  mDevSpecWin->PrintEMF(aEMFFilePath);
   return IPC_OK();
 }
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/windows/PDFiumParent.h
+++ b/widget/windows/PDFiumParent.h
@@ -3,34 +3,37 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef PDFIUMPARENT_H_
 #define PDFIUMPARENT_H_
 
 #include "mozilla/widget/PPDFiumParent.h"
 
+class nsDeviceContextSpecWin;
 
 namespace mozilla {
 namespace widget {
 
 class PDFiumParent final : public PPDFiumParent {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDFiumParent)
 
-  explicit PDFiumParent();
+  explicit PDFiumParent(nsDeviceContextSpecWin* aDevSpec);
 
   bool Init(IPC::Channel* aChannel, base::ProcessId aPid);
 
 private:
   ~PDFiumParent();
 
   // PPDFiumParent functions.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvDoneConvertingToEMF(const nsString& aEMFFilePath) override;
   mozilla::ipc::IPCResult RecvFinishedEMFConversions() override;
+
+  RefPtr<nsDeviceContextSpecWin> mDevSpecWin;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // PDFIUMPARENT_H_
--- a/widget/windows/PDFiumProcessParent.cpp
+++ b/widget/windows/PDFiumProcessParent.cpp
@@ -24,27 +24,27 @@ PDFiumProcessParent::PDFiumProcessParent
 }
 
 PDFiumProcessParent::~PDFiumProcessParent()
 {
   MOZ_COUNT_DTOR(PDFiumProcessParent);
 }
 
 bool
-PDFiumProcessParent::Launch()
+PDFiumProcessParent::Launch(nsDeviceContextSpecWin* aDeviceContext)
 {
   mLaunchThread = NS_GetCurrentThread();
 
   if (!AsyncLaunch()) {
     return false;
   }
 
   // Open the top level protocol for PDFium process.
   MOZ_ASSERT(!mPDFiumActor);
-  mPDFiumActor = new PDFiumParent();
+  mPDFiumActor = new PDFiumParent(aDeviceContext);
   return mPDFiumActor->Init(GetChannel(),
                             base::GetProcId(GetChildProcessHandle()));
 }
 
 void
 PDFiumProcessParent::Delete()
 {
   // PDFiumProcessParent::Launch is not called, protocol is not created.
--- a/widget/windows/PDFiumProcessParent.h
+++ b/widget/windows/PDFiumProcessParent.h
@@ -25,22 +25,24 @@ namespace mozilla {
 namespace widget {
 
 class PDFiumProcessParent final : public mozilla::ipc::GeckoChildProcessHost
 {
 public:
   PDFiumProcessParent();
   ~PDFiumProcessParent();
 
-  bool Launch();
+  bool Launch(nsDeviceContextSpecWin* aDeviceContext);
 
   void Delete();
 
   bool CanShutdown() override { return true; }
 
+  PDFiumParent* GetActor() const { return mPDFiumActor; }
+
 private:
 
   DISALLOW_COPY_AND_ASSIGN(PDFiumProcessParent);
 
   RefPtr<PDFiumParent> mPDFiumActor;
   nsCOMPtr<nsIThread> mLaunchThread;
 };
 
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -37,16 +37,18 @@
 #ifdef MOZ_ENABLE_SKIA_PDF
 #include "mozilla/gfx/PrintTargetSkPDF.h"
 #include "nsIUUIDGenerator.h"
 #include "mozilla/widget/PDFViaEMFPrintHelper.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "PDFiumProcessParent.h"
+#include "PDFiumParent.h"
+#include "WindowsEMF.h"
 #endif
 
 static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
 #define PR_PL(_p1)  MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
@@ -97,18 +99,16 @@ struct AutoFreeGlobalPrinters
 
 //----------------------------------------------------------------------------------
 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
 {
   mDevMode       = nullptr;
 #ifdef MOZ_ENABLE_SKIA_PDF
   mPrintViaSkPDF          = false;
   mDC                     = NULL;
-  mPDFPageCount           = 0;
-  mPDFCurrentPageNum      = 0;
   mPrintViaPDFInProgress  = false;
   mPDFiumProcess = nullptr;
 #endif
 }
 
 
 //----------------------------------------------------------------------------------
 
@@ -352,24 +352,27 @@ nsDeviceContextSpecWin::GetPrintingScale
   // The print settings will have the resolution stored from the real device.
   int32_t resolution;
   mPrintSettings->GetResolution(&resolution);
   return float(resolution) / GetDPI();
 }
 
 #ifdef MOZ_ENABLE_SKIA_PDF
 void
+nsDeviceContextSpecWin::FinishPrint()
+{
+  NS_DispatchToMainThread(NewRunnableMethod(
+    "nsDeviceContextSpecWin::CleanupPrintViaPDF",
+    this,
+    &nsDeviceContextSpecWin::CleanupPrintViaPDF));
+}
+
+void
 nsDeviceContextSpecWin::CleanupPrintViaPDF()
 {
-  if (mPDFPrintHelper) {
-    mPDFPrintHelper->CloseDocument();
-    mPDFPrintHelper = nullptr;
-    mPDFPageCount = 0;
-  }
-
   if (mPDFTempFile) {
     mPDFTempFile->Remove(/* aRecursive */ false);
     mPDFTempFile = nullptr;
   }
 
   if (mDC != NULL) {
     if (mPrintViaPDFInProgress) {
       ::EndDoc(mDC);
@@ -381,46 +384,47 @@ nsDeviceContextSpecWin::CleanupPrintViaP
 
   if (mPDFiumProcess) {
     mPDFiumProcess->Delete();
     mPDFiumProcess = nullptr;
   }
 }
 
 void
-nsDeviceContextSpecWin::FinishPrintViaPDF()
+nsDeviceContextSpecWin::PrintEMFInternal(nsString aEMFFilePath)
 {
-  MOZ_ASSERT(mDC != NULL);
-  MOZ_ASSERT(mPDFPrintHelper);
-  MOZ_ASSERT(mPDFTempFile);
-  MOZ_ASSERT(mPrintViaPDFInProgress);
+  if (::StartPage(mDC) > 0) {
+    WindowsEMF emf;
+    if (emf.InitFromFileContents(aEMFFilePath.get())) {
+      RECT printRect = {0, 0, ::GetDeviceCaps(mDC, HORZRES),
+                        ::GetDeviceCaps(mDC, VERTRES)};
+      emf.Playback(mDC, printRect);
+    }
 
-  bool isPrinted = false;
-  bool endPageSuccess = false;
-  if (::StartPage(mDC) > 0) {
-    isPrinted = mPDFPrintHelper->DrawPage(mDC, mPDFCurrentPageNum++,
-                                          ::GetDeviceCaps(mDC, HORZRES),
-                                          ::GetDeviceCaps(mDC, VERTRES));
-    if (::EndPage(mDC) > 0) {
-      endPageSuccess = true;
-    }
+    ::EndPage(mDC);
   }
 
-  if (mPDFCurrentPageNum < mPDFPageCount && isPrinted && endPageSuccess) {
-    nsresult rv = NS_DispatchToCurrentThread(NewRunnableMethod(
-      "nsDeviceContextSpecWin::PrintPDFOnThread",
+  // Delete the intermediate EMF file.
+  nsCOMPtr<nsIFile> emfFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
+  if (emfFile) {
+    emfFile->InitWithPath(aEMFFilePath);
+    emfFile->Remove(/* aRecursive */ false);
+  }
+}
+
+void
+nsDeviceContextSpecWin::PrintEMF(const nsString& aEMFFilePath)
+{
+  NS_DispatchToCurrentThread(NewRunnableMethod<nsString>(
+      "nsDeviceContextSpecWin::PrintEMFInternal",
       this,
-      &nsDeviceContextSpecWin::FinishPrintViaPDF));
-    if (NS_SUCCEEDED(rv)) {
-      return;
-    }
-  }
+      &nsDeviceContextSpecWin::PrintEMFInternal,
+      aEMFFilePath));
+}
 
-  CleanupPrintViaPDF();
-}
 #endif
 
 nsresult
 nsDeviceContextSpecWin::BeginDocument(const nsAString& aTitle,
                                       const nsAString& aPrintToFileName,
                                       int32_t          aStartPage,
                                       int32_t          aEndPage)
 {
@@ -457,52 +461,38 @@ nsDeviceContextSpecWin::BeginDocument(co
     if (::StartDocW(mDC, &di) <= 0) {
       // Defer calling CleanupPrintViaPDF() in destructor because PDF temp file
       // is not ready yet.
       return NS_ERROR_FAILURE;
     }
 
     mPrintViaPDFInProgress = true;
 
-    MOZ_ASSERT(!mPDFiumProcess);
+    MOZ_ASSERT(!mPDFiumProcess && mDC);
     mPDFiumProcess = new PDFiumProcessParent();
     NS_ENSURE_TRUE(mPDFiumProcess->Launch(this), NS_ERROR_FAILURE);
   }
 #endif
 
   return NS_OK;
 }
 
 nsresult
 nsDeviceContextSpecWin::EndDocument()
 {
   nsresult rv = NS_OK;
 #ifdef MOZ_ENABLE_SKIA_PDF
-  if (mPrintViaSkPDF &&
-      mOutputFormat != nsIPrintSettings::kOutputFormatPDF &&
-      mPrintViaPDFInProgress) {
-
-    mPDFPrintHelper = MakeUnique<PDFViaEMFPrintHelper>();
-    rv = mPDFPrintHelper->OpenDocument(mPDFTempFile);
+  if (mPDFiumProcess) {
+    MOZ_ASSERT(mDC);
+    nsAutoString pdfFilePath;
+    rv = mPDFTempFile->GetPath(pdfFilePath);
     NS_ENSURE_SUCCESS(rv, rv);
-    mPDFPageCount = mPDFPrintHelper->GetPageCount();
-    if (mPDFPageCount <= 0) {
-      CleanupPrintViaPDF();
-      return NS_ERROR_FAILURE;
-    }
-    mPDFCurrentPageNum = 0;
-
-    rv = NS_DispatchToCurrentThread(NewRunnableMethod(
-      "nsDeviceContextSpecWin::PrintPDFOnThread",
-      this,
-      &nsDeviceContextSpecWin::FinishPrintViaPDF));
-    if (NS_FAILED(rv)) {
-      CleanupPrintViaPDF();
-      NS_WARNING("Failed to dispatch to the current thread!");
-    }
+    mPDFiumProcess->GetActor()->SendConvertToEMF(pdfFilePath,
+                                                 ::GetDeviceCaps(mDC, HORZRES),
+                                                 ::GetDeviceCaps(mDC, VERTRES));
   }
 #endif
   return rv;
 }
 
 //----------------------------------------------------------------------------------
 void nsDeviceContextSpecWin::SetDeviceName(const nsAString& aDeviceName)
 {
--- a/widget/windows/nsDeviceContextSpecWin.h
+++ b/widget/windows/nsDeviceContextSpecWin.h
@@ -61,45 +61,47 @@ public:
   // To get the DevMode from the Global memory Handle it must lock it 
   // So this call must be paired with a call to UnlockGlobalHandle
   void GetDevMode(LPDEVMODEW &aDevMode);
 
   // helper functions
   nsresult GetDataFromPrinter(const nsAString& aName,
                               nsIPrintSettings* aPS = nullptr);
 
+#ifdef MOZ_ENABLE_SKIA_PDF
+  void PrintEMF(const nsString& aEMFFilePath);
+  void FinishPrint();
+#endif
+
 protected:
 
   void SetDeviceName(const nsAString& aDeviceName);
   void SetDriverName(const nsAString& aDriverName);
   void SetDevMode(LPDEVMODEW aDevMode);
 
   virtual ~nsDeviceContextSpecWin();
 
   nsString mDriverName;
   nsString mDeviceName;
   LPDEVMODEW mDevMode;
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   int16_t mOutputFormat = nsIPrintSettings::kOutputFormatNative;
 
 #ifdef MOZ_ENABLE_SKIA_PDF
-  void  FinishPrintViaPDF();
-  void  CleanupPrintViaPDF();
+  void PrintEMFInternal(nsString aEMFFilePath);
+  void CleanupPrintViaPDF();
 
   // This variable is independant of nsIPrintSettings::kOutputFormatPDF.
   // It controls both whether normal printing is done via PDF using Skia and
   // whether print-to-PDF uses Skia.
   bool mPrintViaSkPDF;
   nsCOMPtr<nsIFile> mPDFTempFile;
   HDC mDC;
   bool mPrintViaPDFInProgress;
-  mozilla::UniquePtr<PDFViaEMFPrintHelper> mPDFPrintHelper;
-  int mPDFPageCount;
-  int mPDFCurrentPageNum;
 
   PDFiumProcessParent* mPDFiumProcess;
 #endif
 };
 
 
 //-------------------------------------------------------------------------
 // Printer Enumerator