Bug 1156742 Part 9: Add a new nsIDeviceContextSpec for proxied printing. r=roc
authorBob Owen <bobowencode@gmail.com>
Tue, 05 Jan 2016 10:08:57 +0000
changeset 278420 f9f91b619a87c5c7142a396b62a5f90145fb3811
parent 278419 ced236c18d9d457fbc50bcd15e2c6364536e0223
child 278421 e42b8b6de581f8ca772c30a588e54e31a1e88347
push id69783
push userbobowencode@gmail.com
push dateTue, 05 Jan 2016 10:09:19 +0000
treeherdermozilla-inbound@33e805e80b96 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
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 9: Add a new nsIDeviceContextSpec for proxied printing. r=roc This also changes aPrintToFileName parameter for BeginDocument to an nsAString& from char16_t*. Having a char16_t* caused a pain with VS2105 where wchar_t != char16_t (as on VS2103), after it had been sent over IPDL. This could have been worked around with casting, but this seemed like the tidier solution.
gfx/2d/DrawEventRecorder.cpp
gfx/2d/DrawTargetRecording.cpp
gfx/2d/RecordedEvent.cpp
gfx/2d/RecordedEvent.h
gfx/2d/moz.build
gfx/src/nsDeviceContext.cpp
gfx/src/nsDeviceContext.h
layout/printing/nsPrintEngine.cpp
widget/android/nsDeviceContextAndroid.cpp
widget/android/nsDeviceContextAndroid.h
widget/cocoa/nsDeviceContextSpecX.h
widget/cocoa/nsDeviceContextSpecX.mm
widget/gtk/nsDeviceContextSpecG.cpp
widget/gtk/nsDeviceContextSpecG.h
widget/moz.build
widget/nsDeviceContextSpecProxy.cpp
widget/nsDeviceContextSpecProxy.h
widget/nsIDeviceContextSpec.h
widget/nsPrimitiveHelpers.cpp
widget/qt/nsDeviceContextSpecQt.cpp
widget/qt/nsDeviceContextSpecQt.h
widget/windows/nsDeviceContextSpecWin.h
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "DrawEventRecorder.h"
 #include "PathRecording.h"
+#include "RecordingTypes.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
 
 const uint32_t kMagicInt = 0xc001feed;
 
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -7,16 +7,17 @@
 #include "DrawTargetRecording.h"
 #include "PathRecording.h"
 #include <stdio.h>
 
 #include "Logging.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "mozilla/UniquePtr.h"
+#include "RecordingTypes.h"
 
 namespace mozilla {
 namespace gfx {
 
 struct RecordingSourceSurfaceUserData
 {
   void *refPtr;
   RefPtr<DrawEventRecorderPrivate> recorder;
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "RecordedEvent.h"
+
 #include "PathRecording.h"
-
+#include "RecordingTypes.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -5,22 +5,24 @@
 
 #ifndef MOZILLA_GFX_RECORDEDEVENT_H_
 #define MOZILLA_GFX_RECORDEDEVENT_H_
 
 #include "2D.h"
 #include <ostream>
 #include <sstream>
 #include <cstring>
-#include "RecordingTypes.h"
-#include "PathRecording.h"
+#include <vector>
 
 namespace mozilla {
 namespace gfx {
 
+struct PathOp;
+class PathRecording;
+
 // A change in major revision means a change in event binary format, causing
 // loss of backwards compatibility. Old streams will not work in a player
 // using a newer major revision. And new streams will not work in a player
 // using an older major revision.
 const uint16_t kMajorRevision = 3;
 // A change in minor revision means additions of new events. New streams will
 // not play in older players.
 const uint16_t kMinorRevision = 2;
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -17,32 +17,34 @@ EXPORTS.mozilla.gfx += [
     'BasePoint4D.h',
     'BaseRect.h',
     'BaseSize.h',
     'Blur.h',
     'BorrowedContext.h',
     'Coord.h',
     'CriticalSection.h',
     'DataSurfaceHelpers.h',
+    'DrawEventRecorder.h',
     'DrawTargetTiled.h',
     'Filters.h',
     'Helpers.h',
     'HelpersCairo.h',
     'IterableArena.h',
     'JobScheduler.h',
     'JobScheduler_posix.h',
     'JobScheduler_win32.h',
     'Logging.h',
     'Matrix.h',
     'MatrixFwd.h',
     'NumericTools.h',
     'PathHelpers.h',
     'PatternHelpers.h',
     'Point.h',
     'Quaternion.h',
+    'RecordedEvent.h',
     'Rect.h',
     'Scale.h',
     'ScaleFactor.h',
     'ScaleFactors2D.h',
     'SourceSurfaceCairo.h',
     'SourceSurfaceRawData.h',
     'StackArray.h',
     'Tools.h',
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -395,16 +395,22 @@ nsDeviceContext::CreateRenderingContext(
 
     // This can legitimately happen - CreateDrawTargetForSurface will fail
     // to create a draw target if the size is too large, for instance.
     if (!dt) {
         gfxCriticalNote << "Failed to create draw target in device context sized " << mWidth << "x" << mHeight << " and pointers " << hexa(mPrintingSurface) << " and " << hexa(printingSurface);
         return nullptr;
     }
 
+    RefPtr<DrawEventRecorder> recorder;
+    nsresult rv = mDeviceContextSpec->GetDrawEventRecorder(getter_AddRefs(recorder));
+    if (NS_SUCCEEDED(rv) && recorder) {
+      dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dt);
+    }
+
 #ifdef XP_MACOSX
     dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
 #endif
     dt->AddUserData(&sDisablePixelSnapping, (void*)0x1, nullptr);
 
     RefPtr<gfxContext> pContext = new gfxContext(dt);
 
     gfxMatrix transform;
@@ -501,28 +507,26 @@ nsDeviceContext::InitForPrinting(nsIDevi
         return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
 }
 
 nsresult
 nsDeviceContext::BeginDocument(const nsAString& aTitle,
-                               char16_t*       aPrintToFileName,
+                               const nsAString& aPrintToFileName,
                                int32_t          aStartPage,
                                int32_t          aEndPage)
 {
-    static const char16_t kEmpty[] = { '\0' };
-    nsresult rv;
+    nsresult rv = mPrintingSurface->BeginPrinting(aTitle, aPrintToFileName);
 
-    rv = mPrintingSurface->BeginPrinting(aTitle,
-                                         nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty));
-
-    if (NS_SUCCEEDED(rv) && mDeviceContextSpec)
-        rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage);
+    if (NS_SUCCEEDED(rv) && mDeviceContextSpec) {
+      rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName,
+                                             aStartPage, aEndPage);
+    }
 
     return rv;
 }
 
 
 nsresult
 nsDeviceContext::EndDocument(void)
 {
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -177,26 +177,26 @@ public:
     nsresult GetClientRect(nsRect& aRect);
 
     /**
      * Inform the output device that output of a document is beginning
      * Used for print related device contexts. Must be matched 1:1 with
      * EndDocument() or AbortDocument().
      *
      * @param aTitle - title of Document
-     * @param aPrintToFileName - name of file to print to, if nullptr
-     * then don't print to file
+     * @param aPrintToFileName - name of file to print to, if empty then don't
+     *                           print to file
      * @param aStartPage - starting page number (must be greater than zero)
      * @param aEndPage - ending page number (must be less than or
      * equal to number of pages)
      *
      * @return error status
      */
     nsresult BeginDocument(const nsAString& aTitle,
-                           char16_t*       aPrintToFileName,
+                           const nsAString& aPrintToFileName,
                            int32_t          aStartPage,
                            int32_t          aEndPage);
 
     /**
      * Inform the output device that output of a document is ending.
      * Used for print related device contexts. Must be matched 1:1 with
      * BeginDocument()
      * @return error status
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -1673,24 +1673,25 @@ nsPrintEngine::SetupToPrintContent()
   PR_PL(("--- Printing %d pages\n", mPrt->mNumPrintablePages));
   DUMP_DOC_TREELAYOUT;
 
   // Print listener setup...
   if (mPrt != nullptr) {
     mPrt->OnStartPrinting();    
   }
 
-  char16_t* fileName = nullptr;
+  nsAutoString fileNameStr;
   // check to see if we are printing to a file
   bool isPrintToFile = false;
   mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile);
   if (isPrintToFile) {
-  // On some platforms The BeginDocument needs to know the name of the file
-  // and it uses the PrintService to get it, so we need to set it into the PrintService here
+    // On some platforms The BeginDocument needs to know the name of the file.
+    char16_t* fileName = nullptr;
     mPrt->mPrintSettings->GetToFileName(&fileName);
+    fileNameStr = fileName;
   }
 
   nsAutoString docTitleStr;
   nsAutoString docURLStr;
   GetDisplayTitleAndURL(mPrt->mPrintObject, docTitleStr, docURLStr, eDocTitleDefURLDoc);
 
   int32_t startPage = 1;
   int32_t endPage   = mPrt->mNumPrintablePages;
@@ -1706,17 +1707,18 @@ nsPrintEngine::SetupToPrintContent()
   }
 
   rv = NS_OK;
   // BeginDocument may pass back a FAILURE code
   // i.e. On Windows, if you are printing to a file and hit "Cancel" 
   //      to the "File Name" dialog, this comes back as an error
   // Don't start printing when regression test are executed  
   if (!mPrt->mDebugFilePtr && mIsDoingPrinting) {
-    rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage);
+    rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileNameStr, startPage,
+                                       endPage);
   } 
 
   if (mIsCreatingPrintPreview) {
     // Copy docTitleStr and docURLStr to the pageSequenceFrame, to be displayed
     // in the header
     nsIPageSequenceFrame *seqFrame = mPrt->mPrintObject->mPresShell->GetPageSequenceFrame();
     if (seqFrame) {
       seqFrame->StartPrint(mPrt->mPrintObject->mPresContext, 
--- a/widget/android/nsDeviceContextAndroid.cpp
+++ b/widget/android/nsDeviceContextAndroid.cpp
@@ -47,17 +47,17 @@ nsDeviceContextSpecAndroid::Init(nsIWidg
                              bool aIsPrintPreview)
 {
   mPrintSettings = aPS;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecAndroid::BeginDocument(const nsAString& aTitle,
-                                          char16_t* aPrintToFileName,
+                                          const nsAString& aPrintToFileName,
                                           int32_t aStartPage,
                                           int32_t aEndPage)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDeviceContextSpecAndroid::EndDocument()
--- a/widget/android/nsDeviceContextAndroid.h
+++ b/widget/android/nsDeviceContextAndroid.h
@@ -14,17 +14,17 @@ public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD GetSurfaceForPrinter(gfxASurface** surface) override;
 
     NS_IMETHOD Init(nsIWidget* aWidget,
                     nsIPrintSettings* aPS,
                     bool aIsPrintPreview) override;
     NS_IMETHOD BeginDocument(const nsAString& aTitle,
-                             char16_t* aPrintToFileName,
+                             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; }
 
 private:
     nsCOMPtr<nsIPrintSettings> mPrintSettings;
--- a/widget/cocoa/nsDeviceContextSpecX.h
+++ b/widget/cocoa/nsDeviceContextSpecX.h
@@ -15,17 +15,17 @@ class nsDeviceContextSpecX : public nsID
 public:
     NS_DECL_ISUPPORTS
 
     nsDeviceContextSpecX();
 
     NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
     NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface) override;
     NS_IMETHOD BeginDocument(const nsAString& aTitle,
-                             char16_t*       aPrintToFileName,
+                             const nsAString& aPrintToFileName,
                              int32_t          aStartPage,
                              int32_t          aEndPage) override;
     NS_IMETHOD EndDocument() override;
     NS_IMETHOD BeginPage() override;
     NS_IMETHOD EndPage() override;
 
     void GetPaperRect(double* aTop, double* aLeft, double* aBottom, double* aRight);
 
--- a/widget/cocoa/nsDeviceContextSpecX.mm
+++ b/widget/cocoa/nsDeviceContextSpecX.mm
@@ -54,17 +54,17 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init
   mPrintSettings = settings->GetPMPrintSettings();
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
 NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle, 
-                                                  char16_t*       aPrintToFileName,
+                                                  const nsAString& aPrintToFileName,
                                                   int32_t          aStartPage, 
                                                   int32_t          aEndPage)
 {
     NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
     if (!aTitle.IsEmpty()) {
       CFStringRef cfString =
         ::CFStringCreateWithCharacters(NULL, reinterpret_cast<const UniChar*>(aTitle.BeginReading()),
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -295,18 +295,20 @@ void nsDeviceContextSpecGTK::StartPrintJ
 
 void
 nsDeviceContextSpecGTK::EnumeratePrinters()
 {
   gtk_enumerate_printers(&nsDeviceContextSpecGTK::PrinterEnumerator, this,
                          nullptr, TRUE);
 }
 
-NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle, char16_t * aPrintToFileName,
-                                                    int32_t aStartPage, int32_t aEndPage)
+NS_IMETHODIMP
+nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle,
+                                      const nsAString& aPrintToFileName,
+                                      int32_t aStartPage, int32_t aEndPage)
 {
   mTitle.Truncate();
   AppendUTF16toUTF8(aTitle, mTitle);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceContextSpecGTK::EndDocument()
 {
--- a/widget/gtk/nsDeviceContextSpecG.h
+++ b/widget/gtk/nsDeviceContextSpecG.h
@@ -29,17 +29,18 @@ public:
   nsDeviceContextSpecGTK();
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface) override;
 
   NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS,
                   bool aIsPrintPreview) override;
-  NS_IMETHOD BeginDocument(const nsAString& aTitle, char16_t * aPrintToFileName,
+  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; }
 
 protected:
   virtual ~nsDeviceContextSpecGTK();
   nsCOMPtr<nsPrintSettingsGTK> mPrintSettings;
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -143,16 +143,17 @@ UNIFIED_SOURCES += [
     'InputData.cpp',
     'nsBaseAppShell.cpp',
     'nsBaseDragService.cpp',
     'nsBaseScreen.cpp',
     'nsClipboardHelper.cpp',
     'nsClipboardProxy.cpp',
     'nsColorPickerProxy.cpp',
     'nsContentProcessWidgetFactory.cpp',
+    'nsDeviceContextSpecProxy.cpp',
     'nsDragServiceProxy.cpp',
     'nsFilePickerProxy.cpp',
     'nsHTMLFormatConverter.cpp',
     'nsIdleService.cpp',
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
     'nsPrintSession.cpp',
     'nsPrintSettingsImpl.cpp',
new file mode 100644
--- /dev/null
+++ b/widget/nsDeviceContextSpecProxy.cpp
@@ -0,0 +1,179 @@
+/* -*- 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 "nsDeviceContextSpecProxy.h"
+
+#include "gfxASurface.h"
+#include "gfxPlatform.h"
+#include "mozilla/gfx/DrawEventRecorder.h"
+#include "mozilla/layout/RemotePrintJobChild.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/unused.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIPrintSession.h"
+#include "nsIPrintSettings.h"
+
+using mozilla::Unused;
+
+NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec)
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::Init(nsIWidget* aWidget,
+                               nsIPrintSettings* aPrintSettings,
+                               bool aIsPrintPreview)
+{
+  nsresult rv;
+  mRealDeviceContextSpec =
+    do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mRealDeviceContextSpec->Init(nullptr, aPrintSettings, false);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mRealDeviceContextSpec = nullptr;
+    return rv;
+  }
+
+  mPrintSettings = aPrintSettings;
+
+  if (aIsPrintPreview) {
+    return NS_OK;
+  }
+
+  // nsIPrintSettings only has a weak reference to nsIPrintSession, so we hold
+  // it to make sure it's available for the lifetime of the print.
+  rv = mPrintSettings->GetPrintSession(getter_AddRefs(mPrintSession));
+  if (NS_FAILED(rv) || !mPrintSession) {
+    NS_WARNING("We can't print via the parent without an nsIPrintSession.");
+    return rv;
+  }
+
+  rv = mPrintSession->GetRemotePrintJob(getter_AddRefs(mRemotePrintJob));
+  if (NS_FAILED(rv) || !mRemotePrintJob) {
+    NS_WARNING("We can't print via the parent without a RemotePrintJobChild.");
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::GetSurfaceForPrinter(gfxASurface** aSurface)
+{
+  MOZ_ASSERT(aSurface);
+  MOZ_ASSERT(mRealDeviceContextSpec);
+
+  // The real device context may need to have created a real printing surface
+  // even though we're not using it directly.
+  nsresult rv = mRealDeviceContextSpec->GetSurfaceForPrinter(aSurface);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  double width, height;
+  rv = mPrintSettings->GetEffectivePageSize(&width, &height);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // convert twips to points
+  width /= TWIPS_PER_POINT_FLOAT;
+  height /= TWIPS_PER_POINT_FLOAT;
+
+  RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
+    CreateOffscreenSurface(mozilla::gfx::IntSize(width, height),
+                           gfxImageFormat::ARGB32);
+
+  surface.forget(aSurface);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder)
+{
+  MOZ_ASSERT(aDrawEventRecorder);
+  RefPtr<mozilla::gfx::DrawEventRecorder> result = mRecorder;
+  result.forget(aDrawEventRecorder);
+  return NS_OK;
+}
+
+float
+nsDeviceContextSpecProxy::GetDPI()
+{
+  MOZ_ASSERT(mRealDeviceContextSpec);
+
+  return mRealDeviceContextSpec->GetDPI();
+}
+
+float
+nsDeviceContextSpecProxy::GetPrintingScale()
+{
+  MOZ_ASSERT(mRealDeviceContextSpec);
+
+  return mRealDeviceContextSpec->GetPrintingScale();
+}
+
+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;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::EndDocument()
+{
+  Unused << mRemotePrintJob->SendFinalizePrint();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::AbortDocument()
+{
+  Unused << mRemotePrintJob->SendAbortPrint(NS_OK);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::BeginPage()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDeviceContextSpecProxy::EndPage()
+{
+  // Save the current page recording to shared memory.
+  mozilla::ipc::Shmem storedPage;
+  size_t recordingSize = mRecorder->RecordingSize();
+  if (!mRemotePrintJob->AllocShmem(recordingSize,
+                                   mozilla::ipc::SharedMemory::TYPE_BASIC,
+                                   &storedPage)) {
+    NS_WARNING("Failed to create shared memory for remote printing.");
+    return NS_ERROR_FAILURE;
+  }
+
+  bool success = mRecorder->CopyRecording(storedPage.get<char>(), recordingSize);
+  if (!success) {
+    NS_WARNING("Copying recording to shared memory was not succesful.");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Wipe the recording to free memory. The recorder does not forget which data
+  // backed objects that it has stored.
+  mRecorder->WipeRecording();
+
+  // Send the page recording to the parent.
+  mRemotePrintJob->ProcessPage(storedPage);
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/widget/nsDeviceContextSpecProxy.h
@@ -0,0 +1,63 @@
+/* -*- 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/. */
+
+#ifndef nsDeviceContextSpecProxy_h
+#define nsDeviceContextSpecProxy_h
+
+#include "nsIDeviceContextSpec.h"
+#include "nsCOMPtr.h"
+
+class nsIPrintSession;
+
+namespace mozilla {
+namespace gfx {
+class DrawEventRecorderMemory;
+}
+
+namespace layout {
+class RemotePrintJobChild;
+}
+}
+
+class nsDeviceContextSpecProxy final : public nsIDeviceContextSpec
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  NS_METHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPrintSettings,
+                 bool aIsPrintPreview) final;
+
+  NS_METHOD GetSurfaceForPrinter(gfxASurface** aSurface) final;
+
+  NS_METHOD GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder) final;
+
+  float GetDPI() final;
+
+  float GetPrintingScale() final;
+
+  NS_METHOD BeginDocument(const nsAString& aTitle,
+                          const nsAString& aPrintToFileName,
+                          int32_t aStartPage, int32_t aEndPage) final;
+
+  NS_METHOD EndDocument() final;
+
+  NS_METHOD AbortDocument() final;
+
+  NS_METHOD BeginPage() final;
+
+  NS_METHOD EndPage() final;
+
+private:
+  ~nsDeviceContextSpecProxy() {}
+
+  nsCOMPtr<nsIPrintSettings> mPrintSettings;
+  nsCOMPtr<nsIPrintSession> mPrintSession;
+  nsCOMPtr<nsIDeviceContextSpec> mRealDeviceContextSpec;
+  RefPtr<mozilla::layout::RemotePrintJobChild> mRemotePrintJob;
+  RefPtr<mozilla::gfx::DrawEventRecorderMemory> mRecorder;
+};
+
+#endif // nsDeviceContextSpecProxy_h
--- a/widget/nsIDeviceContextSpec.h
+++ b/widget/nsIDeviceContextSpec.h
@@ -7,16 +7,22 @@
 #define nsIDeviceContextSpec_h___
 
 #include "nsISupports.h"
 
 class nsIWidget;
 class nsIPrintSettings;
 class gfxASurface;
 
+namespace mozilla {
+namespace gfx{
+class DrawEventRecorder;
+}
+}
+
 #define NS_IDEVICE_CONTEXT_SPEC_IID   \
 { 0xf407cfba, 0xbe28, 0x46c9, \
   { 0x8a, 0xba, 0x04, 0x2d, 0xae, 0xbb, 0x4f, 0x23 } }
 
 class nsIDeviceContextSpec : public nsISupports
 {
 public:
    NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDEVICE_CONTEXT_SPEC_IID)
@@ -30,34 +36,48 @@ public:
     */
    NS_IMETHOD Init(nsIWidget *aWidget,
                    nsIPrintSettings* aPrintSettings,
                    bool aIsPrintPreview) = 0;
 
    NS_IMETHOD GetSurfaceForPrinter(gfxASurface **nativeSurface) = 0;
 
    /**
+    * If required override to return a recorder to record the print.
+    *
+    * @param aDrawEventRecorder out param for the recorder to use
+    * @return NS_OK or a suitable error code
+    */
+   NS_IMETHOD GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder)
+   {
+     MOZ_ASSERT(aDrawEventRecorder);
+     *aDrawEventRecorder = nullptr;
+     return NS_OK;
+   }
+
+   /**
     * Override to return something other than the default.
     *
     * @return DPI for printing.
     */
    virtual float GetDPI() { return 72.0f; }
 
    /**
     * Override to return something other than the default.
     *
     * @return the printing scale to be applied to the context for printing.
     */
    virtual float GetPrintingScale() { return 1.0f;  }
 
    NS_IMETHOD BeginDocument(const nsAString& aTitle,
-                            char16_t*       aPrintToFileName,
+                            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_DEFINE_STATIC_IID_ACCESSOR(nsIDeviceContextSpec,
                               NS_IDEVICE_CONTEXT_SPEC_IID)
 #endif
--- a/widget/nsPrimitiveHelpers.cpp
+++ b/widget/nsPrimitiveHelpers.cpp
@@ -16,16 +16,19 @@
 //
 // For now, this is the assumption that we are making:
 //  - text/plain is always a char*
 //  - anything else is a char16_t*
 //
 
 
 #include "nsPrimitiveHelpers.h"
+
+#include "mozilla/UniquePtr.h"
+#include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITransferable.h"
 #include "nsIComponentManager.h"
 #include "nsLinebreakConverter.h"
 #include "nsReadableUtils.h"
 
@@ -55,17 +58,17 @@ nsPrimitiveHelpers :: CreatePrimitiveFor
       NS_ADDREF(*aPrimitive = primitive);
     }
   }
   else {
     nsCOMPtr<nsISupportsString> primitive =
         do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
     if (primitive ) {
       if (aDataLen % 2) {
-        auto buffer = MakeUnique<char[]>(aDataLen + 1);
+        auto buffer = mozilla::MakeUnique<char[]>(aDataLen + 1);
         if (!MOZ_LIKELY(buffer))
           return;
 
         memcpy(buffer.get(), aDataBuff, aDataLen);
         buffer[aDataLen] = 0;
         const char16_t* start = reinterpret_cast<const char16_t*>(buffer.get());
         // recall that length takes length as characters, not bytes
         primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
--- a/widget/qt/nsDeviceContextSpecQt.cpp
+++ b/widget/qt/nsDeviceContextSpecQt.cpp
@@ -146,17 +146,17 @@ NS_IMETHODIMP nsDeviceContextSpecQt::Ini
     nsCOMPtr<nsPrintSettingsQt> printSettingsQt(do_QueryInterface(aPS));
     if (!printSettingsQt)
         return NS_ERROR_NO_INTERFACE;
     return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceContextSpecQt::BeginDocument(
         const nsAString& aTitle,
-        char16_t* aPrintToFileName,
+        const nsAString& aPrintToFileName,
         int32_t aStartPage,
         int32_t aEndPage)
 {
     if (mToPrinter) {
         return NS_ERROR_NOT_IMPLEMENTED;
     }
     return NS_OK;
 }
--- a/widget/qt/nsDeviceContextSpecQt.h
+++ b/widget/qt/nsDeviceContextSpecQt.h
@@ -23,17 +23,17 @@ public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD GetSurfaceForPrinter(gfxASurface** surface);
 
     NS_IMETHOD Init(nsIWidget* aWidget,
                     nsIPrintSettings* aPS,
                     bool aIsPrintPreview);
     NS_IMETHOD BeginDocument(const nsAString& aTitle,
-                             char16_t* aPrintToFileName,
+                             const nsAString& aPrintToFileName,
                              int32_t aStartPage,
                              int32_t aEndPage);
     NS_IMETHOD EndDocument();
     NS_IMETHOD BeginPage() { return NS_OK; }
     NS_IMETHOD EndPage() { return NS_OK; }
 
 protected:
     virtual ~nsDeviceContextSpecQt();
--- a/widget/windows/nsDeviceContextSpecWin.h
+++ b/widget/windows/nsDeviceContextSpecWin.h
@@ -21,17 +21,17 @@ class nsDeviceContextSpecWin : public ns
 {
 public:
   nsDeviceContextSpecWin();
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface) override;
   NS_IMETHOD BeginDocument(const nsAString& aTitle,
-                           char16_t*       aPrintToFileName,
+                           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 Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;