Bug 1156742 Part 14: Complete RemotePrintJob using PrintTranslator. r=mconley
☠☠ backed out by 9bdfae920430 ☠ ☠
authorBob Owen <bobowencode@gmail.com>
Mon, 21 Dec 2015 20:33:14 +0000
changeset 277226 de352000aae180f59f2a1fe4dee6ae1a1378b07d
parent 277225 4dd34ea230c633fb41d35f731840c4637aafbe4a
child 277227 7ac1c7e15a11ace9bd47e6acde84f6aa75f44da7
push id29819
push usercbook@mozilla.com
push dateTue, 22 Dec 2015 10:47:17 +0000
treeherdermozilla-central@ad16863d1d45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1156742
milestone46.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
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;
 }