Bug 1309272, part 8 - Implement printing via Skia PDF for macOS (behind pref print.print_via_pdf_encoder=skia-pdf). r=lsalzman

This commit is contained in:
Jonathan Watt 2016-11-23 09:14:10 +00:00
Родитель a986dd0cf9
Коммит 09a9ea3a3d
3 изменённых файлов: 165 добавлений и 1 удалений

Просмотреть файл

@ -91,6 +91,14 @@ LOCAL_INCLUDES += [
'/widget',
]
if CONFIG['MOZ_ENABLE_SKIA_PDF']:
LOCAL_INCLUDES += [
# Skia includes because widget code includes PrintTargetSkPDF.h, and that
# includes skia headers.
'/gfx/skia/skia/include/config',
'/gfx/skia/skia/include/core',
]
RESOURCE_FILES.cursors += [
'cursors/arrowN.png',
'cursors/arrowN@2x.png',

Просмотреть файл

@ -40,6 +40,10 @@ protected:
PMPrintSession mPrintSession; // printing context.
PMPageFormat mPageFormat; // page format.
PMPrintSettings mPrintSettings; // print settings.
#ifdef MOZ_ENABLE_SKIA_PDF
nsCOMPtr<nsIFile> mTempFile; // file "print" output is generated to if printing via PDF
bool mPrintViaSkPDF;
#endif
};
#endif //nsDeviceContextSpecX_h_

Просмотреть файл

@ -6,8 +6,14 @@
#include "nsDeviceContextSpecX.h"
#include "mozilla/gfx/PrintTargetCG.h"
#ifdef MOZ_ENABLE_SKIA_PDF
#include "mozilla/gfx/PrintTargetSkPDF.h"
#endif
#include "mozilla/Preferences.h"
#include "mozilla/RefPtr.h"
#include "nsCRT.h"
#include "nsDirectoryServiceDefs.h"
#include "nsILocalFileMac.h"
#include <unistd.h>
#include "nsQueryObject.h"
@ -18,12 +24,21 @@
#include "nsObjCExceptions.h"
using namespace mozilla;
using namespace mozilla::gfx;
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;
nsDeviceContextSpecX::nsDeviceContextSpecX()
: mPrintSession(NULL)
, mPageFormat(kPMNoPageFormat)
, mPrintSettings(kPMNoPrintSettings)
#ifdef MOZ_ENABLE_SKIA_PDF
, mPrintViaSkPDF(false)
#endif
{
}
@ -54,6 +69,45 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget *aWidget,
mPageFormat = settings->GetPMPageFormat();
mPrintSettings = settings->GetPMPrintSettings();
#ifdef MOZ_ENABLE_SKIA_PDF
const nsAdoptingString& printViaPdf =
mozilla::Preferences::GetString("print.print_via_pdf_encoder");
if (printViaPdf == NS_LITERAL_STRING("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) {
CFURLRef destURL;
status = ::PMSessionCopyDestinationLocation(mPrintSession,
mPrintSettings, &destURL);
if (status == noErr) {
CFStringRef destPathRef =
CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
NSString* destPath = (NSString*) destPathRef;
NSString* destPathExt = [destPath pathExtension];
if ([destPathExt isEqualToString: @"pdf"]) {
mPrintViaSkPDF = true;
}
}
}
}
}
#endif
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@ -83,7 +137,90 @@ NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
NS_IMETHODIMP nsDeviceContextSpecX::EndDocument()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
#ifdef MOZ_ENABLE_SKIA_PDF
if (mPrintViaSkPDF) {
OSStatus status = noErr;
nsCOMPtr<nsILocalFileMac> tmpPDFFile = do_QueryInterface(mTempFile);
if (!tmpPDFFile) {
return NS_ERROR_FAILURE;
}
CFURLRef pdfURL;
nsresult rv = tmpPDFFile->GetCFURL(&pdfURL);
NS_ENSURE_SUCCESS(rv, rv);
PMDestinationType destination;
status = ::PMSessionGetDestinationType(mPrintSession, mPrintSettings,
&destination);
switch (destination) {
case kPMDestinationPrinter: {
PMPrinter currentPrinter = NULL;
status = ::PMSessionGetCurrentPrinter(mPrintSession, &currentPrinter);
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);
CFStringRef pdfPath = CFURLCopyFileSystemPath(pdfURL,
kCFURLPOSIXPathStyle);
NSString* path = (NSString*) pdfPath;
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
[ws openFile: path];
break;
}
case kPMDestinationFile: {
CFURLRef destURL;
status = ::PMSessionCopyDestinationLocation(mPrintSession,
mPrintSettings, &destURL);
if (status == noErr) {
CFStringRef sourcePathRef =
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
CFStringRef destPathRef =
CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
NSString* sourcePath = (NSString*) sourcePathRef;
NSString* destPath = (NSString*) destPathRef;
#ifdef DEBUG
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*>(pdfURL);
NSURL* dest = static_cast<NSURL*>(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_ABORT_BLOCK_NSRESULT;
}
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom, double* aRight)
@ -107,6 +244,21 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget()
const double height = bottom - top;
IntSize size = IntSize::Floor(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(Move(stream), size);
}
#endif
return PrintTargetCG::CreateOrNull(mPrintSession, mPageFormat,
mPrintSettings, size);
}