Bug 1156742 Part 14: Complete RemotePrintJob using PrintTranslator. r=mconley
authorBob Owen <bobowencode@gmail.com>
Tue, 05 Jan 2016 10:08:57 +0000
changeset 300717 f17ecf3189bd4a25e806a71ed4ae2be40e82440f
parent 300716 6c13b972933639299aceef19b6541e9412ef9242
child 300718 dda221fc2e37196dc96413b2c6d04b5ae86441fd
push id8978
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 14:05:32 +0000
treeherdermozilla-aurora@b9a803752a2c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1156742
milestone46.0a1
Bug 1156742 Part 14: Complete RemotePrintJob using PrintTranslator. r=mconley
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
widget/nsDeviceContextSpecProxy.cpp
--- a/layout/printing/ipc/PRemotePrintJob.ipdl
+++ b/layout/printing/ipc/PRemotePrintJob.ipdl
@@ -28,16 +28,20 @@ parent:
   async ProcessPage(Shmem aStoredPage);
 
   // This informs the real print device that we've finished, so it can trigger
   // the actual print.
   async FinalizePrint();
 
 
 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();
 
   async __delete__();
 };
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -13,16 +13,50 @@
 namespace mozilla {
 namespace layout {
 
 RemotePrintJobChild::RemotePrintJobChild()
 {
   MOZ_COUNT_CTOR(RemotePrintJobChild);
 }
 
+nsresult
+RemotePrintJobChild::InitializePrint(const nsString& aDocumentTitle,
+                                     const nsString& aPrintToFile,
+                                     const int32_t& aStartPage,
+                                     const int32_t& aEndPage)
+{
+  // Print initialization can sometimes display a dialog in the parent, so we
+  // need to spin a nested event loop until initialization completes.
+  Unused << SendInitializePrint(aDocumentTitle, aPrintToFile, aStartPage,
+                                aEndPage);
+  while (!mPrintInitialized) {
+    Unused << NS_ProcessNextEvent();
+  }
+
+  return mInitializationResult;
+}
+
+bool
+RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv)
+{
+  mPrintInitialized = true;
+  mInitializationResult = aRv;
+  return true;
+}
+
+void
+RemotePrintJobChild::ProcessPage(Shmem& aStoredPage)
+{
+  MOZ_ASSERT(mPagePrintTimer);
+
+  mPagePrintTimer->WaitForRemotePrint();
+  Unused << SendProcessPage(aStoredPage);
+}
+
 bool
 RemotePrintJobChild::RecvPageProcessed()
 {
   MOZ_ASSERT(mPagePrintTimer);
 
   mPagePrintTimer->RemotePrintFinished();
   return true;
 }
@@ -32,25 +66,16 @@ RemotePrintJobChild::RecvAbortPrint(cons
 {
   MOZ_ASSERT(mPrintEngine);
 
   mPrintEngine->CleanupOnFailure(aRv, true);
   return true;
 }
 
 void
-RemotePrintJobChild::ProcessPage(Shmem& aStoredPage)
-{
-  MOZ_ASSERT(mPagePrintTimer);
-
-  mPagePrintTimer->WaitForRemotePrint();
-  Unused << SendProcessPage(aStoredPage);
-}
-
-void
 RemotePrintJobChild::SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer)
 {
   MOZ_ASSERT(aPagePrintTimer);
 
   mPagePrintTimer = aPagePrintTimer;
 }
 
 void
--- a/layout/printing/ipc/RemotePrintJobChild.h
+++ b/layout/printing/ipc/RemotePrintJobChild.h
@@ -21,29 +21,38 @@ class RemotePrintJobChild final : public
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(RemotePrintJobChild)
 
   RemotePrintJobChild();
 
   void ActorDestroy(ActorDestroyReason aWhy) final;
 
+  nsresult InitializePrint(const nsString& aDocumentTitle,
+                           const nsString& aPrintToFile,
+                           const int32_t& aStartPage,
+                           const int32_t& aEndPage);
+
+  bool RecvPrintInitializationResult(const nsresult& aRv) final;
+
+  void ProcessPage(Shmem& aStoredPage);
+
   bool RecvPageProcessed() final;
 
   bool RecvAbortPrint(const nsresult& aRv) final;
 
-  void ProcessPage(Shmem& aStoredPage);
-
   void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer);
 
   void SetPrintEngine(nsPrintEngine* aPrintEngine);
 
 private:
   ~RemotePrintJobChild() final;
 
+  bool mPrintInitialized = false;
+  nsresult mInitializationResult = NS_OK;
   RefPtr<nsPagePrintTimer> mPagePrintTimer;
   RefPtr<nsPrintEngine> mPrintEngine;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif // mozilla_layout_RemotePrintJobChild_h
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -1,56 +1,159 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RemotePrintJobParent.h"
 
+#include <istream>
+
+#include "gfxContext.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/unused.h"
+#include "nsComponentManagerUtils.h"
+#include "nsDeviceContext.h"
+#include "nsIDeviceContextSpec.h"
 #include "nsIPrintSettings.h"
+#include "PrintTranslator.h"
 
 namespace mozilla {
 namespace layout {
 
 RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings)
   : mPrintSettings(aPrintSettings)
 {
   MOZ_COUNT_CTOR(RemotePrintJobParent);
 }
 
 bool
 RemotePrintJobParent::RecvInitializePrint(const nsString& aDocumentTitle,
                                           const nsString& aPrintToFile,
                                           const int32_t& aStartPage,
                                           const int32_t& aEndPage)
 {
-  NS_NOTREACHED("RemotePrintJobParent::RecvInitializePrint not implemented!");
-  return false;
+  nsresult rv = InitializePrintDevice(aDocumentTitle, aPrintToFile, aStartPage,
+                                      aEndPage);
+  if (NS_FAILED(rv)) {
+    Unused << SendPrintInitializationResult(rv);
+    Unused << Send__delete__(this);
+    return true;
+  }
+
+  mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext));
+  Unused << SendPrintInitializationResult(NS_OK);
+
+  return true;
+}
+
+nsresult
+RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle,
+                                            const nsString& aPrintToFile,
+                                            const int32_t& aStartPage,
+                                            const int32_t& aEndPage)
+{
+  nsresult rv;
+  nsCOMPtr<nsIDeviceContextSpec> deviceContextSpec =
+  do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = deviceContextSpec->Init(nullptr, mPrintSettings, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mPrintDeviceContext = new nsDeviceContext();
+  rv = mPrintDeviceContext->InitForPrinting(deviceContextSpec);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = mPrintDeviceContext->BeginDocument(aDocumentTitle, aPrintToFile,
+                                          aStartPage, aEndPage);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
 }
 
 bool
 RemotePrintJobParent::RecvProcessPage(Shmem&& aStoredPage)
 {
-  NS_NOTREACHED("PrintingParent::RecvProcessPage not implemented!");
-  return false;
+  nsresult rv = PrintPage(aStoredPage);
+
+  // Always deallocate the shared memory no matter what the result.
+  if (!DeallocShmem(aStoredPage)) {
+    NS_WARNING("Failed to deallocated shared memory, remote print will abort.");
+    rv = NS_ERROR_FAILURE;
+  }
+
+  if (NS_FAILED(rv)) {
+    Unused << SendAbortPrint(rv);
+  } else {
+    Unused << SendPageProcessed();
+  }
+
+  return true;
+}
+
+nsresult
+RemotePrintJobParent::PrintPage(const Shmem& aStoredPage)
+{
+  MOZ_ASSERT(mPrintDeviceContext);
+
+  nsresult rv = mPrintDeviceContext->BeginPage();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  std::istringstream recording(std::string(aStoredPage.get<char>(),
+                                           aStoredPage.Size<char>()));
+  mPrintTranslator->TranslateRecording(recording);
+
+  rv = mPrintDeviceContext->EndPage();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mPrintTranslator->ClearSavedFonts();
+
+  return NS_OK;
 }
 
 bool
 RemotePrintJobParent::RecvFinalizePrint()
 {
-  NS_NOTREACHED("PrintingParent::RecvFinalizePrint not implemented!");
-  return false;
+  // EndDocument is sometimes called in the child even when BeginDocument has
+  // not been called. See bug 1223332.
+  if (mPrintDeviceContext) {
+    nsresult rv = mPrintDeviceContext->EndDocument();
+
+    // Too late to abort the child just log.
+    NS_WARN_IF(NS_FAILED(rv));
+  }
+
+
+  Unused << Send__delete__(this);
+  return true;
 }
 
 bool
 RemotePrintJobParent::RecvAbortPrint(const nsresult& aRv)
 {
-  NS_NOTREACHED("PrintingParent::RecvAbortPrint not implemented!");
-  return false;
+  if (mPrintDeviceContext) {
+    Unused << mPrintDeviceContext->AbortDocument();
+  }
+
+  Unused << Send__delete__(this);
+  return true;
 }
 
 RemotePrintJobParent::~RemotePrintJobParent()
 {
   MOZ_COUNT_DTOR(RemotePrintJobParent);
 }
 
 void
--- a/layout/printing/ipc/RemotePrintJobParent.h
+++ b/layout/printing/ipc/RemotePrintJobParent.h
@@ -5,18 +5,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_RemotePrintJobParent_h
 #define mozilla_layout_RemotePrintJobParent_h
 
 #include "mozilla/layout/PRemotePrintJobParent.h"
 
 #include "nsCOMPtr.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
 
+class nsDeviceContext;
 class nsIPrintSettings;
+class PrintTranslator;
 
 namespace mozilla {
 namespace layout {
 
 class RemotePrintJobParent final : public PRemotePrintJobParent
 {
 public:
   explicit RemotePrintJobParent(nsIPrintSettings* aPrintSettings);
@@ -32,15 +36,24 @@ public:
 
   bool RecvFinalizePrint() final;
 
   bool RecvAbortPrint(const nsresult& aRv) final;
 
 private:
   ~RemotePrintJobParent() final;
 
+  nsresult InitializePrintDevice(const nsString& aDocumentTitle,
+                                 const nsString& aPrintToFile,
+                                 const int32_t& aStartPage,
+                                 const int32_t& aEndPage);
+
+  nsresult PrintPage(const Shmem& aStoredPage);
+
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
+  RefPtr<nsDeviceContext> mPrintDeviceContext;
+  UniquePtr<PrintTranslator> mPrintTranslator;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif // mozilla_layout_RemotePrintJobParent_h
--- a/widget/nsDeviceContextSpecProxy.cpp
+++ b/widget/nsDeviceContextSpecProxy.cpp
@@ -118,20 +118,19 @@ nsDeviceContextSpecProxy::GetPrintingSca
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle,
                                         const nsAString& aPrintToFileName,
                                         int32_t aStartPage, int32_t aEndPage)
 {
   mRecorder = new DrawEventRecorderMemory();
-  Unused << mRemotePrintJob->SendInitializePrint(nsString(aTitle),
-                                                 nsString(aPrintToFileName),
-                                                 aStartPage, aEndPage);
-  return NS_OK;
+  return mRemotePrintJob->InitializePrint(nsString(aTitle),
+                                          nsString(aPrintToFileName),
+                                          aStartPage, aEndPage);
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecProxy::EndDocument()
 {
   Unused << mRemotePrintJob->SendFinalizePrint();
   return NS_OK;
 }