Bug 1091112 - Proxy opening the print dialog on OS X to the parent. r=mstange
authorMike Conley <mconley@mozilla.com>
Wed, 06 May 2015 14:10:21 -0400
changeset 246478 7380457b8ba00bf1a9073b7c99891d86be487e6b
parent 246477 9b2f9883b6a8d5b787a5ba69ef1e574a19f74b9a
child 246479 17eb57fa30c753148e562b1b65074f8575197876
push id28830
push usercbook@mozilla.com
push dateMon, 01 Jun 2015 13:02:44 +0000
treeherdermozilla-central@39c85ec2d644 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1091112
milestone41.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 1091112 - Proxy opening the print dialog on OS X to the parent. r=mstange
embedding/components/build/moz.build
embedding/components/printingui/ipc/PPrintingTypes.ipdlh
embedding/components/printingui/ipc/PrintDataUtils.cpp
widget/cocoa/nsPrintDialogX.mm
widget/cocoa/nsPrintOptionsX.h
widget/cocoa/nsPrintOptionsX.mm
widget/cocoa/nsPrintSettingsX.mm
widget/nsPrintOptionsImpl.cpp
--- a/embedding/components/build/moz.build
+++ b/embedding/components/build/moz.build
@@ -21,16 +21,17 @@ LOCAL_INCLUDES += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../printingui/win',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+    DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../printingui/mac',
     ]
 
 if CONFIG['MOZ_PDF_PRINTING']:
     DEFINES['PROXY_PRINTING'] = 1
     LOCAL_INCLUDES += [
         '../printingui/unixshared',
--- a/embedding/components/printingui/ipc/PPrintingTypes.ipdlh
+++ b/embedding/components/printingui/ipc/PPrintingTypes.ipdlh
@@ -96,17 +96,17 @@ struct PrintData {
    */
   nsString printJobName;
   bool printAllPages;
   bool mustCollate;
   nsString disposition;
   /** TODO: Is there an "unsigned short" primitive? **/
   short pagesAcross;
   short pagesDown;
-  nsString printTime;
+  double printTime;
   bool detailedErrorReporting;
   nsString faxNumber;
   bool addHeaderAndFooter;
   bool fileNameExtensionHidden;
 };
 
 } // namespace embedding
 } // namespace mozilla
--- a/embedding/components/printingui/ipc/PrintDataUtils.cpp
+++ b/embedding/components/printingui/ipc/PrintDataUtils.cpp
@@ -124,17 +124,33 @@ MockWebBrowserPrint::Cancel()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 MockWebBrowserPrint::EnumerateDocumentNames(uint32_t* aCount,
                                             char16_t*** aResult)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  *aCount = 0;
+  *aResult = nullptr;
+
+  if (mData.printJobName().IsEmpty()) {
+    return NS_OK;
+  }
+
+  // The only consumer that cares about this is the OS X printing
+  // dialog, and even then, it only cares about the first document
+  // name. That's why we only send a single document name through
+  // PrintData.
+  char16_t** array = (char16_t**) moz_xmalloc(sizeof(char16_t*));
+  array[0] = ToNewUnicode(mData.printJobName());
+
+  *aCount = 1;
+  *aResult = array;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 MockWebBrowserPrint::ExitPrintPreview()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/widget/cocoa/nsPrintDialogX.mm
+++ b/widget/cocoa/nsPrintDialogX.mm
@@ -83,19 +83,24 @@ nsPrintDialogServiceX::Show(nsIDOMWindow
   [panel addAccessoryController:viewController];
   [viewController release];
 
   // Show the dialog.
   nsCocoaUtils::PrepareForNativeAppModalDialog();
   int button = [panel runModal];
   nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
 
-  settingsX->SetCocoaPrintInfo([[[NSPrintOperation currentOperation] printInfo] copy]);
+  NSPrintInfo* copy = [[[NSPrintOperation currentOperation] printInfo] copy];
+  if (!copy) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  settingsX->SetCocoaPrintInfo(copy);
+  [copy release];
+
   [NSPrintOperation setCurrentOperation:nil];
-  [printInfo release];
   [tmpView release];
 
   if (button != NSOKButton)
     return NS_ERROR_ABORT;
 
   // Export settings.
   [viewController exportSettings];
 
--- a/widget/cocoa/nsPrintOptionsX.h
+++ b/widget/cocoa/nsPrintOptionsX.h
@@ -3,20 +3,35 @@
  * 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 nsPrintOptionsX_h_
 #define nsPrintOptionsX_h_
 
 #include "nsPrintOptionsImpl.h"
 
+namespace mozilla
+{
+namespace embedding
+{
+  class PrintData;
+} // namespace embedding
+} // namespace mozilla
+
 class nsPrintOptionsX : public nsPrintOptions
 {
 public:
              nsPrintOptionsX();
   virtual    ~nsPrintOptionsX();
+
+  NS_IMETHODIMP SerializeToPrintData(nsIPrintSettings* aSettings,
+                                     nsIWebBrowserPrint* aWBP,
+                                     mozilla::embedding::PrintData* data);
+  NS_IMETHODIMP DeserializeToPrintSettings(const mozilla::embedding::PrintData& data,
+                                           nsIPrintSettings* settings);
+
 protected:
   nsresult   _CreatePrintSettings(nsIPrintSettings **_retval);
   nsresult   ReadPrefs(nsIPrintSettings* aPS, const nsAString& aPrinterName, uint32_t aFlags);
   nsresult   WritePrefs(nsIPrintSettings* aPS, const nsAString& aPrinterName, uint32_t aFlags);
 };
 
 #endif // nsPrintOptionsX_h_
--- a/widget/cocoa/nsPrintOptionsX.mm
+++ b/widget/cocoa/nsPrintOptionsX.mm
@@ -4,24 +4,230 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMPtr.h"
 #include "nsQueryObject.h"
 #include "nsIServiceManager.h"
 #include "nsPrintOptionsX.h"
 #include "nsPrintSettingsX.h"
 
+using namespace mozilla::embedding;
+
 nsPrintOptionsX::nsPrintOptionsX()
 {
 }
 
 nsPrintOptionsX::~nsPrintOptionsX()
 {
 }
 
+NS_IMETHODIMP
+nsPrintOptionsX::SerializeToPrintData(nsIPrintSettings* aSettings,
+                                      nsIWebBrowserPrint* aWBP,
+                                      PrintData* data)
+{
+  nsresult rv = nsPrintOptions::SerializeToPrintData(aSettings, aWBP, data);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (aWBP) {
+    // When serializing an nsIWebBrowserPrint, we need to pass up the first
+    // document name. We could pass up the entire collection of document
+    // names, but the OS X printing prompt code only really cares about
+    // the first one, so we just send the first to save IPC traffic.
+    char16_t** docTitles;
+    uint32_t titleCount;
+    nsresult rv = aWBP->EnumerateDocumentNames(&titleCount, &docTitles);
+    if (NS_SUCCEEDED(rv) && titleCount > 0) {
+      data->printJobName().Assign(docTitles[0]);
+    }
+
+    for (int32_t i = titleCount - 1; i >= 0; i--) {
+      free(docTitles[i]);
+    }
+    free(docTitles);
+    docTitles = nullptr;
+  }
+
+  nsRefPtr<nsPrintSettingsX> settingsX(do_QueryObject(aSettings));
+  if (NS_WARN_IF(!settingsX)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  NSPrintInfo* printInfo = settingsX->GetCocoaPrintInfo();
+  if (NS_WARN_IF(!printInfo)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  NSDictionary* dict = [printInfo dictionary];
+  if (NS_WARN_IF(!dict)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  NSString* printerName = [dict objectForKey: NSPrintPrinterName];
+  if (printerName) {
+    nsCocoaUtils::GetStringForNSString(printerName, data->printerName());
+  }
+
+  NSString* faxNumber = [dict objectForKey: NSPrintFaxNumber];
+  if (faxNumber) {
+    nsCocoaUtils::GetStringForNSString(faxNumber, data->faxNumber());
+  }
+
+  NSURL* printToFileURL = [dict objectForKey: NSPrintJobSavingURL];
+  if (printToFileURL) {
+    nsCocoaUtils::GetStringForNSString([printToFileURL absoluteString],
+                                       data->toFileName());
+  }
+
+  NSDate* printTime = [dict objectForKey: NSPrintTime];
+  if (printTime) {
+    NSTimeInterval timestamp = [printTime timeIntervalSinceReferenceDate];
+    data->printTime() = timestamp;
+  }
+
+  NSString* disposition = [dict objectForKey: NSPrintJobDisposition];
+  if (disposition) {
+    nsCocoaUtils::GetStringForNSString(disposition, data->disposition());
+  }
+
+  data->numCopies() = [[dict objectForKey: NSPrintCopies] intValue];
+  data->printAllPages() = [[dict objectForKey: NSPrintAllPages] boolValue];
+  data->startPageRange() = [[dict objectForKey: NSPrintFirstPage] intValue];
+  data->endPageRange() = [[dict objectForKey: NSPrintLastPage] intValue];
+  data->mustCollate() = [[dict objectForKey: NSPrintMustCollate] boolValue];
+  data->printReversed() = [[dict objectForKey: NSPrintReversePageOrder] boolValue];
+  data->pagesAcross() = [[dict objectForKey: NSPrintPagesAcross] unsignedShortValue];
+  data->pagesDown() = [[dict objectForKey: NSPrintPagesDown] unsignedShortValue];
+  data->detailedErrorReporting() = [[dict objectForKey: NSPrintDetailedErrorReporting] boolValue];
+  data->addHeaderAndFooter() = [[dict objectForKey: NSPrintHeaderAndFooter] boolValue];
+  data->fileNameExtensionHidden() =
+    [[dict objectForKey: NSPrintJobSavingFileNameExtensionHidden] boolValue];
+
+  bool printSelectionOnly = [[dict objectForKey: NSPrintSelectionOnly] boolValue];
+  aSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB,
+                             printSelectionOnly);
+  aSettings->GetPrintOptionsBits(&data->optionFlags());
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrintOptionsX::DeserializeToPrintSettings(const PrintData& data,
+                                            nsIPrintSettings* settings)
+{
+  nsresult rv = nsPrintOptions::DeserializeToPrintSettings(data, settings);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsRefPtr<nsPrintSettingsX> settingsX(do_QueryObject(settings));
+  if (NS_WARN_IF(!settingsX)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  NSPrintInfo* sharedPrintInfo = [NSPrintInfo sharedPrintInfo];
+  if (NS_WARN_IF(!sharedPrintInfo)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  NSDictionary* sharedDict = [sharedPrintInfo dictionary];
+  if (NS_WARN_IF(!sharedDict)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // We need to create a new NSMutableDictionary to pass to NSPrintInfo with
+  // the values that we got from the other process.
+  NSMutableDictionary* newPrintInfoDict =
+    [NSMutableDictionary dictionaryWithDictionary:sharedDict];
+  if (NS_WARN_IF(!newPrintInfoDict)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  NSString* printerName = nsCocoaUtils::ToNSString(data.printerName());
+  if (printerName) {
+    NSPrinter* printer = [NSPrinter printerWithName: printerName];
+    if (NS_WARN_IF(!printer)) {
+      return NS_ERROR_FAILURE;
+    }
+    [newPrintInfoDict setObject: printer forKey: NSPrintPrinter];
+    [newPrintInfoDict setObject: printerName forKey: NSPrintPrinterName];
+  }
+
+  [newPrintInfoDict setObject: [NSNumber numberWithInt: data.numCopies()]
+                    forKey: NSPrintCopies];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.printAllPages()]
+                    forKey: NSPrintAllPages];
+  [newPrintInfoDict setObject: [NSNumber numberWithInt: data.startPageRange()]
+                    forKey: NSPrintFirstPage];
+  [newPrintInfoDict setObject: [NSNumber numberWithInt: data.endPageRange()]
+                    forKey: NSPrintLastPage];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.mustCollate()]
+                    forKey: NSPrintMustCollate];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.printReversed()]
+                    forKey: NSPrintReversePageOrder];
+
+  [newPrintInfoDict setObject: nsCocoaUtils::ToNSString(data.disposition())
+                    forKey: NSPrintJobDisposition];
+
+  [newPrintInfoDict setObject: [NSNumber numberWithShort: data.pagesAcross()]
+                    forKey: NSPrintPagesAcross];
+  [newPrintInfoDict setObject: [NSNumber numberWithShort: data.pagesDown()]
+                    forKey: NSPrintPagesDown];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.detailedErrorReporting()]
+                    forKey: NSPrintDetailedErrorReporting];
+  [newPrintInfoDict setObject: nsCocoaUtils::ToNSString(data.faxNumber())
+                    forKey: NSPrintFaxNumber];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.addHeaderAndFooter()]
+                    forKey: NSPrintHeaderAndFooter];
+  [newPrintInfoDict setObject: [NSNumber numberWithBool: data.fileNameExtensionHidden()]
+                    forKey: NSPrintJobSavingFileNameExtensionHidden];
+
+  // At this point, the base class should have properly deserialized the print
+  // options bitfield for nsIPrintSettings, so that it holds the correct value
+  // for kEnableSelectionRB, which we use to set NSPrintSelectionOnly.
+
+  bool printSelectionOnly = false;
+  rv = settings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &printSelectionOnly);
+  if (NS_SUCCEEDED(rv)) {
+    [newPrintInfoDict setObject: [NSNumber numberWithBool: printSelectionOnly]
+                      forKey: NSPrintSelectionOnly];
+  } else {
+    [newPrintInfoDict setObject: [NSNumber numberWithBool: NO]
+                      forKey: NSPrintSelectionOnly];
+  }
+
+  NSURL* jobSavingURL =
+    [NSURL URLWithString:[nsCocoaUtils::ToNSString(data.toFileName())
+                          stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
+  if (jobSavingURL) {
+    [newPrintInfoDict setObject: jobSavingURL forKey: NSPrintJobSavingURL];
+  }
+
+  NSTimeInterval timestamp = data.printTime();
+  NSDate* printTime = [NSDate dateWithTimeIntervalSinceReferenceDate: timestamp];
+  if (printTime) {
+    [newPrintInfoDict setObject: printTime forKey: NSPrintTime];
+  }
+
+  // Next, we create a new NSPrintInfo with the values in our dictionary.
+  NSPrintInfo* newPrintInfo =
+    [[NSPrintInfo alloc] initWithDictionary: newPrintInfoDict];
+  if (NS_WARN_IF(!newPrintInfo)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  // And now swap in the new NSPrintInfo we've just populated.
+  settingsX->SetCocoaPrintInfo(newPrintInfo);
+  [newPrintInfo release];
+
+  return NS_OK;
+}
+
 nsresult
 nsPrintOptionsX::ReadPrefs(nsIPrintSettings* aPS, const nsAString& aPrinterName, uint32_t aFlags)
 {
   nsresult rv;
   
   rv = nsPrintOptions::ReadPrefs(aPS, aPrinterName, aFlags);
   NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrintOptions::ReadPrefs() failed");
   
--- a/widget/cocoa/nsPrintSettingsX.mm
+++ b/widget/cocoa/nsPrintSettingsX.mm
@@ -89,17 +89,20 @@ NS_IMETHODIMP nsPrintSettingsX::InitUnwr
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;  
 }
 
 void
 nsPrintSettingsX::SetCocoaPrintInfo(NSPrintInfo* aPrintInfo)
 {
-  mPrintInfo = aPrintInfo;
+  if (mPrintInfo != aPrintInfo) {
+    [mPrintInfo release];
+    mPrintInfo = [aPrintInfo retain];
+  }
 }
 
 NS_IMETHODIMP nsPrintSettingsX::ReadPageFormatFromPrefs()
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   nsAutoCString encodedData;
   nsresult rv =
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -237,17 +237,17 @@ nsPrintOptions::SerializeToPrintData(nsI
   data->isRangeSelection() = false;
   // data->GTKPrintSettings() default-initializes
   // data->printJobName() default-initializes
   data->printAllPages() = true;
   data->mustCollate() = false;
   // data->disposition() default-initializes
   data->pagesAcross() = 1;
   data->pagesDown() = 1;
-  // data->printTime() default-initializes
+  data->printTime() = 0;
   data->detailedErrorReporting() = true;
   // data->faxNumber() default-initializes
   data->addHeaderAndFooter() = false;
   data->fileNameExtensionHidden() = false;
 
   return NS_OK;
 }