Bug 1324064: Stop accessing printer devices in the child when printing via parent. r=jimm a=lizzard
authorBob Owen <bobowencode@gmail.com>
Fri, 06 Jan 2017 11:29:11 +0000
changeset 353457 048ad2874f2cc95adc4fa20ad3e35d5439f4ad62
parent 353456 2c312ad91c1b26a9f80cec96cfb5f05f848241d5
child 353458 f4b165800dd77f1482d620a4ff3658083f6282d7
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, lizzard
bugs1324064
milestone52.0a2
Bug 1324064: Stop accessing printer devices in the child when printing via parent. r=jimm a=lizzard 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 true;
 }
 
 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;
 }
 
 bool
 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,19 +1,21 @@
 /* -*- 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/Preferences.h"
 #include "mozilla/RefPtr.h"
 
-#include "nsDeviceContextSpecWin.h"
 #include "prmem.h"
 
 #include <winspool.h>
 
 #include "nsIWidget.h"
 
 #include "nsTArray.h"
 #include "nsIPrintSettingsWin.h"
@@ -126,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;
@@ -171,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");
@@ -435,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;