зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1604506
- Add print command to marionette, r=marionette-reviewers,whimboo,ato
Add a WebDriver:Print command to marionette, following the proposed WebDriver spec at https://github.com/w3c/webdriver/pull/1468 The implementation is largely the same as that added to the remote agent in Bug 1599994. Depends on D57471 Differential Revision: https://phabricator.services.mozilla.com/D57472 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
10c86c0f8d
Коммит
9fe8166c64
|
@ -5,7 +5,11 @@
|
|||
"use strict";
|
||||
/* global XPCNativeWrapper */
|
||||
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { clearInterval, setInterval } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
@ -3676,6 +3680,187 @@ GeckoDriver.prototype.teardownReftest = function() {
|
|||
this._reftest = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Print page as PDF.
|
||||
*
|
||||
* @param {boolean=} landscape
|
||||
* Paper orientation. Defaults to false.
|
||||
* @param {number=} margin.bottom
|
||||
* Bottom margin in cm. Defaults to 1cm (~0.4 inches).
|
||||
* @param {number=} margin.left
|
||||
* Left margin in cm. Defaults to 1cm (~0.4 inches).
|
||||
* @param {number=} margin.right
|
||||
* Right margin in cm. Defaults to 1cm (~0.4 inches).
|
||||
* @param {number=} margin.top
|
||||
* Top margin in cm. Defaults to 1cm (~0.4 inches).
|
||||
* @param {string=} pageRanges (not supported)
|
||||
* Paper ranges to print, e.g., '1-5, 8, 11-13'.
|
||||
* Defaults to the empty string, which means print all pages.
|
||||
* @param {number=} page.height
|
||||
* Paper height in cm. Defaults to US letter height (11 inches / 27.94cm)
|
||||
* @param {number=} page.width
|
||||
* Paper width in cm. Defaults to US letter width (8.5 inches / 21.59cm)
|
||||
* @param {boolean=} shrinkToFit
|
||||
* Whether or not to override page size as defined by CSS.
|
||||
* Defaults to true, in which case the content will be scaled
|
||||
* to fit the paper size.
|
||||
* @param {boolean=} printBackground
|
||||
* Print background graphics. Defaults to false.
|
||||
* @param {number=} scale
|
||||
* Scale of the webpage rendering. Defaults to 1.
|
||||
*
|
||||
* @return {string}
|
||||
* Base64 encoded PDF representing printed document
|
||||
*/
|
||||
GeckoDriver.prototype.print = async function(cmd) {
|
||||
const printMaxScaleValue = 2.0;
|
||||
const printMinScaleValue = 0.1;
|
||||
const letterPaperSizeCm = {
|
||||
width: 21.59,
|
||||
height: 27.94,
|
||||
};
|
||||
|
||||
assert.content(this.context);
|
||||
assert.open(this.getCurrentWindow());
|
||||
await this._handleUserPrompts();
|
||||
|
||||
const {
|
||||
landscape = false,
|
||||
margin = {
|
||||
top: 1,
|
||||
bottom: 1,
|
||||
left: 1,
|
||||
right: 1,
|
||||
},
|
||||
page = letterPaperSizeCm,
|
||||
shrinkToFit = true,
|
||||
printBackground = false,
|
||||
scale = 1.0,
|
||||
} = cmd.parameters;
|
||||
|
||||
for (let prop of ["top", "bottom", "left", "right"]) {
|
||||
assert.positiveNumber(
|
||||
margin[prop],
|
||||
pprint`margin.${prop} is not a positive number`
|
||||
);
|
||||
}
|
||||
for (let prop of ["width", "height"]) {
|
||||
assert.positiveNumber(
|
||||
page[prop],
|
||||
pprint`page.${prop} is not a positive number`
|
||||
);
|
||||
}
|
||||
assert.positiveNumber(scale, `scale ${scale} is not a positive number`);
|
||||
assert.that(
|
||||
s => s >= printMinScaleValue && scale <= printMaxScaleValue,
|
||||
`scale ${scale} is outside the range ${printMinScaleValue}-${printMaxScaleValue}`
|
||||
)(scale);
|
||||
assert.boolean(shrinkToFit);
|
||||
assert.boolean(landscape);
|
||||
assert.boolean(printBackground);
|
||||
|
||||
// Create a unique filename for the temporary PDF file
|
||||
const basePath = OS.Path.join(OS.Constants.Path.tmpDir, "marionette.pdf");
|
||||
const { file, path: filePath } = await OS.File.openUnique(basePath);
|
||||
await file.close();
|
||||
|
||||
const psService = Cc["@mozilla.org/gfx/printsettings-service;1"].getService(
|
||||
Ci.nsIPrintSettingsService
|
||||
);
|
||||
|
||||
const printSettings = psService.newPrintSettings;
|
||||
printSettings.isInitializedFromPrinter = true;
|
||||
printSettings.isInitializedFromPrefs = true;
|
||||
printSettings.outputFormat = Ci.nsIPrintSettings.kOutputFormatPDF;
|
||||
printSettings.printerName = "";
|
||||
printSettings.printSilent = true;
|
||||
printSettings.printToFile = true;
|
||||
printSettings.showPrintProgress = false;
|
||||
printSettings.toFileName = filePath;
|
||||
|
||||
printSettings.paperSizeUnit = Ci.nsIPrintSettings.kPaperSizeMillimeters;
|
||||
printSettings.paperWidth = page.width * 10;
|
||||
printSettings.paperHeight = page.height * 10;
|
||||
|
||||
// Margins are always in inches irrspective of paperSizeUnit
|
||||
|
||||
let cmToInches = cm => cm / 2.54;
|
||||
|
||||
printSettings.marginBottom = cmToInches(margin.bottom);
|
||||
printSettings.marginLeft = cmToInches(margin.left);
|
||||
printSettings.marginRight = cmToInches(margin.right);
|
||||
printSettings.marginTop = cmToInches(margin.top);
|
||||
|
||||
printSettings.printBGColors = printBackground;
|
||||
printSettings.printBGImages = printBackground;
|
||||
printSettings.scaling = scale;
|
||||
printSettings.shrinkToFit = shrinkToFit;
|
||||
|
||||
printSettings.headerStrCenter = "";
|
||||
printSettings.headerStrLeft = "";
|
||||
printSettings.headerStrRight = "";
|
||||
printSettings.footerStrCenter = "";
|
||||
printSettings.footerStrLeft = "";
|
||||
printSettings.footerStrRight = "";
|
||||
|
||||
if (landscape) {
|
||||
printSettings.orientation = Ci.nsIPrintSettings.kLandscapeOrientation;
|
||||
}
|
||||
|
||||
await new Promise(resolve => {
|
||||
// Bug 1603739 - With e10s enabled the WebProgressListener states
|
||||
// STOP too early, which means the file hasn't been completely written.
|
||||
const waitForFileWritten = () => {
|
||||
const DELAY_CHECK_FILE_COMPLETELY_WRITTEN = 100;
|
||||
|
||||
let lastSize = 0;
|
||||
const timerId = setInterval(async () => {
|
||||
const fileInfo = await OS.File.stat(filePath);
|
||||
if (lastSize > 0 && fileInfo.size == lastSize) {
|
||||
clearInterval(timerId);
|
||||
resolve();
|
||||
}
|
||||
lastSize = fileInfo.size;
|
||||
}, DELAY_CHECK_FILE_COMPLETELY_WRITTEN);
|
||||
};
|
||||
|
||||
const printProgressListener = {
|
||||
onStateChange(webProgress, request, flags, status) {
|
||||
if (
|
||||
flags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
flags & Ci.nsIWebProgressListener.STATE_IS_NETWORK
|
||||
) {
|
||||
waitForFileWritten();
|
||||
}
|
||||
},
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener]),
|
||||
};
|
||||
let linkedBrowser = this.curBrowser.tab.linkedBrowser;
|
||||
linkedBrowser.print(
|
||||
linkedBrowser.outerWindowID,
|
||||
printSettings,
|
||||
printProgressListener
|
||||
);
|
||||
});
|
||||
|
||||
const fp = await OS.File.open(filePath);
|
||||
|
||||
// return all data as a base64 encoded string
|
||||
let bytes;
|
||||
try {
|
||||
bytes = await fp.read();
|
||||
} finally {
|
||||
fp.close();
|
||||
await OS.File.remove(filePath);
|
||||
}
|
||||
|
||||
// Each UCS2 character has an upper byte of 0 and a lower byte matching
|
||||
// the binary data
|
||||
return {
|
||||
value: btoa(String.fromCharCode.apply(null, bytes)),
|
||||
};
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.commands = {
|
||||
// Marionette service
|
||||
"Marionette:AcceptConnections": GeckoDriver.prototype.acceptConnections,
|
||||
|
@ -3756,6 +3941,7 @@ GeckoDriver.prototype.commands = {
|
|||
"WebDriver:NewSession": GeckoDriver.prototype.newSession,
|
||||
"WebDriver:NewWindow": GeckoDriver.prototype.newWindow,
|
||||
"WebDriver:PerformActions": GeckoDriver.prototype.performActions,
|
||||
"WebDriver:Print": GeckoDriver.prototype.print,
|
||||
"WebDriver:Refresh": GeckoDriver.prototype.refresh,
|
||||
"WebDriver:ReleaseActions": GeckoDriver.prototype.releaseActions,
|
||||
"WebDriver:SendAlertText": GeckoDriver.prototype.sendKeysToDialog,
|
||||
|
|
Загрузка…
Ссылка в новой задаче