mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 19:37:15 +00:00
Bug 1760836 - Support printing to an nsIOutputStream. r=jfkthame,jrmuizel,webdriver-reviewers,geckoview-reviewers,agi
The trickiest bits are the PrintTargetCG ones, the rest is just plumbing and cleanups and tests, but let me know if you want those to be split out, can do. The GTK change to nsPrintSettingsGTK::GetResolution is a no-op (we only read resolution on windows), but I did that because we assume that it doesn't fail and GTK returns a sane default anyways. Differential Revision: https://phabricator.services.mozilla.com/D142199
This commit is contained in:
parent
9480f3270e
commit
b0fb172236
@ -1351,7 +1351,8 @@ this.tabs = class extends ExtensionAPI {
|
||||
printSettings.isInitializedFromPrinter = true;
|
||||
printSettings.isInitializedFromPrefs = true;
|
||||
|
||||
printSettings.printToFile = true;
|
||||
printSettings.outputDestination =
|
||||
Ci.nsIPrintSettings.kOutputDestinationFile;
|
||||
printSettings.toFileName = picker.file.path;
|
||||
|
||||
printSettings.printSilent = true;
|
||||
|
@ -9,8 +9,9 @@
|
||||
#include <Carbon/Carbon.h>
|
||||
#include "PrintTarget.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class nsIOutputStream;
|
||||
|
||||
namespace mozilla::gfx {
|
||||
|
||||
/**
|
||||
* CoreGraphics printing target.
|
||||
@ -18,8 +19,9 @@ namespace gfx {
|
||||
class PrintTargetCG final : public PrintTarget {
|
||||
public:
|
||||
static already_AddRefed<PrintTargetCG> CreateOrNull(
|
||||
PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings, const IntSize& aSize);
|
||||
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession,
|
||||
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||
const IntSize& aSize);
|
||||
|
||||
nsresult BeginPrinting(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName, int32_t aStartPage,
|
||||
@ -32,16 +34,17 @@ class PrintTargetCG final : public PrintTarget {
|
||||
already_AddRefed<DrawTarget> GetReferenceDrawTarget() final;
|
||||
|
||||
private:
|
||||
PrintTargetCG(PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PrintTargetCG(CGContextRef aPrintToStreamContext,
|
||||
PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings, const IntSize& aSize);
|
||||
~PrintTargetCG();
|
||||
|
||||
CGContextRef mPrintToStreamContext = nullptr;
|
||||
PMPrintSession mPrintSession;
|
||||
PMPageFormat mPageFormat;
|
||||
PMPrintSettings mPrintSettings;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::gfx
|
||||
|
||||
#endif /* MOZILLA_GFX_PRINTTARGETCG_H */
|
||||
|
@ -10,13 +10,17 @@
|
||||
#include "mozilla/gfx/HelpersCairo.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
namespace mozilla::gfx {
|
||||
|
||||
PrintTargetCG::PrintTargetCG(PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings, const IntSize& aSize)
|
||||
static size_t PutBytesNull(void* info, const void* buffer, size_t count) { return count; }
|
||||
|
||||
PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext, PMPrintSession aPrintSession,
|
||||
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||
const IntSize& aSize)
|
||||
: PrintTarget(/* aCairoSurface */ nullptr, aSize),
|
||||
mPrintToStreamContext(aPrintToStreamContext),
|
||||
mPrintSession(aPrintSession),
|
||||
mPageFormat(aPageFormat),
|
||||
mPrintSettings(aPrintSettings) {
|
||||
@ -41,24 +45,80 @@ PrintTargetCG::~PrintTargetCG() {
|
||||
::PMRelease(mPageFormat);
|
||||
::PMRelease(mPrintSettings);
|
||||
|
||||
if (mPrintToStreamContext) {
|
||||
CGContextRelease(mPrintToStreamContext);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
static size_t WriteStreamBytes(void* aInfo, const void* aBuffer, size_t aCount) {
|
||||
auto* stream = static_cast<nsIOutputStream*>(aInfo);
|
||||
auto* data = static_cast<const char*>(aBuffer);
|
||||
size_t remaining = aCount;
|
||||
do {
|
||||
uint32_t wrote = 0;
|
||||
// Handle potential narrowing from size_t to uint32_t.
|
||||
uint32_t toWrite = uint32_t(std::min(remaining, size_t(std::numeric_limits<uint32_t>::max())));
|
||||
if (NS_WARN_IF(NS_FAILED(stream->Write(data, toWrite, &wrote)))) {
|
||||
break;
|
||||
}
|
||||
data += wrote;
|
||||
remaining -= size_t(wrote);
|
||||
} while (remaining);
|
||||
return aCount;
|
||||
}
|
||||
|
||||
static void ReleaseStream(void* aInfo) {
|
||||
auto* stream = static_cast<nsIOutputStream*>(aInfo);
|
||||
stream->Close();
|
||||
NS_RELEASE(stream);
|
||||
}
|
||||
|
||||
static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
|
||||
const IntSize& aSize) {
|
||||
MOZ_ASSERT(aOutputStream);
|
||||
|
||||
NS_ADDREF(aOutputStream); // Matched by the NS_RELEASE in ReleaseStream.
|
||||
|
||||
CGRect pageBox{{0.0, 0.0}, {CGFloat(aSize.width), CGFloat(aSize.height)}};
|
||||
CGDataConsumerCallbacks callbacks = {WriteStreamBytes, ReleaseStream};
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks);
|
||||
|
||||
// This metadata is added by the CorePrinting APIs in the non-stream case.
|
||||
NSString* bundleName =
|
||||
[NSBundle.mainBundle.localizedInfoDictionary objectForKey:(NSString*)kCFBundleNameKey];
|
||||
CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator, (__bridge CFStringRef)bundleName);
|
||||
|
||||
CGContextRef pdfContext = CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
|
||||
CGDataConsumerRelease(consumer);
|
||||
CFRelease(auxiliaryInfo);
|
||||
return pdfContext;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull(
|
||||
PMPrintSession aPrintSession, PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||
const IntSize& aSize) {
|
||||
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings, const IntSize& aSize) {
|
||||
if (!Factory::CheckSurfaceSize(aSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CGContextRef printToStreamContext = nullptr;
|
||||
if (aOutputStream) {
|
||||
printToStreamContext = CreatePrintToStreamContext(aOutputStream, aSize);
|
||||
if (!printToStreamContext) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<PrintTargetCG> target =
|
||||
new PrintTargetCG(aPrintSession, aPageFormat, aPrintSettings, aSize);
|
||||
new PrintTargetCG(printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
|
||||
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static size_t PutBytesNull(void* info, const void* buffer, size_t count) { return count; }
|
||||
|
||||
already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
||||
if (!mRefDT) {
|
||||
const IntSize size(1, 1);
|
||||
@ -95,6 +155,10 @@ nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString&
|
||||
int32_t aStartPage, int32_t aEndPage) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
if (mPrintToStreamContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Print Core of Application Service sent print job with names exceeding
|
||||
// 255 bytes. This is a workaround until fix it.
|
||||
// (https://openradar.appspot.com/34428043)
|
||||
@ -127,6 +191,12 @@ nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString&
|
||||
nsresult PrintTargetCG::EndPrinting() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
if (mPrintToStreamContext) {
|
||||
CGContextFlush(mPrintToStreamContext);
|
||||
CGPDFContextClose(mPrintToStreamContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
::PMSessionEndDocumentNoDialog(mPrintSession);
|
||||
return NS_OK;
|
||||
|
||||
@ -143,19 +213,24 @@ nsresult PrintTargetCG::AbortPrinting() {
|
||||
nsresult PrintTargetCG::BeginPage() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
PMSessionError(mPrintSession);
|
||||
OSStatus status = ::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, NULL);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
CGContextRef context;
|
||||
// This call will fail if it wasn't called between the PMSessionBeginPage/
|
||||
// PMSessionEndPage calls:
|
||||
::PMSessionGetCGGraphicsContext(mPrintSession, &context);
|
||||
if (mPrintToStreamContext) {
|
||||
CGContextBeginPage(mPrintToStreamContext, nullptr);
|
||||
context = mPrintToStreamContext;
|
||||
} else {
|
||||
PMSessionError(mPrintSession);
|
||||
OSStatus status = ::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, nullptr);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
if (!context) {
|
||||
return NS_ERROR_FAILURE;
|
||||
// This call will fail if it wasn't called between the PMSessionBeginPage/
|
||||
// PMSessionEndPage calls:
|
||||
::PMSessionGetCGGraphicsContext(mPrintSession, &context);
|
||||
|
||||
if (!context) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int width = static_cast<unsigned int>(mSize.width);
|
||||
@ -185,9 +260,13 @@ nsresult PrintTargetCG::EndPage() {
|
||||
cairo_surface_finish(mCairoSurface);
|
||||
mCairoSurface = nullptr;
|
||||
|
||||
OSStatus status = ::PMSessionEndPageNoDialog(mPrintSession);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_ABORT;
|
||||
if (mPrintToStreamContext) {
|
||||
CGContextEndPage(mPrintToStreamContext);
|
||||
} else {
|
||||
OSStatus status = ::PMSessionEndPageNoDialog(mPrintSession);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
return PrintTarget::EndPage();
|
||||
@ -195,5 +274,4 @@ nsresult PrintTargetCG::EndPage() {
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla::gfx
|
||||
|
@ -1080,10 +1080,9 @@ nsresult nsPrintJob::SetupToPrintContent() {
|
||||
|
||||
nsAutoString fileNameStr;
|
||||
// check to see if we are printing to a file
|
||||
bool isPrintToFile = false;
|
||||
printData->mPrintSettings->GetPrintToFile(&isPrintToFile);
|
||||
if (isPrintToFile) {
|
||||
// On some platforms The BeginDocument needs to know the name of the file.
|
||||
if (printData->mPrintSettings->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationFile) {
|
||||
// On some platforms the BeginDocument needs to know the name of the file.
|
||||
printData->mPrintSettings->GetToFileName(fileNameStr);
|
||||
}
|
||||
|
||||
@ -2332,8 +2331,7 @@ nsresult nsPrintJob::StartPagePrintTimer(const UniquePtr<nsPrintObject>& aPO) {
|
||||
if (!mPagePrintTimer) {
|
||||
// Get the delay time in between the printing of each page
|
||||
// this gives the user more time to press cancel
|
||||
int32_t printPageDelay = 50;
|
||||
mPrt->mPrintSettings->GetPrintPageDelay(&printPageDelay);
|
||||
int32_t printPageDelay = mPrt->mPrintSettings->GetPrintPageDelay();
|
||||
|
||||
nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
|
||||
NS_ENSURE_TRUE(cv, NS_ERROR_FAILURE);
|
||||
|
@ -1721,7 +1721,7 @@ function RecvStartPrint(isPrintSelection, printRange)
|
||||
ps.unwriteableMarginRight = 0;
|
||||
ps.unwriteableMarginLeft = 0;
|
||||
ps.unwriteableMarginBottom = 0;
|
||||
ps.printToFile = true;
|
||||
ps.outputDestination = Ci.nsIPrintSettings.kOutputDestinationFile;
|
||||
ps.toFileName = file.path;
|
||||
ps.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
ps.printSelectionOnly = isPrintSelection;
|
||||
|
@ -575,7 +575,8 @@ class Page extends Domain {
|
||||
printSettings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
printSettings.printerName = "";
|
||||
printSettings.printSilent = true;
|
||||
printSettings.printToFile = true;
|
||||
printSettings.outputDestination =
|
||||
Ci.nsIPrintSettings.kOutputDestinationFile;
|
||||
printSettings.toFileName = filePath;
|
||||
|
||||
printSettings.paperSizeUnit = Ci.nsIPrintSettings.kPaperSizeInches;
|
||||
|
@ -70,7 +70,7 @@ function getPrintSettings(settings, filePath) {
|
||||
printSettings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
printSettings.printerName = "marionette";
|
||||
printSettings.printSilent = true;
|
||||
printSettings.printToFile = true;
|
||||
printSettings.outputDestination = Ci.nsIPrintSettings.kOutputDestinationFile;
|
||||
printSettings.toFileName = filePath;
|
||||
|
||||
// Setting the paperSizeUnit to kPaperSizeMillimeters doesn't work on mac
|
||||
|
@ -1181,15 +1181,18 @@ var PrintSettingsViewProxy = {
|
||||
printerInfo.defaultSettings.toFileName = "";
|
||||
printerInfo.defaultSettings.outputFormat =
|
||||
Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
printerInfo.defaultSettings.printToFile = true;
|
||||
printerInfo.defaultSettings.outputDestination =
|
||||
Ci.nsIPrintSettings.kOutputDestinationFile;
|
||||
printerInfo.paperList = this.fallbackPaperList;
|
||||
}
|
||||
printerInfo.settings = printerInfo.defaultSettings.clone();
|
||||
// Apply any previously persisted user values
|
||||
// Don't apply kInitSavePrintToFile though, that should only be true for
|
||||
// the PDF printer.
|
||||
printerInfo.settings.printToFile =
|
||||
printerName == PrintUtils.SAVE_TO_PDF_PRINTER;
|
||||
printerInfo.settings.outputDestination =
|
||||
printerName == PrintUtils.SAVE_TO_PDF_PRINTER
|
||||
? Ci.nsIPrintSettings.kOutputDestinationFile
|
||||
: Ci.nsIPrintSettings.kOutputDestinationPrinter;
|
||||
let flags =
|
||||
printerInfo.settings.kInitSaveAll ^
|
||||
printerInfo.settings.kInitSavePrintToFile;
|
||||
@ -2615,7 +2618,7 @@ class PageCount extends PrintUIControlMixin(HTMLElement) {
|
||||
update(settings) {
|
||||
this.numCopies = settings.numCopies;
|
||||
this.duplex = settings.duplex;
|
||||
this.printToFile = settings.printToFile;
|
||||
this.outputDestination = settings.outputDestination;
|
||||
this.render();
|
||||
}
|
||||
|
||||
@ -2628,7 +2631,10 @@ class PageCount extends PrintUIControlMixin(HTMLElement) {
|
||||
|
||||
// When printing to a printer (not to a file) update
|
||||
// the sheet count to account for duplex printing.
|
||||
if (!this.printToFile && this.duplex != Ci.nsIPrintSettings.kDuplexNone) {
|
||||
if (
|
||||
this.outputDestination == Ci.nsIPrintSettings.kOutputDestinationPrinter &&
|
||||
this.duplex != Ci.nsIPrintSettings.kDuplexNone
|
||||
) {
|
||||
sheetCount = Math.ceil(sheetCount / 2);
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,11 @@ var PrintUtils = {
|
||||
|
||||
async function makePrintSettingsMaybeEnsuringToFileName() {
|
||||
let settings = PrintUtils.getPrintSettings();
|
||||
if (settings.printToFile && !settings.toFileName) {
|
||||
if (
|
||||
settings.outputDestination ==
|
||||
Ci.nsIPrintSettings.kOutputDestinationFile &&
|
||||
!settings.toFileName
|
||||
) {
|
||||
// TODO(bug 1748004): We should consider generating the file name
|
||||
// from the document's title as we do in print.js's pickFileName
|
||||
// (including using DownloadPaths.sanitize!).
|
||||
|
@ -28,6 +28,7 @@ skip-if = (verify && (os == 'mac')) # bug 1675609
|
||||
[browser_print_margins.js]
|
||||
[browser_print_frame.js]
|
||||
[browser_print_selection.js]
|
||||
[browser_print_stream.js]
|
||||
[browser_print_page_range.js]
|
||||
[browser_print_pdf_on_frame_load.js]
|
||||
support-files =
|
||||
|
@ -22,8 +22,8 @@ add_task(async function testPDFPrinterSettings() {
|
||||
let { settings } = helper;
|
||||
|
||||
ok(
|
||||
settings.printToFile,
|
||||
"Check the current settings have a truthy printToFile for the PDF printer"
|
||||
settings.outputDestination == Ci.nsIPrintSettings.kOutputDestinationFile,
|
||||
"Check the current settings have file destination"
|
||||
);
|
||||
ok(
|
||||
settings.printInColor,
|
||||
|
94
toolkit/components/printing/tests/browser_print_stream.js
Normal file
94
toolkit/components/printing/tests/browser_print_stream.js
Normal file
@ -0,0 +1,94 @@
|
||||
//creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService(
|
||||
Ci.nsIPrintSettingsService
|
||||
);
|
||||
|
||||
async function printToDestination(aBrowser, aDestination) {
|
||||
let tmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
let fileName = `printDestinationTest-${aDestination}.pdf`;
|
||||
let filePath = PathUtils.join(tmpDir.path, fileName);
|
||||
|
||||
info(`Printing to ${filePath}`);
|
||||
|
||||
let settings = PSSVC.newPrintSettings;
|
||||
settings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
settings.outputDestination = aDestination;
|
||||
settings.unwriteableMarginTop = 1; /* Just to ensure settings are respected on both */
|
||||
let outStream = null;
|
||||
if (aDestination == Ci.nsIPrintSettings.kOutputDestinationFile) {
|
||||
settings.toFileName = PathUtils.join(tmpDir.path, fileName);
|
||||
} else {
|
||||
is(aDestination, Ci.nsIPrintSettings.kOutputDestinationStream);
|
||||
outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
|
||||
Ci.nsIFileOutputStream
|
||||
);
|
||||
let tmpFile = tmpDir.clone();
|
||||
tmpFile.append(fileName);
|
||||
outStream.init(tmpFile, -1, 0o666, 0);
|
||||
settings.outputStream = outStream;
|
||||
}
|
||||
|
||||
await aBrowser.browsingContext.print(settings);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// In Cocoa the CGContext adds a hash, plus there are other minor
|
||||
// non-user-visible differences, so we need to be a bit sloppy here.
|
||||
const COCOA_MAX_SIZE_DIFFERENCE = 100; // bytes
|
||||
|
||||
add_task(async function testPrintToStream() {
|
||||
await PrintHelper.withTestPage(async helper => {
|
||||
let filePath = await printToDestination(
|
||||
helper.sourceBrowser,
|
||||
Ci.nsIPrintSettings.kOutputDestinationFile
|
||||
);
|
||||
let streamPath = await printToDestination(
|
||||
helper.sourceBrowser,
|
||||
Ci.nsIPrintSettings.kOutputDestinationStream
|
||||
);
|
||||
|
||||
const isCocoa = AppConstants.platform == "macosx";
|
||||
|
||||
// Buffering shenanigans? Wait for sizes to match... There's no great
|
||||
// IOUtils methods to force a flush without writing anything...
|
||||
await TestUtils.waitForCondition(async function() {
|
||||
let fileStat = await IOUtils.stat(filePath);
|
||||
let streamStat = await IOUtils.stat(streamPath);
|
||||
|
||||
ok(fileStat.size > 0, "File file should not be empty: " + fileStat.size);
|
||||
ok(
|
||||
streamStat.size > 0,
|
||||
"Stream file should not be empty: " + streamStat.size
|
||||
);
|
||||
if (isCocoa) {
|
||||
return (
|
||||
Math.abs(fileStat.size - streamStat.size) < COCOA_MAX_SIZE_DIFFERENCE
|
||||
);
|
||||
}
|
||||
return fileStat.size == streamStat.size;
|
||||
}, "Sizes should match");
|
||||
|
||||
if (!isCocoa) {
|
||||
let fileData = await IOUtils.read(filePath);
|
||||
let streamData = await IOUtils.read(streamPath);
|
||||
ok(!!fileData.length, "File should not be empty");
|
||||
is(fileData.length, streamData.length, "File size should be equal");
|
||||
for (let i = 0; i < fileData.length; ++i) {
|
||||
if (fileData[i] != streamData[i]) {
|
||||
is(
|
||||
fileData[i],
|
||||
streamData[i],
|
||||
`Files should be equal (byte ${i} different)`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await IOUtils.remove(filePath);
|
||||
await IOUtils.remove(streamPath);
|
||||
});
|
||||
});
|
@ -285,7 +285,8 @@ class PrintHelper {
|
||||
defaultSettings.printerName = name;
|
||||
defaultSettings.toFileName = "";
|
||||
defaultSettings.outputFormat = Ci.nsIPrintSettings.kOutputFormatNative;
|
||||
defaultSettings.printToFile = false;
|
||||
defaultSettings.outputDestination =
|
||||
Ci.nsIPrintSettings.kOutputDestinationPrinter;
|
||||
defaultSettings.paperSizeUnit = paperSizeUnit;
|
||||
if (paperId) {
|
||||
defaultSettings.paperId = paperId;
|
||||
|
@ -57,10 +57,13 @@ struct PrintData {
|
||||
int32_t orientation;
|
||||
int32_t numCopies;
|
||||
int32_t numPagesPerSheet;
|
||||
nsString printerName;
|
||||
bool printToFile;
|
||||
nsString toFileName;
|
||||
|
||||
// TODO: Do we really need to deal with these in child processes?
|
||||
short outputDestination;
|
||||
short outputFormat;
|
||||
nsString printerName;
|
||||
nsString toFileName;
|
||||
|
||||
int32_t printPageDelay;
|
||||
int32_t resolution;
|
||||
int32_t duplex;
|
||||
|
@ -11,32 +11,50 @@
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIPrintSettings.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDeviceContextSpecAndroid, nsIDeviceContextSpec)
|
||||
|
||||
nsDeviceContextSpecAndroid::~nsDeviceContextSpecAndroid() {
|
||||
if (mTempFile) {
|
||||
mTempFile->Remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<PrintTarget> nsDeviceContextSpecAndroid::MakePrintTarget() {
|
||||
nsresult rv =
|
||||
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
double width, height;
|
||||
mPrintSettings->GetEffectiveSheetSize(&width, &height);
|
||||
|
||||
nsAutoCString filename("tmp-printing.pdf");
|
||||
mTempFile->AppendNative(filename);
|
||||
rv = mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
// convert twips to points
|
||||
width /= TWIPS_PER_POINT_FLOAT;
|
||||
height /= TWIPS_PER_POINT_FLOAT;
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
rv = stream->Init(mTempFile, -1, -1, 0);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
auto stream = [&]() -> nsCOMPtr<nsIOutputStream> {
|
||||
if (mPrintSettings->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationStream) {
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
mPrintSettings->GetOutputStream(getter_AddRefs(out));
|
||||
return out;
|
||||
}
|
||||
if (NS_FAILED(
|
||||
NS_OpenAnonymousTemporaryNsIFile(getter_AddRefs(mTempFile)))) {
|
||||
return nullptr;
|
||||
}
|
||||
// Print to printer not supported...
|
||||
nsCOMPtr<nsIFileOutputStream> s =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
if (NS_FAILED(s->Init(mTempFile, -1, -1, 0))) {
|
||||
return nullptr;
|
||||
}
|
||||
return s;
|
||||
}();
|
||||
|
||||
// XXX: what should we do here for size? screen size?
|
||||
IntSize size(480, 800);
|
||||
|
||||
return PrintTargetPDF::CreateOrNull(stream, size);
|
||||
return PrintTargetPDF::CreateOrNull(stream, IntSize::Ceil(width, height));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -56,24 +74,23 @@ nsDeviceContextSpecAndroid::BeginDocument(const nsAString& aTitle,
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDeviceContextSpecAndroid::EndDocument() {
|
||||
nsString targetPath;
|
||||
nsCOMPtr<nsIFile> destFile;
|
||||
mPrintSettings->GetToFileName(targetPath);
|
||||
if (mPrintSettings->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationFile &&
|
||||
mTempFile) {
|
||||
nsAutoString targetPath;
|
||||
mPrintSettings->GetToFileName(targetPath);
|
||||
nsCOMPtr<nsIFile> destFile;
|
||||
MOZ_TRY(NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile)));
|
||||
nsAutoString destLeafName;
|
||||
MOZ_TRY(destFile->GetLeafName(destLeafName));
|
||||
|
||||
nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIFile> destDir;
|
||||
MOZ_TRY(destFile->GetParent(getter_AddRefs(destDir)));
|
||||
|
||||
nsAutoString destLeafName;
|
||||
rv = destFile->GetLeafName(destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_TRY(mTempFile->MoveTo(destDir, destLeafName));
|
||||
destFile->SetPermissions(0666);
|
||||
|
||||
nsCOMPtr<nsIFile> destDir;
|
||||
rv = destFile->GetParent(getter_AddRefs(destDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mTempFile->MoveTo(destDir, destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
destFile->SetPermissions(0666);
|
||||
mTempFile = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
class nsDeviceContextSpecAndroid final : public nsIDeviceContextSpec {
|
||||
private:
|
||||
~nsDeviceContextSpecAndroid() {}
|
||||
virtual ~nsDeviceContextSpecAndroid();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -37,13 +37,14 @@ class nsDeviceContextSpecX : public nsIDeviceContextSpec {
|
||||
virtual ~nsDeviceContextSpecX();
|
||||
|
||||
protected:
|
||||
PMPrintSession mPrintSession; // printing context.
|
||||
PMPageFormat mPageFormat; // page format.
|
||||
PMPrintSettings mPrintSettings; // print settings.
|
||||
PMPrintSession mPrintSession = nullptr; // printing context.
|
||||
PMPageFormat mPageFormat = nullptr; // page format.
|
||||
PMPrintSettings mPrintSettings = nullptr; // print settings.
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream; // Output stream from settings.
|
||||
#ifdef MOZ_ENABLE_SKIA_PDF
|
||||
nsCOMPtr<nsIFile>
|
||||
mTempFile; // file "print" output is generated to if printing via PDF
|
||||
bool mPrintViaSkPDF;
|
||||
// file "print" output generated if printing via PDF
|
||||
nsCOMPtr<nsIFile> mTempFile;
|
||||
bool mPrintViaSkPDF = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsCUPSShim.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsPaper.h"
|
||||
#include "nsPrinterListCUPS.h"
|
||||
#include "nsPrintSettingsX.h"
|
||||
@ -40,23 +41,11 @@ 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() = default;
|
||||
|
||||
nsDeviceContextSpecX::~nsDeviceContextSpecX() {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
@ -85,13 +74,16 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget* aWidget, nsIPrintSettings* a
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
bool toFile;
|
||||
settings->GetPrintToFile(&toFile);
|
||||
|
||||
NSPrintInfo* printInfo = settings->CreateOrCopyPrintInfo();
|
||||
if (!printInfo) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (aPS->GetOutputDestination() == nsIPrintSettings::kOutputDestinationStream) {
|
||||
aPS->GetOutputStream(getter_AddRefs(mOutputStream));
|
||||
if (!mOutputStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
mPrintSession = static_cast<PMPrintSession>([printInfo PMPrintSession]);
|
||||
mPageFormat = static_cast<PMPageFormat>([printInfo PMPageFormat]);
|
||||
mPrintSettings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
|
||||
@ -138,8 +130,7 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget* aWidget, nsIPrintSettings* a
|
||||
}
|
||||
#endif
|
||||
|
||||
int16_t outputFormat;
|
||||
aPS->GetOutputFormat(&outputFormat);
|
||||
int16_t outputFormat = aPS->GetOutputFormat();
|
||||
|
||||
if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
// We don't actually currently support/use kOutputFormatPDF on mac, but
|
||||
@ -287,6 +278,7 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
||||
|
||||
#ifdef MOZ_ENABLE_SKIA_PDF
|
||||
if (mPrintViaSkPDF) {
|
||||
// TODO: Add support for stream printing via SkPDF if we enable that again.
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsAutoCString tempPath("tmp-printing.pdf");
|
||||
@ -299,5 +291,6 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
||||
}
|
||||
#endif
|
||||
|
||||
return PrintTargetCG::CreateOrNull(mPrintSession, mPageFormat, mPrintSettings, size);
|
||||
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat, mPrintSettings,
|
||||
size);
|
||||
}
|
||||
|
@ -180,7 +180,9 @@ NSPrintInfo* nsPrintSettingsX::CreateOrCopyPrintInfo(bool aWithScaling) {
|
||||
}
|
||||
|
||||
if (mDisposition.IsEmpty()) {
|
||||
if (mPrintToFile) {
|
||||
// NOTE: It's unclear what to do for kOutputDestinationStream but this is
|
||||
// only for the native print dialog where that can't happen.
|
||||
if (mOutputDestination == kOutputDestinationFile) {
|
||||
[printInfo setJobDisposition:NSPrintSaveJob];
|
||||
} else {
|
||||
[printInfo setJobDisposition:NSPrintSpoolJob];
|
||||
@ -292,7 +294,12 @@ void nsPrintSettingsX::SetFromPrintInfo(NSPrintInfo* aPrintInfo, bool aAdoptPrin
|
||||
mScaling = round(double([aPrintInfo scalingFactor]) * 100.0) / 100.0;
|
||||
}
|
||||
|
||||
mPrintToFile = [aPrintInfo jobDisposition] == NSPrintSaveJob;
|
||||
mOutputDestination = [&] {
|
||||
if ([aPrintInfo jobDisposition] == NSPrintSaveJob) {
|
||||
return kOutputDestinationFile;
|
||||
}
|
||||
return kOutputDestinationPrinter;
|
||||
}();
|
||||
|
||||
NSDictionary* dict = [aPrintInfo dictionary];
|
||||
const char* filePath = [[dict objectForKey:NSPrintJobSavingURL] fileSystemRepresentation];
|
||||
|
@ -74,37 +74,46 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecGTK::MakePrintTarget() {
|
||||
width /= TWIPS_PER_POINT_FLOAT;
|
||||
height /= TWIPS_PER_POINT_FLOAT;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// We shouldn't be attempting to get a surface if we've already got a spool
|
||||
// file.
|
||||
MOZ_ASSERT(!mSpoolFile);
|
||||
|
||||
// Spool file. Use Glib's temporary file function since we're
|
||||
// already dependent on the gtk software stack.
|
||||
gchar* buf;
|
||||
gint fd = g_file_open_tmp("XXXXXX.tmp", &buf, nullptr);
|
||||
if (-1 == fd) return nullptr;
|
||||
close(fd);
|
||||
|
||||
rv = NS_NewNativeLocalFile(nsDependentCString(buf), false,
|
||||
getter_AddRefs(mSpoolFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
unlink(buf);
|
||||
auto stream = [&]() -> nsCOMPtr<nsIOutputStream> {
|
||||
if (mPrintSettings->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationStream) {
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
mPrintSettings->GetOutputStream(getter_AddRefs(out));
|
||||
return out;
|
||||
}
|
||||
// Spool file. Use Glib's temporary file function since we're
|
||||
// already dependent on the gtk software stack.
|
||||
gchar* buf;
|
||||
gint fd = g_file_open_tmp("XXXXXX.tmp", &buf, nullptr);
|
||||
if (-1 == fd) {
|
||||
return nullptr;
|
||||
}
|
||||
close(fd);
|
||||
if (NS_FAILED(NS_NewNativeLocalFile(nsDependentCString(buf), false,
|
||||
getter_AddRefs(mSpoolFile)))) {
|
||||
unlink(buf);
|
||||
g_free(buf);
|
||||
return nullptr;
|
||||
}
|
||||
mSpoolName = buf;
|
||||
g_free(buf);
|
||||
mSpoolFile->SetPermissions(0600);
|
||||
nsCOMPtr<nsIFileOutputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
if (NS_FAILED(stream->Init(mSpoolFile, -1, -1, 0))) {
|
||||
return nullptr;
|
||||
}
|
||||
return stream;
|
||||
}();
|
||||
|
||||
if (!stream) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mSpoolName = buf;
|
||||
g_free(buf);
|
||||
|
||||
mSpoolFile->SetPermissions(0600);
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
rv = stream->Init(mSpoolFile, -1, -1, 0);
|
||||
if (NS_FAILED(rv)) return nullptr;
|
||||
|
||||
return PrintTargetPDF::CreateOrNull(stream, IntSize::Ceil(width, height));
|
||||
}
|
||||
|
||||
@ -197,12 +206,6 @@ NS_IMETHODIMP nsDeviceContextSpecGTK::Init(nsIWidget* aWidget,
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
// This is only set by embedders
|
||||
bool toFile;
|
||||
aPS->GetPrintToFile(&toFile);
|
||||
|
||||
mToPrinter = !toFile && !aIsPrintPreview;
|
||||
|
||||
mGtkPrintSettings = mPrintSettings->GetGtkPrintSettings();
|
||||
mGtkPageSetup = mPrintSettings->GetGtkPageSetup();
|
||||
|
||||
@ -309,55 +312,65 @@ nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecGTK::EndDocument() {
|
||||
if (mToPrinter) {
|
||||
// At this point, we might have a GtkPrinter set up in nsPrintSettingsGTK,
|
||||
// or we might not. In the single-process case, we probably will, as this
|
||||
// is populated by the print settings dialog, or set to the default
|
||||
// printer.
|
||||
// In the multi-process case, we proxy the print settings dialog over to
|
||||
// the parent process, and only get the name of the printer back on the
|
||||
// content process side. In that case, we need to enumerate the printers
|
||||
// on the content side, and find a printer with a matching name.
|
||||
switch (mPrintSettings->GetOutputDestination()) {
|
||||
case nsIPrintSettings::kOutputDestinationPrinter: {
|
||||
// At this point, we might have a GtkPrinter set up in nsPrintSettingsGTK,
|
||||
// or we might not. In the single-process case, we probably will, as this
|
||||
// is populated by the print settings dialog, or set to the default
|
||||
// printer.
|
||||
// In the multi-process case, we proxy the print settings dialog over to
|
||||
// the parent process, and only get the name of the printer back on the
|
||||
// content process side. In that case, we need to enumerate the printers
|
||||
// on the content side, and find a printer with a matching name.
|
||||
|
||||
if (mPrintSettings->GetGtkPrinter()) {
|
||||
// We have a printer, so we can print right away.
|
||||
StartPrintJob();
|
||||
} else {
|
||||
// We don't have a printer. We have to enumerate the printers and find
|
||||
// one with a matching name.
|
||||
NS_DispatchToCurrentThread(
|
||||
NewRunnableMethod("nsDeviceContextSpecGTK::EnumeratePrinters", this,
|
||||
&nsDeviceContextSpecGTK::EnumeratePrinters));
|
||||
if (mPrintSettings->GetGtkPrinter()) {
|
||||
// We have a printer, so we can print right away.
|
||||
StartPrintJob();
|
||||
} else {
|
||||
// We don't have a printer. We have to enumerate the printers and find
|
||||
// one with a matching name.
|
||||
NS_DispatchToCurrentThread(
|
||||
NewRunnableMethod("nsDeviceContextSpecGTK::EnumeratePrinters", this,
|
||||
&nsDeviceContextSpecGTK::EnumeratePrinters));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Handle print-to-file ourselves for the benefit of embedders
|
||||
nsString targetPath;
|
||||
nsCOMPtr<nsIFile> destFile;
|
||||
mPrintSettings->GetToFileName(targetPath);
|
||||
case nsIPrintSettings::kOutputDestinationFile: {
|
||||
// Handle print-to-file ourselves for the benefit of embedders
|
||||
nsString targetPath;
|
||||
nsCOMPtr<nsIFile> destFile;
|
||||
mPrintSettings->GetToFileName(targetPath);
|
||||
|
||||
nsresult rv = NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(targetPath, false, getter_AddRefs(destFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString destLeafName;
|
||||
rv = destFile->GetLeafName(destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString destLeafName;
|
||||
rv = destFile->GetLeafName(destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> destDir;
|
||||
rv = destFile->GetParent(getter_AddRefs(destDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIFile> destDir;
|
||||
rv = destFile->GetParent(getter_AddRefs(destDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mSpoolFile->MoveTo(destDir, destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mSpoolFile->MoveTo(destDir, destLeafName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSpoolFile = nullptr;
|
||||
mSpoolFile = nullptr;
|
||||
|
||||
// This is the standard way to get the UNIX umask. Ugh.
|
||||
mode_t mask = umask(0);
|
||||
umask(mask);
|
||||
// If you're not familiar with umasks, they contain the bits of what NOT
|
||||
// to set in the permissions (thats because files and directories have
|
||||
// different numbers of bits for their permissions)
|
||||
destFile->SetPermissions(0666 & ~(mask));
|
||||
// This is the standard way to get the UNIX umask. Ugh.
|
||||
mode_t mask = umask(0);
|
||||
umask(mask);
|
||||
// If you're not familiar with umasks, they contain the bits of what NOT
|
||||
// to set in the permissions (thats because files and directories have
|
||||
// different numbers of bits for their permissions)
|
||||
destFile->SetPermissions(0666 & ~(mask));
|
||||
break;
|
||||
}
|
||||
case nsIPrintSettings::kOutputDestinationStream:
|
||||
// Nothing to do, handled in MakePrintTarget.
|
||||
MOZ_ASSERT(!mSpoolFile);
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ class nsDeviceContextSpecGTK : public nsIDeviceContextSpec {
|
||||
protected:
|
||||
virtual ~nsDeviceContextSpecGTK();
|
||||
nsCOMPtr<nsPrintSettingsGTK> mPrintSettings;
|
||||
bool mToPrinter : 1; /* If true, print to printer */
|
||||
GtkPrintSettings* mGtkPrintSettings;
|
||||
GtkPageSetup* mGtkPageSetup;
|
||||
|
||||
|
@ -409,7 +409,8 @@ nsresult nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings* aNSSettings) {
|
||||
// printing won't occur! (We manually copy the spool file when this flag is
|
||||
// set, because we love our embedders) Even if it is print-to-file in GTK's
|
||||
// case, GTK does The Right Thing when we send the job.
|
||||
aNSSettings->SetPrintToFile(false);
|
||||
aNSSettings->SetOutputDestination(
|
||||
nsIPrintSettings::kOutputDestinationPrinter);
|
||||
|
||||
aNSSettings->SetShrinkToFit(
|
||||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shrink_to_fit_toggle)));
|
||||
|
@ -612,9 +612,6 @@ nsPrintSettingsGTK::GetPageRanges(nsTArray<int32_t>& aPages) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsGTK::GetResolution(int32_t* aResolution) {
|
||||
if (!gtk_print_settings_has_key(mPrintSettings,
|
||||
GTK_PRINT_SETTINGS_RESOLUTION))
|
||||
return NS_ERROR_FAILURE;
|
||||
*aResolution = gtk_print_settings_get_resolution(mPrintSettings);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
|
||||
%{ C++
|
||||
#include "nsMargin.h"
|
||||
#include "nsTArray.h"
|
||||
@ -22,6 +21,7 @@ native nsNativeIntMargin(nsIntMargin);
|
||||
[ref] native nsNativeIntMarginRef(nsIntMargin);
|
||||
|
||||
interface nsIPrintSession;
|
||||
interface nsIOutputStream;
|
||||
|
||||
/**
|
||||
* Simplified graphics interface for JS rendering.
|
||||
@ -78,24 +78,25 @@ interface nsIPrintSettings : nsISupports
|
||||
const long kJustCenter = 1;
|
||||
const long kJustRight = 2;
|
||||
|
||||
/**
|
||||
* Page Size Unit Constants
|
||||
*/
|
||||
/** Page Size Unit Constants */
|
||||
const short kPaperSizeInches = 0;
|
||||
const short kPaperSizeMillimeters = 1;
|
||||
|
||||
/**
|
||||
* Orientation Constants
|
||||
*/
|
||||
/** Orientation Constants */
|
||||
const short kPortraitOrientation = 0;
|
||||
const short kLandscapeOrientation = 1;
|
||||
|
||||
/**
|
||||
* Output file format
|
||||
*/
|
||||
/** Output file format */
|
||||
const short kOutputFormatNative = 0;
|
||||
const short kOutputFormatPDF = 2;
|
||||
|
||||
/** Output destination */
|
||||
cenum OutputDestinationType : 8 {
|
||||
kOutputDestinationPrinter = 0,
|
||||
kOutputDestinationFile = 1,
|
||||
kOutputDestinationStream = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Duplex printing options.
|
||||
*
|
||||
@ -298,17 +299,19 @@ interface nsIPrintSettings : nsISupports
|
||||
*/
|
||||
attribute long numPagesPerSheet;
|
||||
|
||||
attribute AString printerName; /* name of destination printer */
|
||||
/** Output device information */
|
||||
[infallible] attribute nsIPrintSettings_OutputDestinationType outputDestination;
|
||||
[infallible] attribute short outputFormat;
|
||||
|
||||
attribute boolean printToFile;
|
||||
attribute AString toFileName;
|
||||
attribute short outputFormat;
|
||||
attribute AString printerName; /* for kOutputDestinationPrinter */
|
||||
attribute AString toFileName; /* for kOutputDestinationFile */
|
||||
attribute nsIOutputStream outputStream; /* for kOutputDestinationPrinter */
|
||||
|
||||
attribute long printPageDelay; /* in milliseconds */
|
||||
[infallible] attribute long printPageDelay; /* in milliseconds */
|
||||
|
||||
attribute long resolution; /* print resolution (dpi) */
|
||||
[infallible] attribute long resolution; /* print resolution (dpi) */
|
||||
|
||||
attribute long duplex; /* duplex mode */
|
||||
[infallible] attribute long duplex; /* duplex mode */
|
||||
|
||||
/* initialize helpers */
|
||||
/**
|
||||
@ -316,7 +319,7 @@ interface nsIPrintSettings : nsISupports
|
||||
* from a printer specified by the "printerName" attr.
|
||||
* If a different name is set into the "printerName"
|
||||
* attribute than the one it was initialized with the PS
|
||||
* will then get intialized from that printer.
|
||||
* will then get initialized from that printer.
|
||||
*/
|
||||
attribute boolean isInitializedFromPrinter;
|
||||
|
||||
@ -324,7 +327,7 @@ interface nsIPrintSettings : nsISupports
|
||||
* This attribute tracks whether the PS has been initialized
|
||||
* from prefs. If a different name is set into the "printerName"
|
||||
* attribute than the one it was initialized with the PS
|
||||
* will then get intialized from prefs again.
|
||||
* will then get initialized from prefs again.
|
||||
*/
|
||||
attribute boolean isInitializedFromPrefs;
|
||||
|
||||
|
@ -20,33 +20,7 @@ using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPrintSettings, nsIPrintSettings)
|
||||
|
||||
nsPrintSettings::nsPrintSettings()
|
||||
: mScaling(1.0),
|
||||
mPrintBGColors(false),
|
||||
mPrintBGImages(false),
|
||||
mIsCancelled(false),
|
||||
mSaveOnCancel(true),
|
||||
mPrintSilent(false),
|
||||
mShrinkToFit(true),
|
||||
mShowMarginGuides(false),
|
||||
mHonorPageRuleMargins(true),
|
||||
mIsPrintSelectionRBEnabled(false),
|
||||
mPrintSelectionOnly(false),
|
||||
mPrintPageDelay(50),
|
||||
mPaperWidth(8.5),
|
||||
mPaperHeight(11.0),
|
||||
mPaperSizeUnit(kPaperSizeInches),
|
||||
mPrintReversed(false),
|
||||
mPrintInColor(true),
|
||||
mOrientation(kPortraitOrientation),
|
||||
mResolution(0),
|
||||
mDuplex(0),
|
||||
mNumCopies(1),
|
||||
mNumPagesPerSheet(1),
|
||||
mPrintToFile(false),
|
||||
mOutputFormat(kOutputFormatNative),
|
||||
mIsInitedFromPrinter(false),
|
||||
mIsInitedFromPrefs(false) {
|
||||
nsPrintSettings::nsPrintSettings() {
|
||||
/* member initializers and constructor code */
|
||||
int32_t marginWidth = NS_INCHES_TO_INT_TWIPS(DEFAULT_MARGIN_WIDTH);
|
||||
mMargin.SizeTo(marginWidth, marginWidth, marginWidth, marginWidth);
|
||||
@ -219,13 +193,25 @@ NS_IMETHODIMP nsPrintSettings::SetNumPagesPerSheet(int32_t aNumPagesPerSheet) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettings::GetPrintToFile(bool* aPrintToFile) {
|
||||
NS_ENSURE_ARG_POINTER(aPrintToFile);
|
||||
*aPrintToFile = mPrintToFile;
|
||||
NS_IMETHODIMP nsPrintSettings::GetOutputDestination(
|
||||
OutputDestinationType* aDestination) {
|
||||
*aDestination = mOutputDestination;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP nsPrintSettings::SetPrintToFile(bool aPrintToFile) {
|
||||
mPrintToFile = aPrintToFile;
|
||||
|
||||
NS_IMETHODIMP nsPrintSettings::SetOutputDestination(
|
||||
OutputDestinationType aDestination) {
|
||||
mOutputDestination = aDestination;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettings::SetOutputStream(nsIOutputStream* aStream) {
|
||||
mOutputStream = aStream;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettings::GetOutputStream(nsIOutputStream** aStream) {
|
||||
NS_IF_ADDREF(*aStream = mOutputStream.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -946,7 +932,8 @@ nsPrintSettings& nsPrintSettings::operator=(const nsPrintSettings& rhs) {
|
||||
mNumCopies = rhs.mNumCopies;
|
||||
mNumPagesPerSheet = rhs.mNumPagesPerSheet;
|
||||
mPrinter = rhs.mPrinter;
|
||||
mPrintToFile = rhs.mPrintToFile;
|
||||
mOutputDestination = rhs.mOutputDestination;
|
||||
mOutputStream = rhs.mOutputStream;
|
||||
mToFileName = rhs.mToFileName;
|
||||
mOutputFormat = rhs.mOutputFormat;
|
||||
mIsInitedFromPrinter = rhs.mIsInitedFromPrinter;
|
||||
|
@ -83,8 +83,6 @@ class nsPrintSettings : public nsIPrintSettings {
|
||||
virtual nsresult _Clone(nsIPrintSettings** _retval);
|
||||
virtual nsresult _Assign(nsIPrintSettings* aPS);
|
||||
|
||||
typedef enum { eHeader, eFooter } nsHeaderFooterEnum;
|
||||
|
||||
// Members
|
||||
nsWeakPtr mSession; // Should never be touched by Clone or Assign
|
||||
|
||||
@ -95,19 +93,20 @@ class nsPrintSettings : public nsIPrintSettings {
|
||||
|
||||
nsTArray<int32_t> mPageRanges;
|
||||
|
||||
double mScaling;
|
||||
bool mPrintBGColors; // print background colors
|
||||
bool mPrintBGImages; // print background images
|
||||
double mScaling = 1.0;
|
||||
bool mPrintBGColors = false;
|
||||
bool mPrintBGImages = false;
|
||||
|
||||
bool mIsCancelled;
|
||||
bool mSaveOnCancel;
|
||||
bool mPrintSilent;
|
||||
bool mShrinkToFit;
|
||||
bool mShowMarginGuides;
|
||||
bool mHonorPageRuleMargins;
|
||||
bool mIsPrintSelectionRBEnabled;
|
||||
bool mPrintSelectionOnly;
|
||||
int32_t mPrintPageDelay;
|
||||
bool mIsCancelled = false;
|
||||
bool mSaveOnCancel = true;
|
||||
bool mPrintSilent = false;
|
||||
bool mShrinkToFit = true;
|
||||
bool mShowMarginGuides = false;
|
||||
bool mHonorPageRuleMargins = true;
|
||||
bool mIsPrintSelectionRBEnabled = false;
|
||||
bool mPrintSelectionOnly = false;
|
||||
|
||||
int32_t mPrintPageDelay = 50; // XXX Do we really want this?
|
||||
|
||||
nsString mTitle;
|
||||
nsString mURL;
|
||||
@ -115,23 +114,24 @@ class nsPrintSettings : public nsIPrintSettings {
|
||||
nsString mFooterStrs[NUM_HEAD_FOOT];
|
||||
|
||||
nsString mPaperId;
|
||||
double mPaperWidth;
|
||||
double mPaperHeight;
|
||||
int16_t mPaperSizeUnit;
|
||||
double mPaperWidth = 8.5;
|
||||
double mPaperHeight = 11.0;
|
||||
int16_t mPaperSizeUnit = kPaperSizeInches;
|
||||
|
||||
bool mPrintReversed;
|
||||
bool mPrintInColor; // a false means grayscale
|
||||
int32_t mOrientation; // see orientation consts
|
||||
int32_t mResolution;
|
||||
int32_t mDuplex;
|
||||
int32_t mNumCopies;
|
||||
int32_t mNumPagesPerSheet;
|
||||
bool mPrintReversed = false;
|
||||
bool mPrintInColor = true;
|
||||
int32_t mOrientation = kPortraitOrientation;
|
||||
int32_t mResolution = 0;
|
||||
int32_t mDuplex = kDuplexNone;
|
||||
int32_t mNumCopies = 1;
|
||||
int32_t mNumPagesPerSheet = 1;
|
||||
int16_t mOutputFormat = kOutputFormatNative;
|
||||
OutputDestinationType mOutputDestination = kOutputDestinationPrinter;
|
||||
nsString mPrinter;
|
||||
bool mPrintToFile;
|
||||
nsString mToFileName;
|
||||
int16_t mOutputFormat;
|
||||
bool mIsInitedFromPrinter;
|
||||
bool mIsInitedFromPrefs;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
bool mIsInitedFromPrinter = false;
|
||||
bool mIsInitedFromPrefs = false;
|
||||
};
|
||||
|
||||
#endif /* nsPrintSettings_h__ */
|
||||
|
@ -154,14 +154,15 @@ nsPrintSettingsService::SerializeToPrintData(nsIPrintSettings* aSettings,
|
||||
|
||||
aSettings->GetPrinterName(data->printerName());
|
||||
|
||||
aSettings->GetPrintToFile(&data->printToFile());
|
||||
data->outputDestination() = aSettings->GetOutputDestination();
|
||||
|
||||
aSettings->GetToFileName(data->toFileName());
|
||||
|
||||
aSettings->GetOutputFormat(&data->outputFormat());
|
||||
aSettings->GetPrintPageDelay(&data->printPageDelay());
|
||||
aSettings->GetResolution(&data->resolution());
|
||||
aSettings->GetDuplex(&data->duplex());
|
||||
data->outputFormat() = aSettings->GetOutputFormat();
|
||||
data->printPageDelay() = aSettings->GetPrintPageDelay();
|
||||
data->resolution() = aSettings->GetResolution();
|
||||
data->duplex() = aSettings->GetDuplex();
|
||||
|
||||
aSettings->GetIsInitializedFromPrinter(&data->isInitializedFromPrinter());
|
||||
aSettings->GetIsInitializedFromPrefs(&data->isInitializedFromPrefs());
|
||||
|
||||
@ -241,11 +242,11 @@ nsPrintSettingsService::DeserializeToPrintSettings(const PrintData& data,
|
||||
settings->SetNumCopies(data.numCopies());
|
||||
settings->SetNumPagesPerSheet(data.numPagesPerSheet());
|
||||
|
||||
settings->SetOutputDestination(
|
||||
nsIPrintSettings::OutputDestinationType(data.outputDestination()));
|
||||
settings->SetPrinterName(data.printerName());
|
||||
|
||||
settings->SetPrintToFile(data.printToFile());
|
||||
|
||||
settings->SetToFileName(data.toFileName());
|
||||
// Output stream intentionally unset, child processes shouldn't care about it.
|
||||
|
||||
settings->SetOutputFormat(data.outputFormat());
|
||||
settings->SetPrintPageDelay(data.printPageDelay());
|
||||
@ -524,7 +525,9 @@ nsresult nsPrintSettingsService::ReadPrefs(nsIPrintSettings* aPS,
|
||||
|
||||
if (aFlags & nsIPrintSettings::kInitSavePrintToFile) {
|
||||
if (GETBOOLPREF(kPrintToFile, &b)) {
|
||||
aPS->SetPrintToFile(b);
|
||||
aPS->SetOutputDestination(
|
||||
b ? nsIPrintSettings::kOutputDestinationFile
|
||||
: nsIPrintSettings::kOutputDestinationPrinter);
|
||||
noValidPrefsFound = false;
|
||||
}
|
||||
}
|
||||
@ -740,9 +743,9 @@ nsresult nsPrintSettingsService::WritePrefs(nsIPrintSettings* aPS,
|
||||
}
|
||||
|
||||
if (aFlags & nsIPrintSettings::kInitSavePrintToFile) {
|
||||
if (NS_SUCCEEDED(aPS->GetPrintToFile(&b))) {
|
||||
Preferences::SetBool(GetPrefName(kPrintToFile, aPrinterName), b);
|
||||
}
|
||||
Preferences::SetBool(GetPrefName(kPrintToFile, aPrinterName),
|
||||
aPS->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationFile);
|
||||
}
|
||||
|
||||
if (aFlags & nsIPrintSettings::kInitSaveToFileName) {
|
||||
|
@ -111,7 +111,7 @@ NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
|
||||
// Get the Printer Name to be used and output format.
|
||||
nsAutoString printerName;
|
||||
if (mPrintSettings) {
|
||||
mPrintSettings->GetOutputFormat(&mOutputFormat);
|
||||
mOutputFormat = mPrintSettings->GetOutputFormat();
|
||||
mPrintSettings->GetPrinterName(printerName);
|
||||
}
|
||||
|
||||
@ -272,9 +272,6 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget() {
|
||||
#endif
|
||||
|
||||
if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
nsString filename;
|
||||
mPrintSettings->GetToFileName(filename);
|
||||
|
||||
double width, height;
|
||||
mPrintSettings->GetEffectiveSheetSize(&width, &height);
|
||||
if (width <= 0 || height <= 0) {
|
||||
@ -285,26 +282,37 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget() {
|
||||
width /= TWIPS_PER_POINT_FLOAT;
|
||||
height /= TWIPS_PER_POINT_FLOAT;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv;
|
||||
if (!filename.IsEmpty()) {
|
||||
file = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
rv = file->InitWithPath(filename);
|
||||
} else {
|
||||
rv = NS_OpenAnonymousTemporaryNsIFile(getter_AddRefs(mTempFile));
|
||||
file = mTempFile;
|
||||
}
|
||||
auto stream = [&]() -> nsCOMPtr<nsIOutputStream> {
|
||||
if (mPrintSettings->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationStream) {
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
mPrintSettings->GetOutputStream(getter_AddRefs(out));
|
||||
return out;
|
||||
}
|
||||
nsAutoString filename;
|
||||
mPrintSettings->GetToFileName(filename);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv;
|
||||
if (!filename.IsEmpty()) {
|
||||
file = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
rv = file->InitWithPath(filename);
|
||||
} else {
|
||||
rv = NS_OpenAnonymousTemporaryNsIFile(getter_AddRefs(mTempFile));
|
||||
file = mTempFile;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
rv = stream->Init(file, -1, -1, 0);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
if (NS_FAILED(stream->Init(file, -1, -1, 0))) {
|
||||
return nullptr;
|
||||
}
|
||||
return stream;
|
||||
}();
|
||||
|
||||
return PrintTargetPDF::CreateOrNull(stream, IntSize::Ceil(width, height));
|
||||
}
|
||||
@ -606,8 +614,7 @@ nsPrinterListWin::InitPrintSettingsFromPrinter(
|
||||
}
|
||||
|
||||
// When printing to PDF on Windows there is no associated printer driver.
|
||||
int16_t outputFormat;
|
||||
aPrintSettings->GetOutputFormat(&outputFormat);
|
||||
int16_t outputFormat = aPrintSettings->GetOutputFormat();
|
||||
if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -314,11 +314,13 @@ static nsresult ShowNativePrintDialog(HWND aHWnd,
|
||||
if (prntdlg.Flags & PD_PRINTTOFILE) {
|
||||
char16ptr_t fileName = &(((wchar_t*)devnames)[devnames->wOutputOffset]);
|
||||
NS_ASSERTION(wcscmp(fileName, L"FILE:") == 0, "FileName must be `FILE:`");
|
||||
aPrintSettings->SetOutputDestination(
|
||||
nsIPrintSettings::kOutputDestinationFile);
|
||||
aPrintSettings->SetToFileName(nsDependentString(fileName));
|
||||
aPrintSettings->SetPrintToFile(true);
|
||||
} else {
|
||||
// clear "print to file" info
|
||||
aPrintSettings->SetPrintToFile(false);
|
||||
aPrintSettings->SetOutputDestination(
|
||||
nsIPrintSettings::kOutputDestinationPrinter);
|
||||
aPrintSettings->SetToFileName(u""_ns);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user