Bug 1324064: Stop accessing printer devices in the child when printing via parent. r=jimm
authorBob Owen <bobowencode@gmail.com>
Fri, 06 Jan 2017 11:29:11 +0000
changeset 328368 1794dcb6d7432b153154fd1ebc90b7f22625fd05
parent 328367 1c11ff13ba6c1298c42b32c15d2cc48e5b420171
child 328369 29bc945061a0f565e38907a5359a483c8a4efa08
push id31169
push userryanvm@gmail.com
push dateSat, 07 Jan 2017 16:22:59 +0000
treeherdermozilla-central@e9d16569a7b4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1324064
milestone53.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 1324064: Stop accessing printer devices in the child when printing via parent. r=jimm This should remove all access to printer devices on Windows, there might by some other OS specific code which still does.
embedding/components/printingui/ipc/PPrinting.ipdl
embedding/components/printingui/ipc/PrintingParent.cpp
embedding/components/printingui/ipc/nsPrintingProxy.cpp
layout/printing/nsPrintEngine.cpp
widget/nsDeviceContextSpecProxy.cpp
widget/nsPrintOptionsImpl.cpp
widget/windows/nsDeviceContextSpecWin.cpp
--- a/embedding/components/printingui/ipc/PPrinting.ipdl
+++ b/embedding/components/printingui/ipc/PPrinting.ipdl
@@ -24,17 +24,17 @@ parent:
   sync ShowProgress(PBrowser browser,
                     PPrintProgressDialog printProgressDialog,
                     nullable PRemotePrintJob remotePrintJob,
                     bool isForPrinting)
     returns(bool notifyOnOpen,
             nsresult rv);
 
   async ShowPrintDialog(PPrintSettingsDialog dialog,
-                        PBrowser browser,
+                        nullable PBrowser browser,
                         PrintData settings);
 
   async PPrintProgressDialog();
   async PPrintSettingsDialog();
 
   sync SavePrintSettings(PrintData settings, bool usePrinterNamePrefix,
                          uint32_t flags)
     returns(nsresult rv);
--- a/embedding/components/printingui/ipc/PrintingParent.cpp
+++ b/embedding/components/printingui/ipc/PrintingParent.cpp
@@ -79,19 +79,25 @@ PrintingParent::RecvShowProgress(PBrowse
   return IPC_OK();
 }
 
 nsresult
 PrintingParent::ShowPrintDialog(PBrowserParent* aParent,
                                 const PrintData& aData,
                                 PrintData* aResult)
 {
-  nsCOMPtr<nsPIDOMWindowOuter> parentWin = DOMWindowFromBrowserParent(aParent);
-  if (!parentWin) {
-    return NS_ERROR_FAILURE;
+  // If aParent is null this call is just being used to get print settings from
+  // the printer for print preview.
+  bool isPrintPreview = !aParent;
+  nsCOMPtr<nsPIDOMWindowOuter> parentWin;
+  if (aParent) {
+    parentWin = DOMWindowFromBrowserParent(aParent);
+    if (!parentWin) {
+      return NS_ERROR_FAILURE;
+    }
   }
 
   nsCOMPtr<nsIPrintingPromptService> pps(do_GetService("@mozilla.org/embedcomp/printingprompt-service;1"));
   if (!pps) {
     return NS_ERROR_FAILURE;
   }
 
   // The initSettings we got can be wrapped using
@@ -118,33 +124,38 @@ PrintingParent::ShowPrintDialog(PBrowser
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mPrintSettingsSvc->DeserializeToPrintSettings(aData, settings);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = settings->SetPrintSilent(printSilently);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // If we are printing silently then we just need to initialize the print
-  // settings with anything specific from the printer.
-  if (printSilently ||
+  // If this is for print preview or we are printing silently then we just need
+  // to initialize the print settings with anything specific from the printer.
+  if (isPrintPreview || printSilently ||
       Preferences::GetBool("print.always_print_silent", printSilently)) {
     nsXPIDLString printerName;
     rv = settings->GetPrinterName(getter_Copies(printerName));
     NS_ENSURE_SUCCESS(rv, rv);
 
     settings->SetIsInitializedFromPrinter(false);
     mPrintSettingsSvc->InitPrintSettingsFromPrinter(printerName, settings);
   } else {
     rv = pps->ShowPrintDialog(parentWin, wbp, settings);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  rv = SerializeAndEnsureRemotePrintJob(settings, nullptr, remotePrintJob,
-                                        aResult);
+  if (isPrintPreview) {
+    // For print preview we don't want a RemotePrintJob just the settings.
+    rv = mPrintSettingsSvc->SerializeToPrintData(settings, nullptr, aResult);
+  } else {
+    rv = SerializeAndEnsureRemotePrintJob(settings, nullptr, remotePrintJob,
+                                          aResult);
+  }
 
   return rv;
 }
 
 mozilla::ipc::IPCResult
 PrintingParent::RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
                                     PBrowserParent* aParent,
                                     const PrintData& aData)
--- a/embedding/components/printingui/ipc/nsPrintingProxy.cpp
+++ b/embedding/components/printingui/ipc/nsPrintingProxy.cpp
@@ -67,31 +67,35 @@ nsPrintingProxy::Init()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrintingProxy::ShowPrintDialog(mozIDOMWindowProxy *parent,
                                  nsIWebBrowserPrint *webBrowserPrint,
                                  nsIPrintSettings *printSettings)
 {
-  NS_ENSURE_ARG(parent);
   NS_ENSURE_ARG(webBrowserPrint);
   NS_ENSURE_ARG(printSettings);
 
-  // Get the TabChild for this nsIDOMWindow, which we can then pass up to
-  // the parent.
-  nsCOMPtr<nsPIDOMWindowOuter> pwin = nsPIDOMWindowOuter::From(parent);
-  NS_ENSURE_STATE(pwin);
-  nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
-  NS_ENSURE_STATE(docShell);
+  // If parent is null we are just being called to retrieve the print settings
+  // from the printer in the parent for print preview.
+  TabChild* pBrowser = nullptr;
+  if (parent) {
+    // Get the TabChild for this nsIDOMWindow, which we can then pass up to
+    // the parent.
+    nsCOMPtr<nsPIDOMWindowOuter> pwin = nsPIDOMWindowOuter::From(parent);
+    NS_ENSURE_STATE(pwin);
+    nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
+    NS_ENSURE_STATE(docShell);
 
-  nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
-  NS_ENSURE_STATE(tabchild);
+    nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
+    NS_ENSURE_STATE(tabchild);
 
-  TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
+    pBrowser = static_cast<TabChild*>(tabchild.get());
+  }
 
   // Next, serialize the nsIWebBrowserPrint and nsIPrintSettings we were given.
   nsresult rv = NS_OK;
   nsCOMPtr<nsIPrintSettingsService> printSettingsSvc =
     do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrintData inSettings;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -557,17 +557,21 @@ nsPrintEngine::DoCommonPrint(bool       
   if (printingViaParent) {
     devspec = new nsDeviceContextSpecProxy();
   } else {
     devspec = do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsScriptSuppressor scriptSuppressor(this);
-  if (!aIsPrintPreview) {
+  // If printing via parent we still call ShowPrintDialog even for print preview
+  // because we use that to retrieve the print settings from the printer.
+  // The dialog is not shown, but this means we don't need to access the printer
+  // driver from the child, which causes sandboxing issues.
+  if (!aIsPrintPreview || printingViaParent) {
 #ifdef DEBUG
     mPrt->mDebugFilePtr = mDebugFile;
 #endif
 
     scriptSuppressor.Suppress();
     bool printSilently;
     mPrt->mPrintSettings->GetPrintSilent(&printSilently);
 
@@ -578,18 +582,22 @@ nsPrintEngine::DoCommonPrint(bool       
     // Ask dialog to be Print Shown via the Plugable Printing Dialog Service
     // This service is for the Print Dialog and the Print Progress Dialog
     // If printing silently or you can't get the service continue on
     // If printing via the parent then we need to confirm that the pref is set
     // and get a remote print job, but the parent won't display a prompt.
     if (!printSilently || printingViaParent) {
       nsCOMPtr<nsIPrintingPromptService> printPromptService(do_GetService(kPrintingPromptService));
       if (printPromptService) {
-        nsPIDOMWindowOuter* domWin = mDocument->GetWindow(); 
-        NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
+        nsPIDOMWindowOuter* domWin = nullptr;
+        // We leave domWin as nullptr to indicate a call for print preview.
+        if (!aIsPrintPreview) {
+          domWin = mDocument->GetWindow();
+          NS_ENSURE_TRUE(domWin, NS_ERROR_FAILURE);
+        }
 
         // Platforms not implementing a given dialog for the service may
         // return NS_ERROR_NOT_IMPLEMENTED or an error code.
         //
         // NS_ERROR_NOT_IMPLEMENTED indicates they want default behavior
         // Any other error code means we must bail out
         //
         nsCOMPtr<nsIWebBrowserPrint> wbp(do_QueryInterface(mDocViewerPrint));
@@ -603,17 +611,17 @@ nsPrintEngine::DoCommonPrint(bool       
           return NS_ERROR_FAILURE;
         }
 
         if (NS_SUCCEEDED(rv)) {
           // since we got the dialog and it worked then make sure we 
           // are telling GFX we want to print silent
           printSilently = true;
 
-          if (mPrt->mPrintSettings) {
+          if (mPrt->mPrintSettings && !aIsPrintPreview) {
             // The user might have changed shrink-to-fit in the print dialog, so update our copy of its state
             mPrt->mPrintSettings->GetShrinkToFit(&mPrt->mShrinkToFit);
 
             // If we haven't already added the RemotePrintJob as a listener,
             // add it now if there is one.
             if (!remotePrintJobListening) {
               RefPtr<mozilla::layout::RemotePrintJobChild> remotePrintJob;
               printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob));
--- a/widget/nsDeviceContextSpecProxy.cpp
+++ b/widget/nsDeviceContextSpecProxy.cpp
@@ -34,17 +34,17 @@ nsDeviceContextSpecProxy::Init(nsIWidget
 {
   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);
+  mRealDeviceContextSpec->Init(nullptr, aPrintSettings, aIsPrintPreview);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     mRealDeviceContextSpec = nullptr;
     return rv;
   }
 
   mPrintSettings = aPrintSettings;
 
   if (aIsPrintPreview) {
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -1025,16 +1025,22 @@ nsPrintOptions::GetDefaultPrinterName(ch
   // Return the default from the printer enumeration.
   return prtEnum->GetDefaultPrinterName(aDefaultPrinterName);
 }
 
 NS_IMETHODIMP
 nsPrintOptions::InitPrintSettingsFromPrinter(const char16_t *aPrinterName,
                                              nsIPrintSettings *aPrintSettings)
 {
+  // Don't get print settings from the printer in the child when printing via
+  // parent, these will be retrieved in the parent later in the print process.
+  if (XRE_IsContentProcess() && Preferences::GetBool("print.print_via_parent")) {
+    return NS_OK;
+  }
+
   NS_ENSURE_ARG_POINTER(aPrintSettings);
   NS_ENSURE_ARG_POINTER(aPrinterName);
 
 #ifdef DEBUG
   nsXPIDLString printerName;
   aPrintSettings->GetPrinterName(getter_Copies(printerName));
   if (!printerName.Equals(aPrinterName)) {
     NS_WARNING("Printer names should match!");
--- a/widget/windows/nsDeviceContextSpecWin.cpp
+++ b/widget/windows/nsDeviceContextSpecWin.cpp
@@ -1,20 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; 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 "nsDeviceContextSpecWin.h"
+
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/gfx/PrintTargetPDF.h"
 #include "mozilla/gfx/PrintTargetWindows.h"
 #include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
 
-#include "nsDeviceContextSpecWin.h"
 #include "prmem.h"
 
 #include <winspool.h>
 
 #include "nsIWidget.h"
 
 #include "nsTArray.h"
 #include "nsIPrintSettingsWin.h"
@@ -29,17 +31,16 @@
 #include "nsIFileStreams.h"
 #include "nsIWindowWatcher.h"
 #include "nsIDOMWindow.h"
 #include "mozilla/Services.h"
 #include "nsWindowsHelpers.h"
 
 #include "mozilla/gfx/Logging.h"
 
-#include "mozilla/Logging.h"
 static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
 #define PR_PL(_p1)  MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 static const wchar_t kDriverName[] =  L"WINSPOOL";
 
@@ -127,16 +128,25 @@ static char16_t * GetDefaultPrinterNameF
 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
                                            nsIPrintSettings* aPrintSettings,
                                            bool aIsPrintPreview)
 {
   mPrintSettings = aPrintSettings;
 
   nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
   if (aPrintSettings) {
+    // If we're in the child and printing via the parent or we're printing to
+    // PDF we only need information from the print settings.
+    mPrintSettings->GetOutputFormat(&mOutputFormat);
+    if ((XRE_IsContentProcess() &&
+         Preferences::GetBool("print.print_via_parent")) ||
+        mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
+      return NS_OK;
+    }
+
     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
     if (psWin) {
       char16_t* deviceName;
       char16_t* driverName;
       psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
       psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
 
       LPDEVMODEW devMode;
@@ -172,17 +182,16 @@ NS_IMETHODIMP nsDeviceContextSpecWin::In
   } else {
     PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
   }
 
   // Get the Printer Name to be used and output format.
   char16_t * printerName = nullptr;
   if (mPrintSettings) {
     mPrintSettings->GetPrinterName(&printerName);
-    mPrintSettings->GetOutputFormat(&mOutputFormat);
   }
 
   // If there is no name then use the default printer
   if (!printerName || (printerName && !*printerName)) {
     printerName = GetDefaultPrinterNameFromGlobalPrinters();
   }
 
   NS_ASSERTION(printerName, "We have to have a printer name");
@@ -436,16 +445,23 @@ nsPrinterEnumeratorWin::InitPrintSetting
 {
   NS_ENSURE_ARG_POINTER(aPrinterName);
   NS_ENSURE_ARG_POINTER(aPrintSettings);
 
   if (!*aPrinterName) {
     return NS_OK;
   }
 
+  // When printing to PDF on Windows there is no associated printer driver.
+  int16_t outputFormat;
+  aPrintSettings->GetOutputFormat(&outputFormat);
+  if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
+    return NS_OK;
+  }
+
   RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
   if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
 
   if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
     return NS_ERROR_FAILURE;
   }
 
   AutoFreeGlobalPrinters autoFreeGlobalPrinters;