forked from mirrors/gecko-dev
		
	 355baf5b39
			
		
	
	
		355baf5b39
		
	
	
	
	
		
			
			This patch was generated automatically, using the following commands: ``` rg -l 'NS_OBJC_BEGIN_TRY_ABORT_BLOCK' . | xargs sed -i '' -e 's/NS_OBJC_BEGIN_TRY_ABORT_BLOCK/NS_OBJC_BEGIN_TRY_IGNORE_BLOCK/g' rg -l 'NS_OBJC_END_TRY_ABORT_BLOCK' . | xargs sed -i '' -e 's/NS_OBJC_END_TRY_ABORT_BLOCK/NS_OBJC_END_TRY_IGNORE_BLOCK/g' ``` Differential Revision: https://phabricator.services.mozilla.com/D104960
		
			
				
	
	
		
			303 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 4; 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 "nsDeviceContextSpecX.h"
 | |
| 
 | |
| #import <Cocoa/Cocoa.h>
 | |
| #include <CoreFoundation/CoreFoundation.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
| #  include "mozilla/gfx/PrintTargetSkPDF.h"
 | |
| #endif
 | |
| #include "mozilla/gfx/PrintTargetCG.h"
 | |
| #include "mozilla/Logging.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/RefPtr.h"
 | |
| #include "mozilla/Telemetry.h"
 | |
| 
 | |
| #include "AppleUtils.h"
 | |
| #include "nsCocoaUtils.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsCUPSShim.h"
 | |
| #include "nsDirectoryServiceDefs.h"
 | |
| #include "nsILocalFileMac.h"
 | |
| #include "nsPaper.h"
 | |
| #include "nsPrinterListCUPS.h"
 | |
| #include "nsPrintSettingsX.h"
 | |
| #include "nsQueryObject.h"
 | |
| #include "prenv.h"
 | |
| 
 | |
| // This must be the last include:
 | |
| #include "nsObjCExceptions.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using mozilla::gfx::IntSize;
 | |
| using mozilla::gfx::PrintTarget;
 | |
| using mozilla::gfx::PrintTargetCG;
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
| using mozilla::gfx::PrintTargetSkPDF;
 | |
| #endif
 | |
| using mozilla::gfx::SurfaceFormat;
 | |
| 
 | |
| static LazyLogModule sDeviceContextSpecXLog("DeviceContextSpecX");
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // nsDeviceContentSpecX
 | |
| 
 | |
| nsDeviceContextSpecX::nsDeviceContextSpecX()
 | |
|     : mPrintSession(nullptr),
 | |
|       mPageFormat(nullptr),
 | |
|       mPrintSettings(nullptr)
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
|       ,
 | |
|       mPrintViaSkPDF(false)
 | |
| #endif
 | |
| {
 | |
| }
 | |
| 
 | |
| nsDeviceContextSpecX::~nsDeviceContextSpecX() {
 | |
|   NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
 | |
| 
 | |
|   if (mPrintSession) {
 | |
|     ::PMRelease(mPrintSession);
 | |
|   }
 | |
|   if (mPageFormat) {
 | |
|     ::PMRelease(mPageFormat);
 | |
|   }
 | |
|   if (mPrintSettings) {
 | |
|     ::PMRelease(mPrintSettings);
 | |
|   }
 | |
| 
 | |
|   NS_OBJC_END_TRY_IGNORE_BLOCK;
 | |
| }
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec)
 | |
| 
 | |
| NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget* aWidget, nsIPrintSettings* aPS,
 | |
|                                          bool aIsPrintPreview) {
 | |
|   NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
 | |
| 
 | |
|   RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
 | |
|   if (!settings) {
 | |
|     return NS_ERROR_NO_INTERFACE;
 | |
|   }
 | |
| 
 | |
|   bool toFile;
 | |
|   settings->GetPrintToFile(&toFile);
 | |
| 
 | |
|   NSPrintInfo* printInfo = settings->CreateOrCopyPrintInfo();
 | |
|   if (!printInfo) {
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
|   mPrintSession = static_cast<PMPrintSession>([printInfo PMPrintSession]);
 | |
|   mPageFormat = static_cast<PMPageFormat>([printInfo PMPageFormat]);
 | |
|   mPrintSettings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
 | |
|   MOZ_ASSERT(mPrintSession && mPageFormat && mPrintSettings);
 | |
|   ::PMRetain(mPrintSession);
 | |
|   ::PMRetain(mPageFormat);
 | |
|   ::PMRetain(mPrintSettings);
 | |
|   [printInfo release];
 | |
| 
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
|   nsAutoString printViaPdf;
 | |
|   mozilla::Preferences::GetString("print.print_via_pdf_encoder", printViaPdf);
 | |
|   if (printViaPdf.EqualsLiteral("skia-pdf")) {
 | |
|     // Annoyingly, PMPrinterPrintWithFile does not pay attention to the
 | |
|     // kPMDestination* value set in the PMPrintSession; it always sends the PDF
 | |
|     // to the specified printer.  This means that if we create the PDF using
 | |
|     // SkPDF then we need to manually handle user actions like "Open PDF in
 | |
|     // Preview" and "Save as PDF...".
 | |
|     // TODO: Currently we do not support using SkPDF for kPMDestinationFax or
 | |
|     // kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support
 | |
|     // it for kPMDestinationFile if the destination file is a PDF.
 | |
|     // XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider help?
 | |
|     OSStatus status = noErr;
 | |
|     PMDestinationType destination;
 | |
|     status = ::PMSessionGetDestinationType(mPrintSession, mPrintSettings, &destination);
 | |
|     if (status == noErr) {
 | |
|       if (destination == kPMDestinationPrinter || destination == kPMDestinationPreview) {
 | |
|         mPrintViaSkPDF = true;
 | |
|       } else if (destination == kPMDestinationFile) {
 | |
|         AutoCFRelease<CFURLRef> destURL(nullptr);
 | |
|         status =
 | |
|             ::PMSessionCopyDestinationLocation(mPrintSession, mPrintSettings, destURL.receive());
 | |
|         if (status == noErr) {
 | |
|           AutoCFRelease<CFStringRef> destPathRef =
 | |
|               CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
 | |
|           NSString* destPath = (NSString*)CFStringRef(destPathRef);
 | |
|           NSString* destPathExt = [destPath pathExtension];
 | |
|           if ([destPathExt isEqualToString:@"pdf"]) {
 | |
|             mPrintViaSkPDF = true;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   int16_t outputFormat;
 | |
|   aPS->GetOutputFormat(&outputFormat);
 | |
| 
 | |
|   if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
 | |
|     // We don't actually currently support/use kOutputFormatPDF on mac, but
 | |
|     // this is for completeness in case we add that (we probably need to in
 | |
|     // order to support adding links into saved PDFs, for example).
 | |
|     Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1);
 | |
|   } else {
 | |
|     PMDestinationType destination;
 | |
|     OSStatus status = ::PMSessionGetDestinationType(mPrintSession, mPrintSettings, &destination);
 | |
|     if (status == noErr &&
 | |
|         (destination == kPMDestinationFile || destination == kPMDestinationPreview ||
 | |
|          destination == kPMDestinationProcessPDF)) {
 | |
|       Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1);
 | |
|     } else {
 | |
|       Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"unknown"_ns, 1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| 
 | |
|   NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
 | |
|                                                   const nsAString& aPrintToFileName,
 | |
|                                                   int32_t aStartPage, int32_t aEndPage) {
 | |
|   NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
 | |
| 
 | |
|   return NS_OK;
 | |
| 
 | |
|   NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP nsDeviceContextSpecX::EndDocument() {
 | |
|   NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
 | |
| 
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
|   if (mPrintViaSkPDF) {
 | |
|     OSStatus status = noErr;
 | |
| 
 | |
|     nsCOMPtr<nsILocalFileMac> tmpPDFFile = do_QueryInterface(mTempFile);
 | |
|     if (!tmpPDFFile) {
 | |
|       return NS_ERROR_FAILURE;
 | |
|     }
 | |
|     AutoCFRelease<CFURLRef> pdfURL(nullptr);
 | |
|     // Note that the caller is responsible to release pdfURL according to nsILocalFileMac.idl,
 | |
|     // even though we didn't follow the Core Foundation naming conventions here (the method
 | |
|     // should've been called CopyCFURL).
 | |
|     nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive());
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|     PMDestinationType destination;
 | |
|     status = ::PMSessionGetDestinationType(mPrintSession, mPrintSettings, &destination);
 | |
| 
 | |
|     switch (destination) {
 | |
|       case kPMDestinationPrinter: {
 | |
|         PMPrinter currentPrinter = NULL;
 | |
|         status = ::PMSessionGetCurrentPrinter(mPrintSession, ¤tPrinter);
 | |
|         if (status != noErr) {
 | |
|           return NS_ERROR_FAILURE;
 | |
|         }
 | |
|         CFStringRef mimeType = CFSTR("application/pdf");
 | |
|         status =
 | |
|             ::PMPrinterPrintWithFile(currentPrinter, mPrintSettings, mPageFormat, mimeType, pdfURL);
 | |
|         break;
 | |
|       }
 | |
|       case kPMDestinationPreview: {
 | |
|         // XXXjwatt Or should we use CocoaFileUtils::RevealFileInFinder(pdfURL);
 | |
|         AutoCFRelease<CFStringRef> pdfPath = CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
 | |
|         NSString* path = (NSString*)CFStringRef(pdfPath);
 | |
|         NSWorkspace* ws = [NSWorkspace sharedWorkspace];
 | |
|         [ws openFile:path];
 | |
|         break;
 | |
|       }
 | |
|       case kPMDestinationFile: {
 | |
|         AutoCFRelease<CFURLRef> destURL(nullptr);
 | |
|         status =
 | |
|             ::PMSessionCopyDestinationLocation(mPrintSession, mPrintSettings, destURL.receive());
 | |
|         if (status == noErr) {
 | |
|           AutoCFRelease<CFStringRef> sourcePathRef =
 | |
|               CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
 | |
|           NSString* sourcePath = (NSString*)CFStringRef(sourcePathRef);
 | |
| #  ifdef DEBUG
 | |
|           AutoCFRelease<CFStringRef> destPathRef =
 | |
|               CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
 | |
|           NSString* destPath = (NSString*)CFStringRef(destPathRef);
 | |
|           NSString* destPathExt = [destPath pathExtension];
 | |
|           MOZ_ASSERT([destPathExt isEqualToString:@"pdf"],
 | |
|                      "nsDeviceContextSpecX::Init only allows '.pdf' for now");
 | |
|           // We could use /usr/sbin/cupsfilter to convert the PDF to PS, but
 | |
|           // currently we don't.
 | |
| #  endif
 | |
|           NSFileManager* fileManager = [NSFileManager defaultManager];
 | |
|           if ([fileManager fileExistsAtPath:sourcePath]) {
 | |
|             NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL));
 | |
|             NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL));
 | |
|             bool ok = [fileManager replaceItemAtURL:dest
 | |
|                                       withItemAtURL:src
 | |
|                                      backupItemName:nil
 | |
|                                             options:NSFileManagerItemReplacementUsingNewMetadataOnly
 | |
|                                    resultingItemURL:nil
 | |
|                                               error:nil];
 | |
|             if (!ok) {
 | |
|               return NS_ERROR_FAILURE;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       default:
 | |
|         MOZ_ASSERT_UNREACHABLE("nsDeviceContextSpecX::Init doesn't set "
 | |
|                                "mPrintViaSkPDF for other values");
 | |
|     }
 | |
| 
 | |
|     return (status == noErr) ? NS_OK : NS_ERROR_FAILURE;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return NS_OK;
 | |
| 
 | |
|   NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
 | |
| }
 | |
| 
 | |
| void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom,
 | |
|                                         double* aRight) {
 | |
|   NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
 | |
| 
 | |
|   PMRect paperRect;
 | |
|   ::PMGetAdjustedPaperRect(mPageFormat, &paperRect);
 | |
| 
 | |
|   *aTop = paperRect.top;
 | |
|   *aLeft = paperRect.left;
 | |
|   *aBottom = paperRect.bottom;
 | |
|   *aRight = paperRect.right;
 | |
| 
 | |
|   NS_OBJC_END_TRY_IGNORE_BLOCK;
 | |
| }
 | |
| 
 | |
| already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
 | |
|   double top, left, bottom, right;
 | |
|   GetPaperRect(&top, &left, &bottom, &right);
 | |
|   const double width = right - left;
 | |
|   const double height = bottom - top;
 | |
|   IntSize size = IntSize::Ceil(width, height);
 | |
| 
 | |
| #ifdef MOZ_ENABLE_SKIA_PDF
 | |
|   if (mPrintViaSkPDF) {
 | |
|     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
 | |
|     NS_ENSURE_SUCCESS(rv, nullptr);
 | |
|     nsAutoCString tempPath("tmp-printing.pdf");
 | |
|     mTempFile->AppendNative(tempPath);
 | |
|     rv = mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
 | |
|     NS_ENSURE_SUCCESS(rv, nullptr);
 | |
|     mTempFile->GetNativePath(tempPath);
 | |
|     auto stream = MakeUnique<SkFILEWStream>(tempPath.get());
 | |
|     return PrintTargetSkPDF::CreateOrNull(std::move(stream), size);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return PrintTargetCG::CreateOrNull(mPrintSession, mPageFormat, mPrintSettings, size);
 | |
| }
 |