refactor: printToPDF should be headless (#33654)
This commit is contained in:
parent
0d69067dee
commit
93b39b92b5
17 changed files with 648 additions and 414 deletions
2
BUILD.gn
2
BUILD.gn
|
@ -667,8 +667,6 @@ source_set("electron_lib") {
|
|||
|
||||
if (enable_basic_printing) {
|
||||
sources += [
|
||||
"shell/browser/printing/print_preview_message_handler.cc",
|
||||
"shell/browser/printing/print_preview_message_handler.h",
|
||||
"shell/browser/printing/print_view_manager_electron.cc",
|
||||
"shell/browser/printing/print_view_manager_electron.h",
|
||||
"shell/renderer/printing/print_render_frame_helper_delegate.cc",
|
||||
|
|
|
@ -216,6 +216,8 @@ static_library("chrome") {
|
|||
"//chrome/browser/printing/printer_query.h",
|
||||
"//chrome/browser/printing/printing_service.cc",
|
||||
"//chrome/browser/printing/printing_service.h",
|
||||
"//components/printing/browser/print_to_pdf/pdf_print_utils.cc",
|
||||
"//components/printing/browser/print_to_pdf/pdf_print_utils.h",
|
||||
]
|
||||
|
||||
if (enable_oop_printing) {
|
||||
|
|
|
@ -1428,7 +1428,7 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
|
|||
* `header` string (optional) - string to be printed as page header.
|
||||
* `footer` string (optional) - string to be printed as page footer.
|
||||
* `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A3`,
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`.
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`.
|
||||
* `callback` Function (optional)
|
||||
* `success` boolean - Indicates success of the print call.
|
||||
* `failureReason` string - Error description called back if the print fails.
|
||||
|
@ -1459,43 +1459,28 @@ win.webContents.print(options, (success, errorType) => {
|
|||
#### `contents.printToPDF(options)`
|
||||
|
||||
* `options` Object
|
||||
* `headerFooter` Record<string, string> (optional) - the header and footer for the PDF.
|
||||
* `title` string - The title for the PDF header.
|
||||
* `url` string - the url for the PDF footer.
|
||||
* `landscape` boolean (optional) - `true` for landscape, `false` for portrait.
|
||||
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
|
||||
default margin, 1 for no margin, and 2 for minimum margin.
|
||||
* `scaleFactor` number (optional) - The scale factor of the web page. Can range from 0 to 100.
|
||||
* `pageRanges` Record<string, number> (optional) - The page range to print.
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width` in microns.
|
||||
* `printBackground` boolean (optional) - Whether to print CSS backgrounds.
|
||||
* `printSelectionOnly` boolean (optional) - Whether to print selection only.
|
||||
* `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false.
|
||||
* `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false.
|
||||
* `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false.
|
||||
* `scale` number(optional) - Scale of the webpage rendering. Defaults to 1.
|
||||
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`,
|
||||
`A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`.
|
||||
* `margins` Object (optional)
|
||||
* `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
|
||||
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
|
||||
Returns `Promise<Buffer>` - Resolves with the generated PDF data.
|
||||
|
||||
Prints window's web page as PDF with Chromium's preview printing custom
|
||||
settings.
|
||||
Prints the window's web page as PDF.
|
||||
|
||||
The `landscape` will be ignored if `@page` CSS at-rule is used in the web page.
|
||||
|
||||
By default, an empty `options` will be regarded as:
|
||||
|
||||
```javascript
|
||||
{
|
||||
marginsType: 0,
|
||||
printBackground: false,
|
||||
printSelectionOnly: false,
|
||||
landscape: false,
|
||||
pageSize: 'A4',
|
||||
scaleFactor: 100
|
||||
}
|
||||
```
|
||||
|
||||
Use `page-break-before: always;` CSS style to force to print to a new page.
|
||||
|
||||
An example of `webContents.printToPDF`:
|
||||
|
||||
```javascript
|
||||
|
@ -1504,7 +1489,7 @@ const fs = require('fs')
|
|||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
const win = new BrowserWindow({ width: 800, height: 600 })
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
|
@ -1521,6 +1506,8 @@ win.webContents.on('did-finish-load', () => {
|
|||
})
|
||||
```
|
||||
|
||||
See [Page.printToPdf](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) for more information.
|
||||
|
||||
#### `contents.addWorkSpace(path)`
|
||||
|
||||
* `path` string
|
||||
|
|
|
@ -565,21 +565,21 @@ Prints `webview`'s web page. Same as `webContents.print([options])`.
|
|||
### `<webview>.printToPDF(options)`
|
||||
|
||||
* `options` Object
|
||||
* `headerFooter` Record<string, string> (optional) - the header and footer for the PDF.
|
||||
* `title` string - The title for the PDF header.
|
||||
* `url` string - the url for the PDF footer.
|
||||
* `landscape` boolean (optional) - `true` for landscape, `false` for portrait.
|
||||
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
|
||||
default margin, 1 for no margin, and 2 for minimum margin.
|
||||
and `width` in microns.
|
||||
* `scaleFactor` number (optional) - The scale factor of the web page. Can range from 0 to 100.
|
||||
* `pageRanges` Record<string, number> (optional) - The page range to print. On macOS, only the first range is honored.
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A3`,
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height`
|
||||
* `printBackground` boolean (optional) - Whether to print CSS backgrounds.
|
||||
* `printSelectionOnly` boolean (optional) - Whether to print selection only.
|
||||
* `landscape` boolean (optional) - Paper orientation.`true` for landscape, `false` for portrait. Defaults to false.
|
||||
* `displayHeaderFooter` boolean (optional) - Whether to display header and footer. Defaults to false.
|
||||
* `printBackground` boolean (optional) - Whether to print background graphics. Defaults to false.
|
||||
* `scale` number(optional) - Scale of the webpage rendering. Defaults to 1.
|
||||
* `pageSize` string | Size (optional) - Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`,
|
||||
`A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing `height` and `width` in inches. Defaults to `Letter`.
|
||||
* `margins` Object (optional)
|
||||
* `top` number (optional) - Top margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `bottom` number (optional) - Bottom margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `left` number (optional) - Left margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `right` number (optional) - Right margin in inches. Defaults to 1cm (~0.4 inches).
|
||||
* `pageRanges` string (optional) - Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages.
|
||||
* `headerTemplate` string (optional) - HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: `date` (formatted print date), `title` (document title), `url` (document location), `pageNumber` (current page number) and `totalPages` (total pages in the document). For example, `<span class=title></span>` would generate span containing the title.
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
|
||||
Returns `Promise<Uint8Array>` - Resolves with the generated PDF data.
|
||||
|
||||
|
|
|
@ -14,6 +14,61 @@ This document uses the following convention to categorize breaking changes:
|
|||
|
||||
## Planned Breaking API Changes (20.0)
|
||||
|
||||
### API Changed: `webContents.printToPDF()`
|
||||
|
||||
`webContents.printToPDF()` has been modified to conform to [`Page.printToPDF`](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF) in the Chrome DevTools Protocol. This has been changes in order to
|
||||
address changes upstream that made our previous implementation untenable and rife with bugs.
|
||||
|
||||
**Arguments Changed**
|
||||
|
||||
* `pageRanges`
|
||||
|
||||
**Arguments Removed**
|
||||
|
||||
* `printSelectionOnly`
|
||||
* `marginsType`
|
||||
* `headerFooter`
|
||||
* `scaleFactor`
|
||||
|
||||
**Arguments Added**
|
||||
|
||||
* `headerTemplate`
|
||||
* `footerTemplate`
|
||||
* `displayHeaderFooter`
|
||||
* `margins`
|
||||
* `scale`
|
||||
* `preferCSSPageSize`
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const { webContents } = require('electron')
|
||||
|
||||
webContents.printToPDF({
|
||||
landscape: true,
|
||||
displayHeaderFooter: true,
|
||||
printBackground: true,
|
||||
scale: 2,
|
||||
pageSize: 'Ledger',
|
||||
margins: {
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
left: 2,
|
||||
right: 2
|
||||
},
|
||||
pageRanges: '1-5, 8, 11-13',
|
||||
headerTemplate: '<h1>Title</h1>',
|
||||
footerTemplate: '<div><span class="pageNumber"></span></div>',
|
||||
preferCSSPageSize: true
|
||||
}).then(data => {
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log(`Failed to write PDF to ${pdfPath}: `, error)
|
||||
})
|
||||
```
|
||||
|
||||
### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default
|
||||
|
||||
Previously, renderers that specified a preload script defaulted to being
|
||||
|
|
|
@ -63,6 +63,20 @@ const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
|
|||
}
|
||||
} as const;
|
||||
|
||||
const paperFormats: Record<string, ElectronInternal.PageSize> = {
|
||||
letter: { width: 8.5, height: 11 },
|
||||
legal: { width: 8.5, height: 14 },
|
||||
tabloid: { width: 11, height: 17 },
|
||||
ledger: { width: 17, height: 11 },
|
||||
a0: { width: 33.1, height: 46.8 },
|
||||
a1: { width: 23.4, height: 33.1 },
|
||||
a2: { width: 16.54, height: 23.4 },
|
||||
a3: { width: 11.7, height: 16.54 },
|
||||
a4: { width: 8.27, height: 11.7 },
|
||||
a5: { width: 5.83, height: 8.27 },
|
||||
a6: { width: 4.13, height: 5.83 }
|
||||
} as const;
|
||||
|
||||
// The minimum micron size Chromium accepts is that where:
|
||||
// Per printing/units.h:
|
||||
// * kMicronsPerInch - Length of an inch in 0.001mm unit.
|
||||
|
@ -76,42 +90,6 @@ const isValidCustomPageSize = (width: number, height: number) => {
|
|||
return [width, height].every(x => x > 352);
|
||||
};
|
||||
|
||||
// Default printing setting
|
||||
const defaultPrintingSetting = {
|
||||
// Customizable.
|
||||
pageRange: [] as {from: number, to: number}[],
|
||||
mediaSize: {} as ElectronInternal.MediaSize,
|
||||
landscape: false,
|
||||
headerFooterEnabled: false,
|
||||
marginsType: 0,
|
||||
scaleFactor: 100,
|
||||
shouldPrintBackgrounds: false,
|
||||
shouldPrintSelectionOnly: false,
|
||||
// Non-customizable.
|
||||
printWithCloudPrint: false,
|
||||
printWithPrivet: false,
|
||||
printWithExtension: false,
|
||||
pagesPerSheet: 1,
|
||||
isFirstRequest: false,
|
||||
previewUIID: 0,
|
||||
// True, if the document source is modifiable. e.g. HTML and not PDF.
|
||||
previewModifiable: true,
|
||||
printToPDF: true,
|
||||
deviceName: 'Save as PDF',
|
||||
generateDraftData: true,
|
||||
dpiHorizontal: 72,
|
||||
dpiVertical: 72,
|
||||
rasterizePDF: false,
|
||||
duplex: 0,
|
||||
copies: 1,
|
||||
// 2 = color - see ColorModel in //printing/print_job_constants.h
|
||||
color: 2,
|
||||
collate: true,
|
||||
printerType: 2,
|
||||
title: undefined as string | undefined,
|
||||
url: undefined as string | undefined
|
||||
} as const;
|
||||
|
||||
// JavaScript implementations of WebContents.
|
||||
const binding = process._linkedBinding('electron_browser_web_contents');
|
||||
const printing = process._linkedBinding('electron_browser_printing');
|
||||
|
@ -193,136 +171,136 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId
|
|||
let pendingPromise: Promise<any> | undefined;
|
||||
WebContents.prototype.printToPDF = async function (options) {
|
||||
const printSettings: Record<string, any> = {
|
||||
...defaultPrintingSetting,
|
||||
requestID: getNextId()
|
||||
requestID: getNextId(),
|
||||
landscape: false,
|
||||
displayHeaderFooter: false,
|
||||
headerTemplate: '',
|
||||
footerTemplate: '',
|
||||
printBackground: false,
|
||||
scale: 1,
|
||||
paperWidth: 8.5,
|
||||
paperHeight: 11,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
pageRanges: '',
|
||||
preferCSSPageSize: false
|
||||
};
|
||||
|
||||
if (options.landscape !== undefined) {
|
||||
if (typeof options.landscape !== 'boolean') {
|
||||
const error = new Error('landscape must be a Boolean');
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(new Error('landscape must be a Boolean'));
|
||||
}
|
||||
printSettings.landscape = options.landscape;
|
||||
}
|
||||
|
||||
if (options.scaleFactor !== undefined) {
|
||||
if (typeof options.scaleFactor !== 'number') {
|
||||
const error = new Error('scaleFactor must be a Number');
|
||||
return Promise.reject(error);
|
||||
if (options.displayHeaderFooter !== undefined) {
|
||||
if (typeof options.displayHeaderFooter !== 'boolean') {
|
||||
return Promise.reject(new Error('displayHeaderFooter must be a Boolean'));
|
||||
}
|
||||
printSettings.scaleFactor = options.scaleFactor;
|
||||
}
|
||||
|
||||
if (options.marginsType !== undefined) {
|
||||
if (typeof options.marginsType !== 'number') {
|
||||
const error = new Error('marginsType must be a Number');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
printSettings.marginsType = options.marginsType;
|
||||
}
|
||||
|
||||
if (options.printSelectionOnly !== undefined) {
|
||||
if (typeof options.printSelectionOnly !== 'boolean') {
|
||||
const error = new Error('printSelectionOnly must be a Boolean');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
printSettings.shouldPrintSelectionOnly = options.printSelectionOnly;
|
||||
printSettings.displayHeaderFooter = options.displayHeaderFooter;
|
||||
}
|
||||
|
||||
if (options.printBackground !== undefined) {
|
||||
if (typeof options.printBackground !== 'boolean') {
|
||||
const error = new Error('printBackground must be a Boolean');
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(new Error('printBackground must be a Boolean'));
|
||||
}
|
||||
printSettings.shouldPrintBackgrounds = options.printBackground;
|
||||
}
|
||||
|
||||
if (options.pageRanges !== undefined) {
|
||||
const pageRanges = options.pageRanges;
|
||||
if (!Object.prototype.hasOwnProperty.call(pageRanges, 'from') || !Object.prototype.hasOwnProperty.call(pageRanges, 'to')) {
|
||||
const error = new Error('pageRanges must be an Object with \'from\' and \'to\' properties');
|
||||
return Promise.reject(error);
|
||||
if (options.scale !== undefined) {
|
||||
if (typeof options.scale !== 'number') {
|
||||
return Promise.reject(new Error('scale must be a Number'));
|
||||
}
|
||||
|
||||
if (typeof pageRanges.from !== 'number') {
|
||||
const error = new Error('pageRanges.from must be a Number');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (typeof pageRanges.to !== 'number') {
|
||||
const error = new Error('pageRanges.to must be a Number');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
// Chromium uses 1-based page ranges, so increment each by 1.
|
||||
printSettings.pageRange = [{
|
||||
from: pageRanges.from + 1,
|
||||
to: pageRanges.to + 1
|
||||
}];
|
||||
printSettings.scaleFactor = options.scale;
|
||||
}
|
||||
|
||||
if (options.headerFooter !== undefined) {
|
||||
const headerFooter = options.headerFooter;
|
||||
printSettings.headerFooterEnabled = true;
|
||||
if (typeof headerFooter === 'object') {
|
||||
if (!headerFooter.url || !headerFooter.title) {
|
||||
const error = new Error('url and title properties are required for headerFooter');
|
||||
return Promise.reject(error);
|
||||
const { pageSize } = options;
|
||||
if (pageSize !== undefined) {
|
||||
if (typeof pageSize === 'string') {
|
||||
const format = paperFormats[pageSize.toLowerCase()];
|
||||
if (!format) {
|
||||
return Promise.reject(new Error(`Invalid pageSize ${pageSize}`));
|
||||
}
|
||||
if (typeof headerFooter.title !== 'string') {
|
||||
const error = new Error('headerFooter.title must be a String');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
printSettings.title = headerFooter.title;
|
||||
|
||||
if (typeof headerFooter.url !== 'string') {
|
||||
const error = new Error('headerFooter.url must be a String');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
printSettings.url = headerFooter.url;
|
||||
} else {
|
||||
const error = new Error('headerFooter must be an Object');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally set size for PDF.
|
||||
if (options.pageSize !== undefined) {
|
||||
const pageSize = options.pageSize;
|
||||
if (typeof pageSize === 'object') {
|
||||
printSettings.paperWidth = format.width;
|
||||
printSettings.paperHeight = format.height;
|
||||
} else if (typeof options.pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
const error = new Error('height and width properties are required for pageSize');
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(new Error('height and width properties are required for pageSize'));
|
||||
}
|
||||
|
||||
// Dimensions in Microns - 1 meter = 10^6 microns
|
||||
const height = Math.ceil(pageSize.height);
|
||||
const width = Math.ceil(pageSize.width);
|
||||
if (!isValidCustomPageSize(width, height)) {
|
||||
const error = new Error('height and width properties must be minimum 352 microns.');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
printSettings.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
width_microns: width
|
||||
};
|
||||
} else if (Object.prototype.hasOwnProperty.call(PDFPageSizes, pageSize)) {
|
||||
printSettings.mediaSize = PDFPageSizes[pageSize];
|
||||
printSettings.paperWidth = pageSize.width;
|
||||
printSettings.paperHeight = pageSize.height;
|
||||
} else {
|
||||
const error = new Error(`Unsupported pageSize: ${pageSize}`);
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(new Error('pageSize must be a String or Object'));
|
||||
}
|
||||
} else {
|
||||
printSettings.mediaSize = PDFPageSizes.A4;
|
||||
}
|
||||
|
||||
// Chromium expects this in a 0-100 range number, not as float
|
||||
printSettings.scaleFactor = Math.ceil(printSettings.scaleFactor) % 100;
|
||||
// PrinterType enum from //printing/print_job_constants.h
|
||||
printSettings.printerType = 2;
|
||||
const { margins } = options;
|
||||
if (margins !== undefined) {
|
||||
if (typeof margins !== 'object') {
|
||||
return Promise.reject(new Error('margins must be an Object'));
|
||||
}
|
||||
|
||||
if (margins.top !== undefined) {
|
||||
if (typeof margins.top !== 'number') {
|
||||
return Promise.reject(new Error('margins.top must be a Number'));
|
||||
}
|
||||
printSettings.marginTop = margins.top;
|
||||
}
|
||||
|
||||
if (margins.bottom !== undefined) {
|
||||
if (typeof margins.bottom !== 'number') {
|
||||
return Promise.reject(new Error('margins.bottom must be a Number'));
|
||||
}
|
||||
printSettings.marginBottom = margins.bottom;
|
||||
}
|
||||
|
||||
if (margins.left !== undefined) {
|
||||
if (typeof margins.left !== 'number') {
|
||||
return Promise.reject(new Error('margins.left must be a Number'));
|
||||
}
|
||||
printSettings.marginLeft = margins.left;
|
||||
}
|
||||
|
||||
if (margins.right !== undefined) {
|
||||
if (typeof margins.right !== 'number') {
|
||||
return Promise.reject(new Error('margins.right must be a Number'));
|
||||
}
|
||||
printSettings.marginRight = margins.right;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.pageRanges !== undefined) {
|
||||
if (typeof options.pageRanges !== 'string') {
|
||||
return Promise.reject(new Error('printBackground must be a String'));
|
||||
}
|
||||
printSettings.pageRanges = options.pageRanges;
|
||||
}
|
||||
|
||||
if (options.headerTemplate !== undefined) {
|
||||
if (typeof options.headerTemplate !== 'string') {
|
||||
return Promise.reject(new Error('headerTemplate must be a String'));
|
||||
}
|
||||
printSettings.headerTemplate = options.headerTemplate;
|
||||
}
|
||||
|
||||
if (options.footerTemplate !== undefined) {
|
||||
if (typeof options.footerTemplate !== 'string') {
|
||||
return Promise.reject(new Error('footerTemplate must be a String'));
|
||||
}
|
||||
printSettings.footerTemplate = options.footerTemplate;
|
||||
}
|
||||
|
||||
if (options.preferCSSPageSize !== undefined) {
|
||||
if (typeof options.preferCSSPageSize !== 'boolean') {
|
||||
return Promise.reject(new Error('footerTemplate must be a String'));
|
||||
}
|
||||
printSettings.preferCSSPageSize = options.preferCSSPageSize;
|
||||
}
|
||||
|
||||
if (this._printToPDF) {
|
||||
if (pendingPromise) {
|
||||
pendingPromise = pendingPromise.then(() => this._printToPDF(printSettings));
|
||||
|
|
|
@ -113,31 +113,19 @@ index dd27bbf387718d6abda5080e7d2c609cd0eaff17..8837cf2aeaa2f87d51be8d00aa356c8a
|
|||
|
||||
void PrintJobWorkerOop::UnregisterServiceManagerClient() {
|
||||
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
|
||||
index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc9c122ae3 100644
|
||||
index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..203ca9b0c4bf048016023fc3d260df6588392418 100644
|
||||
--- a/chrome/browser/printing/print_view_manager_base.cc
|
||||
+++ b/chrome/browser/printing/print_view_manager_base.cc
|
||||
@@ -30,10 +30,10 @@
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "chrome/browser/printing/print_view_manager_common.h"
|
||||
#include "chrome/browser/printing/printer_query.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
-#include "chrome/browser/ui/simple_message_box.h"
|
||||
-#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
+#if 0
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
+#endif
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/printing/browser/print_composite_client.h"
|
||||
#include "components/printing/browser/print_manager_utils.h"
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
+#include "chrome/grit/generated_resources.h"
|
||||
#include "mojo/public/cpp/system/buffer.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "printing/metafile_skia.h"
|
||||
@@ -87,6 +88,8 @@ using PrintSettingsCallback =
|
||||
@@ -87,6 +85,8 @@ using PrintSettingsCallback =
|
||||
base::OnceCallback<void(std::unique_ptr<PrinterQuery>)>;
|
||||
|
||||
void ShowWarningMessageBox(const std::u16string& message) {
|
||||
|
@ -146,7 +134,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
// Runs always on the UI thread.
|
||||
static bool is_dialog_shown = false;
|
||||
if (is_dialog_shown)
|
||||
@@ -95,6 +98,7 @@ void ShowWarningMessageBox(const std::u16string& message) {
|
||||
@@ -95,6 +95,7 @@ void ShowWarningMessageBox(const std::u16string& message) {
|
||||
base::AutoReset<bool> auto_reset(&is_dialog_shown, true);
|
||||
|
||||
chrome::ShowWarningMessageBox(nullptr, std::u16string(), message);
|
||||
|
@ -154,7 +142,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
@@ -192,7 +196,9 @@ void UpdatePrintSettingsReplyOnIO(
|
||||
@@ -192,7 +193,9 @@ void UpdatePrintSettingsReplyOnIO(
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
DCHECK(printer_query);
|
||||
mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr();
|
||||
|
@ -165,7 +153,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
RenderParamsFromPrintSettings(printer_query->settings(),
|
||||
params->params.get());
|
||||
params->params->document_cookie = printer_query->cookie();
|
||||
@@ -245,6 +251,7 @@ void ScriptedPrintReplyOnIO(
|
||||
@@ -245,6 +248,7 @@ void ScriptedPrintReplyOnIO(
|
||||
mojom::PrintManagerHost::ScriptedPrintCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr();
|
||||
|
@ -173,7 +161,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
if (printer_query->last_status() == mojom::ResultCode::kSuccess &&
|
||||
printer_query->settings().dpi()) {
|
||||
RenderParamsFromPrintSettings(printer_query->settings(),
|
||||
@@ -254,8 +261,9 @@ void ScriptedPrintReplyOnIO(
|
||||
@@ -254,8 +258,9 @@ void ScriptedPrintReplyOnIO(
|
||||
}
|
||||
bool has_valid_cookie = params->params->document_cookie;
|
||||
bool has_dpi = !params->params->dpi.IsEmpty();
|
||||
|
@ -184,7 +172,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
|
||||
if (has_dpi && has_valid_cookie) {
|
||||
queue->QueuePrinterQuery(std::move(printer_query));
|
||||
@@ -293,12 +301,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
|
||||
@@ -293,12 +298,14 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
|
||||
: PrintManager(web_contents),
|
||||
queue_(g_browser_process->print_job_manager()->queue()) {
|
||||
DCHECK(queue_);
|
||||
|
@ -199,7 +187,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
}
|
||||
|
||||
PrintViewManagerBase::~PrintViewManagerBase() {
|
||||
@@ -306,7 +316,10 @@ PrintViewManagerBase::~PrintViewManagerBase() {
|
||||
@@ -306,7 +313,10 @@ PrintViewManagerBase::~PrintViewManagerBase() {
|
||||
DisconnectFromCurrentPrintJob();
|
||||
}
|
||||
|
||||
|
@ -211,7 +199,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
// Remember the ID for `rfh`, to enable checking that the `RenderFrameHost`
|
||||
// is still valid after a possible inner message loop runs in
|
||||
// `DisconnectFromCurrentPrintJob()`.
|
||||
@@ -332,6 +345,9 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
|
||||
@@ -332,6 +342,9 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
|
||||
#endif
|
||||
|
||||
SetPrintingRFH(rfh);
|
||||
|
@ -221,7 +209,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
|
||||
#if BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
|
||||
enterprise_connectors::ContentAnalysisDelegate::Data scanning_data;
|
||||
@@ -500,7 +516,8 @@ void PrintViewManagerBase::GetDefaultPrintSettingsReply(
|
||||
@@ -500,7 +513,8 @@ void PrintViewManagerBase::GetDefaultPrintSettingsReply(
|
||||
void PrintViewManagerBase::ScriptedPrintReply(
|
||||
ScriptedPrintCallback callback,
|
||||
int process_id,
|
||||
|
@ -231,7 +219,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
#if BUILDFLAG(ENABLE_OOP_PRINTING)
|
||||
@@ -513,16 +530,19 @@ void PrintViewManagerBase::ScriptedPrintReply(
|
||||
@@ -513,16 +527,19 @@ void PrintViewManagerBase::ScriptedPrintReply(
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -255,7 +243,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
}
|
||||
|
||||
void PrintViewManagerBase::NavigationStopped() {
|
||||
@@ -638,11 +658,14 @@ void PrintViewManagerBase::DidPrintDocument(
|
||||
@@ -638,11 +655,14 @@ void PrintViewManagerBase::DidPrintDocument(
|
||||
void PrintViewManagerBase::GetDefaultPrintSettings(
|
||||
GetDefaultPrintSettingsCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
@ -270,7 +258,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
#if BUILDFLAG(ENABLE_OOP_PRINTING)
|
||||
if (printing::features::kEnableOopPrintDriversJobPrint.Get() &&
|
||||
!service_manager_client_id_.has_value()) {
|
||||
@@ -672,18 +695,20 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -672,18 +692,20 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
base::Value::Dict job_settings,
|
||||
UpdatePrintSettingsCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
@ -292,7 +280,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
content::BrowserContext* context =
|
||||
web_contents() ? web_contents()->GetBrowserContext() : nullptr;
|
||||
PrefService* prefs =
|
||||
@@ -693,6 +718,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -693,6 +715,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
if (value > 0)
|
||||
job_settings.Set(kSettingRasterizePdfDpi, value);
|
||||
}
|
||||
|
@ -300,7 +288,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
|
||||
auto callback_wrapper =
|
||||
base::BindOnce(&PrintViewManagerBase::UpdatePrintSettingsReply,
|
||||
@@ -718,14 +744,14 @@ void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params,
|
||||
@@ -718,14 +741,14 @@ void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params,
|
||||
// didn't happen for some reason.
|
||||
bad_message::ReceivedBadMessage(
|
||||
render_process_host, bad_message::PVMB_SCRIPTED_PRINT_FENCED_FRAME);
|
||||
|
@ -317,7 +305,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -763,7 +789,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
@@ -763,7 +786,6 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
PrintManager::PrintingFailed(cookie, reason);
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID) // Android does not implement this function.
|
||||
|
@ -325,7 +313,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
#endif
|
||||
|
||||
ReleasePrinterQuery();
|
||||
@@ -778,6 +803,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) {
|
||||
@@ -778,6 +800,11 @@ void PrintViewManagerBase::RemoveObserver(Observer& observer) {
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::ShowInvalidPrinterSettingsError() {
|
||||
|
@ -337,7 +325,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ShowWarningMessageBox,
|
||||
l10n_util::GetStringUTF16(
|
||||
@@ -788,10 +818,12 @@ void PrintViewManagerBase::RenderFrameHostStateChanged(
|
||||
@@ -788,10 +815,12 @@ void PrintViewManagerBase::RenderFrameHostStateChanged(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
content::RenderFrameHost::LifecycleState /*old_state*/,
|
||||
content::RenderFrameHost::LifecycleState new_state) {
|
||||
|
@ -350,7 +338,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
}
|
||||
|
||||
void PrintViewManagerBase::DidStartLoading() {
|
||||
@@ -851,6 +883,11 @@ void PrintViewManagerBase::OnJobDone() {
|
||||
@@ -851,6 +880,11 @@ void PrintViewManagerBase::OnJobDone() {
|
||||
ReleasePrintJob();
|
||||
}
|
||||
|
||||
|
@ -362,7 +350,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
void PrintViewManagerBase::OnFailed() {
|
||||
TerminatePrintJob(true);
|
||||
}
|
||||
@@ -908,7 +945,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
|
||||
@@ -908,7 +942,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
|
||||
|
||||
// Disconnect the current |print_job_|.
|
||||
auto weak_this = weak_ptr_factory_.GetWeakPtr();
|
||||
|
@ -374,7 +362,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
if (!weak_this)
|
||||
return false;
|
||||
|
||||
@@ -987,6 +1027,13 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
@@ -987,6 +1024,13 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
UnregisterSystemPrintClient();
|
||||
#endif
|
||||
|
||||
|
@ -388,7 +376,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
if (!print_job_)
|
||||
return;
|
||||
|
||||
@@ -1036,7 +1083,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
|
||||
@@ -1036,7 +1080,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
|
||||
}
|
||||
|
||||
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
|
||||
|
@ -397,7 +385,7 @@ index 3701853ada7f0ffe3cc8a798496f9f48541b4f47..973666a1315c8cbba0a2cefbe9195fdc
|
|||
return true;
|
||||
|
||||
if (!cookie) {
|
||||
@@ -1144,7 +1191,7 @@ void PrintViewManagerBase::SendPrintingEnabled(bool enabled,
|
||||
@@ -1144,7 +1188,7 @@ void PrintViewManagerBase::SendPrintingEnabled(bool enabled,
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::CompletePrintNow(content::RenderFrameHost* rfh) {
|
||||
|
@ -491,29 +479,6 @@ index 5f4d6e314b21351e3e5912e3a43ef87774343085..8627c8305686654dca7cd9c26433592e
|
|||
void PrintWithParams(mojom::PrintPagesParamsPtr params) override;
|
||||
void PrintForSystemDialog() override;
|
||||
void SetPrintPreviewUI(
|
||||
diff --git a/components/printing/browser/print_to_pdf/pdf_print_manager.cc b/components/printing/browser/print_to_pdf/pdf_print_manager.cc
|
||||
index 82591f8c2abbc1a180ef62f7264a68ca279e9b9c..ad27a15ba3028af1046482192dec789df5dda7b2 100644
|
||||
--- a/components/printing/browser/print_to_pdf/pdf_print_manager.cc
|
||||
+++ b/components/printing/browser/print_to_pdf/pdf_print_manager.cc
|
||||
@@ -132,7 +132,8 @@ void PdfPrintManager::PrintToPdf(
|
||||
set_cookie(print_pages_params->params->document_cookie);
|
||||
callback_ = std::move(callback);
|
||||
|
||||
- GetPrintRenderFrame(rfh)->PrintWithParams(std::move(print_pages_params));
|
||||
+ // TODO(electron-maintainers): do something with job_settings here?
|
||||
+ GetPrintRenderFrame(rfh)->PrintRequestedPages(true/*silent*/, base::Value{}/*job_settings*/);
|
||||
}
|
||||
|
||||
void PdfPrintManager::GetDefaultPrintSettings(
|
||||
@@ -147,7 +148,7 @@ void PdfPrintManager::ScriptedPrint(
|
||||
auto default_param = printing::mojom::PrintPagesParams::New();
|
||||
default_param->params = printing::mojom::PrintParams::New();
|
||||
DLOG(ERROR) << "Scripted print is not supported";
|
||||
- std::move(callback).Run(std::move(default_param));
|
||||
+ std::move(callback).Run(std::move(default_param), true/*canceled*/);
|
||||
}
|
||||
|
||||
void PdfPrintManager::ShowInvalidPrinterSettingsError() {
|
||||
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom
|
||||
index 8e5c441b3d0a2d35fc5c6f9d43b4a4ca167e09ca..2cfcd810c9507c434e673064b63e8fbc95172537 100644
|
||||
--- a/components/printing/common/print.mojom
|
||||
|
@ -537,7 +502,7 @@ index 8e5c441b3d0a2d35fc5c6f9d43b4a4ca167e09ca..2cfcd810c9507c434e673064b63e8fbc
|
|||
// Tells the browser that there are invalid printer settings.
|
||||
ShowInvalidPrinterSettingsError();
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index db8913ae41d46d14fd15c6127e126e4b129dc4b8..ddbc3b0d5a00af9de84e1b0aadc44adb6ff84495 100644
|
||||
index db8913ae41d46d14fd15c6127e126e4b129dc4b8..eaddc1bbc59bad9cc885fb8532d4f8c1df2f1a86 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -42,6 +42,7 @@
|
||||
|
@ -716,26 +681,6 @@ index db8913ae41d46d14fd15c6127e126e4b129dc4b8..ddbc3b0d5a00af9de84e1b0aadc44adb
|
|||
*output = std::move(input);
|
||||
std::move(quit_closure).Run();
|
||||
},
|
||||
@@ -2725,18 +2756,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type,
|
||||
}
|
||||
|
||||
bool PrintRenderFrameHelper::CheckForCancel() {
|
||||
- const mojom::PrintParams& print_params = *print_pages_params_->params;
|
||||
- bool cancel = false;
|
||||
-
|
||||
- if (!GetPrintManagerHost()->CheckForCancel(print_params.preview_ui_id,
|
||||
- print_params.preview_request_id,
|
||||
- &cancel)) {
|
||||
- cancel = true;
|
||||
- }
|
||||
-
|
||||
- if (cancel)
|
||||
- notify_browser_of_print_failure_ = false;
|
||||
- return cancel;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
bool PrintRenderFrameHelper::PreviewPageRendered(
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
|
||||
index 220b28a7e63625fe8b76290f0d2f40dd32cae255..cff9e35fab9df680c3c39467c50ddb033c2e6cba 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.h
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/printing/print_view_manager_base.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
|
||||
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
|
@ -165,9 +166,10 @@
|
|||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
#include "components/printing/browser/print_manager_utils.h"
|
||||
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
|
||||
#include "printing/backend/print_backend.h" // nogncheck
|
||||
#include "printing/mojom/print.mojom.h" // nogncheck
|
||||
#include "shell/browser/printing/print_preview_message_handler.h"
|
||||
#include "printing/page_range.h"
|
||||
#include "shell/browser/printing/print_view_manager_electron.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
|
@ -919,10 +921,7 @@ void WebContents::InitWithWebContents(
|
|||
web_contents->SetDelegate(this);
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
PrintPreviewMessageHandler::CreateForWebContents(web_contents.get());
|
||||
PrintViewManagerElectron::CreateForWebContents(web_contents.get());
|
||||
printing::CreateCompositeClientIfNeeded(web_contents.get(),
|
||||
browser_context->GetUserAgent());
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
|
@ -2807,14 +2806,87 @@ void WebContents::Print(gin::Arguments* args) {
|
|||
std::move(callback), device_name, silent));
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> WebContents::PrintToPDF(base::DictionaryValue settings) {
|
||||
// Partially duplicated and modified from
|
||||
// headless/lib/browser/protocol/page_handler.cc;l=41
|
||||
v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
PrintPreviewMessageHandler::FromWebContents(web_contents())
|
||||
->PrintToPDF(std::move(settings), std::move(promise));
|
||||
|
||||
// This allows us to track headless printing calls.
|
||||
auto unique_id = settings.GetDict().FindInt(printing::kPreviewRequestID);
|
||||
auto landscape = settings.GetDict().FindBool("landscape");
|
||||
auto display_header_footer =
|
||||
settings.GetDict().FindBool("displayHeaderFooter");
|
||||
auto print_background = settings.GetDict().FindBool("shouldPrintBackgrounds");
|
||||
auto scale = settings.GetDict().FindDouble("scale");
|
||||
auto paper_width = settings.GetDict().FindInt("paperWidth");
|
||||
auto paper_height = settings.GetDict().FindInt("paperHeight");
|
||||
auto margin_top = settings.GetDict().FindIntByDottedPath("margins.top");
|
||||
auto margin_bottom = settings.GetDict().FindIntByDottedPath("margins.bottom");
|
||||
auto margin_left = settings.GetDict().FindIntByDottedPath("margins.left");
|
||||
auto margin_right = settings.GetDict().FindIntByDottedPath("margins.right");
|
||||
auto page_ranges = *settings.GetDict().FindString("pageRanges");
|
||||
auto header_template = *settings.GetDict().FindString("headerTemplate");
|
||||
auto footer_template = *settings.GetDict().FindString("footerTemplate");
|
||||
auto prefer_css_page_size = settings.GetDict().FindBool("preferCSSPageSize");
|
||||
|
||||
absl::variant<printing::mojom::PrintPagesParamsPtr, std::string>
|
||||
print_pages_params = print_to_pdf::GetPrintPagesParams(
|
||||
web_contents()->GetMainFrame()->GetLastCommittedURL(), landscape,
|
||||
display_header_footer, print_background, scale, paper_width,
|
||||
paper_height, margin_top, margin_bottom, margin_left, margin_right,
|
||||
absl::make_optional(header_template),
|
||||
absl::make_optional(footer_template), prefer_css_page_size);
|
||||
|
||||
if (absl::holds_alternative<std::string>(print_pages_params)) {
|
||||
auto error = absl::get<std::string>(print_pages_params);
|
||||
promise.RejectWithErrorMessage("Invalid print parameters: " + error);
|
||||
return handle;
|
||||
}
|
||||
|
||||
auto* manager = PrintViewManagerElectron::FromWebContents(web_contents());
|
||||
if (!manager) {
|
||||
promise.RejectWithErrorMessage("Failed to find print manager");
|
||||
return handle;
|
||||
}
|
||||
|
||||
auto params = std::move(
|
||||
absl::get<printing::mojom::PrintPagesParamsPtr>(print_pages_params));
|
||||
params->params->document_cookie = unique_id.value_or(0);
|
||||
|
||||
manager->PrintToPdf(web_contents()->GetMainFrame(), page_ranges,
|
||||
std::move(params),
|
||||
base::BindOnce(&WebContents::OnPDFCreated, GetWeakPtr(),
|
||||
std::move(promise)));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void WebContents::OnPDFCreated(
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
PrintViewManagerElectron::PrintResult print_result,
|
||||
scoped_refptr<base::RefCountedMemory> data) {
|
||||
if (print_result != PrintViewManagerElectron::PrintResult::PRINT_SUCCESS) {
|
||||
promise.RejectWithErrorMessage(
|
||||
"Failed to generate PDF: " +
|
||||
PrintViewManagerElectron::PrintResultToString(print_result));
|
||||
return;
|
||||
}
|
||||
|
||||
v8::Isolate* isolate = promise.isolate();
|
||||
gin_helper::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(
|
||||
v8::Local<v8::Context>::New(isolate, promise.GetContext()));
|
||||
|
||||
v8::Local<v8::Value> buffer =
|
||||
node::Buffer::Copy(isolate, reinterpret_cast<const char*>(data->front()),
|
||||
data->size())
|
||||
.ToLocalChecked();
|
||||
|
||||
promise.Resolve(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void WebContents::AddWorkSpace(gin::Arguments* args,
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "ui/gfx/image/image.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
#include "shell/browser/printing/print_preview_message_handler.h"
|
||||
#include "shell/browser/printing/print_view_manager_electron.h"
|
||||
#endif
|
||||
|
||||
|
@ -231,7 +230,10 @@ class WebContents : public ExclusiveAccessContext,
|
|||
std::pair<std::string, std::u16string> info);
|
||||
void Print(gin::Arguments* args);
|
||||
// Print current page as PDF.
|
||||
v8::Local<v8::Promise> PrintToPDF(base::DictionaryValue settings);
|
||||
v8::Local<v8::Promise> PrintToPDF(const base::Value& settings);
|
||||
void OnPDFCreated(gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
PrintViewManagerElectron::PrintResult print_result,
|
||||
scoped_refptr<base::RefCountedMemory> data);
|
||||
#endif
|
||||
|
||||
void SetNextChildWebPreferences(const gin_helper::Dictionary);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
#include "components/printing/browser/print_manager_utils.h"
|
||||
#include "shell/browser/printing/print_preview_message_handler.h"
|
||||
#include "shell/browser/printing/print_view_manager_electron.h"
|
||||
#endif
|
||||
|
||||
|
@ -86,7 +85,6 @@ MessagingDelegate* ElectronExtensionsAPIClient::GetMessagingDelegate() {
|
|||
void ElectronExtensionsAPIClient::AttachWebContentsHelpers(
|
||||
content::WebContents* web_contents) const {
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
electron::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
|
||||
electron::PrintViewManagerElectron::CreateForWebContents(web_contents);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "components/printing/common/print.mojom.h"
|
||||
#include "components/services/print_compositor/public/mojom/print_compositor.mojom.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "mojo/public/cpp/bindings/associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "printing/mojom/print.mojom.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace content {
|
||||
class RenderFrameHost;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Manages the print preview handling for a WebContents.
|
||||
class PrintPreviewMessageHandler
|
||||
: public printing::mojom::PrintPreviewUI,
|
||||
public content::WebContentsUserData<PrintPreviewMessageHandler> {
|
||||
public:
|
||||
~PrintPreviewMessageHandler() override;
|
||||
|
||||
// disable copy
|
||||
PrintPreviewMessageHandler(const PrintPreviewMessageHandler&) = delete;
|
||||
PrintPreviewMessageHandler& operator=(const PrintPreviewMessageHandler&) =
|
||||
delete;
|
||||
|
||||
void PrintToPDF(base::DictionaryValue options,
|
||||
gin_helper::Promise<v8::Local<v8::Value>> promise);
|
||||
|
||||
private:
|
||||
friend class content::WebContentsUserData<PrintPreviewMessageHandler>;
|
||||
|
||||
explicit PrintPreviewMessageHandler(content::WebContents* web_contents);
|
||||
|
||||
void OnCompositeDocumentToPdfDone(
|
||||
int32_t request_id,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
base::ReadOnlySharedMemoryRegion region);
|
||||
void OnPrepareForDocumentToPdfDone(
|
||||
int32_t request_id,
|
||||
printing::mojom::PrintCompositor::Status status);
|
||||
void OnCompositePdfPageDone(int page_number,
|
||||
int document_cookie,
|
||||
int32_t request_id,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
base::ReadOnlySharedMemoryRegion region);
|
||||
|
||||
// printing::mojo::PrintPreviewUI:
|
||||
void SetOptionsFromDocument(
|
||||
const printing::mojom::OptionsFromDocumentParamsPtr params,
|
||||
int32_t request_id) override {}
|
||||
void PrintPreviewFailed(int32_t document_cookie, int32_t request_id) override;
|
||||
void PrintPreviewCancelled(int32_t document_cookie,
|
||||
int32_t request_id) override;
|
||||
void PrinterSettingsInvalid(int32_t document_cookie,
|
||||
int32_t request_id) override {}
|
||||
void DidPrepareDocumentForPreview(int32_t document_cookie,
|
||||
int32_t request_id) override;
|
||||
void DidPreviewPage(printing::mojom::DidPreviewPageParamsPtr params,
|
||||
int32_t request_id) override;
|
||||
void MetafileReadyForPrinting(
|
||||
printing::mojom::DidPreviewDocumentParamsPtr params,
|
||||
int32_t request_id) override;
|
||||
void DidGetDefaultPageLayout(
|
||||
printing::mojom::PageSizeMarginsPtr page_layout_in_points,
|
||||
const gfx::Rect& printable_area_in_points,
|
||||
bool has_custom_page_size_style,
|
||||
int32_t request_id) override {}
|
||||
void DidStartPreview(printing::mojom::DidStartPreviewParamsPtr params,
|
||||
int32_t request_id) override {}
|
||||
|
||||
gin_helper::Promise<v8::Local<v8::Value>> GetPromise(int request_id);
|
||||
|
||||
void ResolvePromise(int request_id,
|
||||
scoped_refptr<base::RefCountedMemory> data_bytes);
|
||||
void RejectPromise(int request_id);
|
||||
|
||||
using PromiseMap = std::map<int, gin_helper::Promise<v8::Local<v8::Value>>>;
|
||||
PromiseMap promise_map_;
|
||||
|
||||
// TODO(clavin): refactor to use the WebContents provided by the
|
||||
// WebContentsUserData base class instead of storing a duplicate ref
|
||||
content::WebContents* web_contents_ = nullptr;
|
||||
|
||||
mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> print_render_frame_;
|
||||
|
||||
mojo::AssociatedReceiver<printing::mojom::PrintPreviewUI> receiver_{this};
|
||||
|
||||
base::WeakPtrFactory<PrintPreviewMessageHandler> weak_ptr_factory_{this};
|
||||
|
||||
WEB_CONTENTS_USER_DATA_KEY_DECL();
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
|
|
@ -7,13 +7,39 @@
|
|||
#include <utility>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
|
||||
#include "printing/mojom/print.mojom.h"
|
||||
#include "printing/page_range.h"
|
||||
#include "third_party/abseil-cpp/absl/types/variant.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
#include "mojo/public/cpp/bindings/message.h"
|
||||
#endif
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
constexpr char kInvalidUpdatePrintSettingsCall[] =
|
||||
"Invalid UpdatePrintSettings Call";
|
||||
constexpr char kInvalidSetupScriptedPrintPreviewCall[] =
|
||||
"Invalid SetupScriptedPrintPreview Call";
|
||||
constexpr char kInvalidShowScriptedPrintPreviewCall[] =
|
||||
"Invalid ShowScriptedPrintPreview Call";
|
||||
constexpr char kInvalidRequestPrintPreviewCall[] =
|
||||
"Invalid RequestPrintPreview Call";
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
// This file subclasses printing::PrintViewManagerBase
|
||||
// but the implementations are duplicated from
|
||||
// components/printing/browser/print_to_pdf/pdf_print_manager.cc.
|
||||
|
||||
PrintViewManagerElectron::PrintViewManagerElectron(
|
||||
content::WebContents* web_contents)
|
||||
: PrintViewManagerBase(web_contents),
|
||||
: printing::PrintViewManagerBase(web_contents),
|
||||
content::WebContentsUserData<PrintViewManagerElectron>(*web_contents) {}
|
||||
|
||||
PrintViewManagerElectron::~PrintViewManagerElectron() = default;
|
||||
|
@ -25,26 +51,237 @@ void PrintViewManagerElectron::BindPrintManagerHost(
|
|||
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
auto* print_manager = PrintViewManagerElectron::FromWebContents(web_contents);
|
||||
if (!print_manager)
|
||||
return;
|
||||
|
||||
print_manager->BindReceiver(std::move(receiver), rfh);
|
||||
}
|
||||
|
||||
// static
|
||||
std::string PrintViewManagerElectron::PrintResultToString(PrintResult result) {
|
||||
switch (result) {
|
||||
case PRINT_SUCCESS:
|
||||
return std::string(); // no error message
|
||||
case PRINTING_FAILED:
|
||||
return "Printing failed";
|
||||
case INVALID_PRINTER_SETTINGS:
|
||||
return "Show invalid printer settings error";
|
||||
case INVALID_MEMORY_HANDLE:
|
||||
return "Invalid memory handle";
|
||||
case METAFILE_MAP_ERROR:
|
||||
return "Map to shared memory error";
|
||||
case METAFILE_INVALID_HEADER:
|
||||
return "Invalid metafile header";
|
||||
case METAFILE_GET_DATA_ERROR:
|
||||
return "Get data from metafile error";
|
||||
case SIMULTANEOUS_PRINT_ACTIVE:
|
||||
return "The previous printing job hasn't finished";
|
||||
case PAGE_RANGE_SYNTAX_ERROR:
|
||||
return "Page range syntax error";
|
||||
case PAGE_RANGE_INVALID_RANGE:
|
||||
return "Page range is invalid (start > end)";
|
||||
case PAGE_COUNT_EXCEEDED:
|
||||
return "Page range exceeds page count";
|
||||
default:
|
||||
NOTREACHED();
|
||||
return "Unknown PrintResult";
|
||||
}
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::PrintToPdf(
|
||||
content::RenderFrameHost* rfh,
|
||||
const std::string& page_ranges,
|
||||
printing::mojom::PrintPagesParamsPtr print_pages_params,
|
||||
PrintToPDFCallback callback) {
|
||||
DCHECK(callback);
|
||||
|
||||
if (callback_) {
|
||||
std::move(callback).Run(SIMULTANEOUS_PRINT_ACTIVE,
|
||||
base::MakeRefCounted<base::RefCountedString>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rfh->IsRenderFrameLive()) {
|
||||
std::move(callback).Run(PRINTING_FAILED,
|
||||
base::MakeRefCounted<base::RefCountedString>());
|
||||
return;
|
||||
}
|
||||
|
||||
absl::variant<printing::PageRanges, print_to_pdf::PageRangeError>
|
||||
parsed_ranges = print_to_pdf::TextPageRangesToPageRanges(page_ranges);
|
||||
if (absl::holds_alternative<print_to_pdf::PageRangeError>(parsed_ranges)) {
|
||||
PrintResult print_result;
|
||||
switch (absl::get<print_to_pdf::PageRangeError>(parsed_ranges)) {
|
||||
case print_to_pdf::PageRangeError::kSyntaxError:
|
||||
print_result = PAGE_RANGE_SYNTAX_ERROR;
|
||||
break;
|
||||
case print_to_pdf::PageRangeError::kInvalidRange:
|
||||
print_result = PAGE_RANGE_INVALID_RANGE;
|
||||
break;
|
||||
}
|
||||
std::move(callback).Run(print_result,
|
||||
base::MakeRefCounted<base::RefCountedString>());
|
||||
return;
|
||||
}
|
||||
|
||||
printing_rfh_ = rfh;
|
||||
print_pages_params->pages = absl::get<printing::PageRanges>(parsed_ranges);
|
||||
auto cookie = print_pages_params->params->document_cookie;
|
||||
set_cookie(cookie);
|
||||
headless_jobs_.emplace_back(cookie);
|
||||
callback_ = std::move(callback);
|
||||
|
||||
GetPrintRenderFrame(rfh)->PrintWithParams(std::move(print_pages_params));
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::GetDefaultPrintSettings(
|
||||
GetDefaultPrintSettingsCallback callback) {
|
||||
if (printing_rfh_) {
|
||||
LOG(ERROR) << "Scripted print is not supported";
|
||||
std::move(callback).Run(printing::mojom::PrintParams::New());
|
||||
} else {
|
||||
PrintViewManagerBase::GetDefaultPrintSettings(std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::ScriptedPrint(
|
||||
printing::mojom::ScriptedPrintParamsPtr params,
|
||||
ScriptedPrintCallback callback) {
|
||||
auto entry =
|
||||
std::find(headless_jobs_.begin(), headless_jobs_.end(), params->cookie);
|
||||
if (entry == headless_jobs_.end()) {
|
||||
PrintViewManagerBase::ScriptedPrint(std::move(params), std::move(callback));
|
||||
return;
|
||||
}
|
||||
|
||||
auto default_param = printing::mojom::PrintPagesParams::New();
|
||||
default_param->params = printing::mojom::PrintParams::New();
|
||||
LOG(ERROR) << "Scripted print is not supported";
|
||||
std::move(callback).Run(std::move(default_param), /*cancelled*/ false);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::ShowInvalidPrinterSettingsError() {
|
||||
ReleaseJob(INVALID_PRINTER_SETTINGS);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::PrintingFailed(
|
||||
int32_t cookie,
|
||||
printing::mojom::PrintFailureReason reason) {
|
||||
ReleaseJob(reason == printing::mojom::PrintFailureReason::kInvalidPageRange
|
||||
? PAGE_COUNT_EXCEEDED
|
||||
: PRINTING_FAILED);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
void PrintViewManagerElectron::UpdatePrintSettings(
|
||||
int32_t cookie,
|
||||
base::Value::Dict job_settings,
|
||||
UpdatePrintSettingsCallback callback) {
|
||||
auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie);
|
||||
if (entry == headless_jobs_.end()) {
|
||||
PrintViewManagerBase::UpdatePrintSettings(cookie, std::move(job_settings),
|
||||
std::move(callback));
|
||||
return;
|
||||
}
|
||||
|
||||
mojo::ReportBadMessage(kInvalidUpdatePrintSettingsCall);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::SetupScriptedPrintPreview(
|
||||
SetupScriptedPrintPreviewCallback callback) {
|
||||
std::move(callback).Run();
|
||||
mojo::ReportBadMessage(kInvalidSetupScriptedPrintPreviewCall);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::ShowScriptedPrintPreview(
|
||||
bool source_is_modifiable) {}
|
||||
bool source_is_modifiable) {
|
||||
mojo::ReportBadMessage(kInvalidShowScriptedPrintPreviewCall);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::RequestPrintPreview(
|
||||
printing::mojom::RequestPrintPreviewParamsPtr params) {}
|
||||
printing::mojom::RequestPrintPreviewParamsPtr params) {
|
||||
mojo::ReportBadMessage(kInvalidRequestPrintPreviewCall);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::CheckForCancel(int32_t preview_ui_id,
|
||||
int32_t request_id,
|
||||
CheckForCancelCallback callback) {
|
||||
std::move(callback).Run(false);
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
|
||||
void PrintViewManagerElectron::RenderFrameDeleted(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
PrintViewManagerBase::RenderFrameDeleted(render_frame_host);
|
||||
|
||||
if (printing_rfh_ != render_frame_host)
|
||||
return;
|
||||
|
||||
if (callback_) {
|
||||
std::move(callback_).Run(PRINTING_FAILED,
|
||||
base::MakeRefCounted<base::RefCountedString>());
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::DidGetPrintedPagesCount(int32_t cookie,
|
||||
uint32_t number_pages) {
|
||||
auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie);
|
||||
if (entry == headless_jobs_.end()) {
|
||||
PrintViewManagerBase::DidGetPrintedPagesCount(cookie, number_pages);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::DidPrintDocument(
|
||||
printing::mojom::DidPrintDocumentParamsPtr params,
|
||||
DidPrintDocumentCallback callback) {
|
||||
auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(),
|
||||
params->document_cookie);
|
||||
if (entry == headless_jobs_.end()) {
|
||||
PrintViewManagerBase::DidPrintDocument(std::move(params),
|
||||
std::move(callback));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& content = *params->content;
|
||||
if (!content.metafile_data_region.IsValid()) {
|
||||
ReleaseJob(INVALID_MEMORY_HANDLE);
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
base::ReadOnlySharedMemoryMapping map = content.metafile_data_region.Map();
|
||||
if (!map.IsValid()) {
|
||||
ReleaseJob(METAFILE_MAP_ERROR);
|
||||
std::move(callback).Run(false);
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = std::string(static_cast<const char*>(map.memory()), map.size());
|
||||
headless_jobs_.erase(entry);
|
||||
std::move(callback).Run(true);
|
||||
ReleaseJob(PRINT_SUCCESS);
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::Reset() {
|
||||
printing_rfh_ = nullptr;
|
||||
callback_.Reset();
|
||||
data_.clear();
|
||||
}
|
||||
|
||||
void PrintViewManagerElectron::ReleaseJob(PrintResult result) {
|
||||
if (callback_) {
|
||||
DCHECK(result == PRINT_SUCCESS || data_.empty());
|
||||
std::move(callback_).Run(result,
|
||||
base::RefCountedString::TakeString(&data_));
|
||||
if (printing_rfh_ && printing_rfh_->IsRenderFrameLive()) {
|
||||
GetPrintRenderFrame(printing_rfh_)->PrintingDone(result == PRINT_SUCCESS);
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerElectron);
|
||||
|
|
|
@ -5,9 +5,19 @@
|
|||
#ifndef ELECTRON_SHELL_BROWSER_PRINTING_PRINT_VIEW_MANAGER_ELECTRON_H_
|
||||
#define ELECTRON_SHELL_BROWSER_PRINTING_PRINT_VIEW_MANAGER_ELECTRON_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/printing/print_view_manager_base.h"
|
||||
#include "components/printing/common/print.mojom.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "printing/print_settings.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
@ -15,9 +25,26 @@ class PrintViewManagerElectron
|
|||
: public printing::PrintViewManagerBase,
|
||||
public content::WebContentsUserData<PrintViewManagerElectron> {
|
||||
public:
|
||||
enum PrintResult {
|
||||
PRINT_SUCCESS,
|
||||
PRINTING_FAILED,
|
||||
INVALID_PRINTER_SETTINGS,
|
||||
INVALID_MEMORY_HANDLE,
|
||||
METAFILE_MAP_ERROR,
|
||||
METAFILE_INVALID_HEADER,
|
||||
METAFILE_GET_DATA_ERROR,
|
||||
SIMULTANEOUS_PRINT_ACTIVE,
|
||||
PAGE_RANGE_SYNTAX_ERROR,
|
||||
PAGE_RANGE_INVALID_RANGE,
|
||||
PAGE_COUNT_EXCEEDED,
|
||||
};
|
||||
|
||||
using PrintToPDFCallback =
|
||||
base::OnceCallback<void(PrintResult,
|
||||
scoped_refptr<base::RefCountedMemory>)>;
|
||||
|
||||
~PrintViewManagerElectron() override;
|
||||
|
||||
// disable copy
|
||||
PrintViewManagerElectron(const PrintViewManagerElectron&) = delete;
|
||||
PrintViewManagerElectron& operator=(const PrintViewManagerElectron&) = delete;
|
||||
|
||||
|
@ -26,6 +53,35 @@ class PrintViewManagerElectron
|
|||
receiver,
|
||||
content::RenderFrameHost* rfh);
|
||||
|
||||
static std::string PrintResultToString(PrintResult result);
|
||||
|
||||
void PrintToPdf(content::RenderFrameHost* rfh,
|
||||
const std::string& page_ranges,
|
||||
printing::mojom::PrintPagesParamsPtr print_page_params,
|
||||
PrintToPDFCallback callback);
|
||||
|
||||
private:
|
||||
explicit PrintViewManagerElectron(content::WebContents* web_contents);
|
||||
friend class content::WebContentsUserData<PrintViewManagerElectron>;
|
||||
|
||||
// WebContentsObserver overrides (via PrintManager):
|
||||
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
|
||||
|
||||
// printing::mojom::PrintManagerHost:
|
||||
void DidPrintDocument(printing::mojom::DidPrintDocumentParamsPtr params,
|
||||
DidPrintDocumentCallback callback) override;
|
||||
void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
|
||||
void GetDefaultPrintSettings(
|
||||
GetDefaultPrintSettingsCallback callback) override;
|
||||
void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params,
|
||||
ScriptedPrintCallback callback) override;
|
||||
void ShowInvalidPrinterSettingsError() override;
|
||||
void PrintingFailed(int32_t cookie,
|
||||
printing::mojom::PrintFailureReason reason) override;
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
void UpdatePrintSettings(int32_t cookie,
|
||||
base::Value::Dict job_settings,
|
||||
UpdatePrintSettingsCallback callback) override;
|
||||
void SetupScriptedPrintPreview(
|
||||
SetupScriptedPrintPreviewCallback callback) override;
|
||||
void ShowScriptedPrintPreview(bool source_is_modifiable) override;
|
||||
|
@ -34,10 +90,15 @@ class PrintViewManagerElectron
|
|||
void CheckForCancel(int32_t preview_ui_id,
|
||||
int32_t request_id,
|
||||
CheckForCancelCallback callback) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class content::WebContentsUserData<PrintViewManagerElectron>;
|
||||
explicit PrintViewManagerElectron(content::WebContents* web_contents);
|
||||
void Reset();
|
||||
void ReleaseJob(PrintResult result);
|
||||
|
||||
raw_ptr<content::RenderFrameHost> printing_rfh_ = nullptr;
|
||||
PrintToPDFCallback callback_;
|
||||
std::string data_;
|
||||
std::vector<int32_t> headless_jobs_;
|
||||
|
||||
WEB_CONTENTS_USER_DATA_KEY_DECL();
|
||||
};
|
||||
|
|
|
@ -1813,14 +1813,16 @@ describe('webContents module', () => {
|
|||
|
||||
it('rejects on incorrectly typed parameters', async () => {
|
||||
const badTypes = {
|
||||
marginsType: 'terrible',
|
||||
scaleFactor: 'not-a-number',
|
||||
landscape: [],
|
||||
pageRanges: { oops: 'im-not-the-right-key' },
|
||||
headerFooter: '123',
|
||||
printSelectionOnly: 1,
|
||||
displayHeaderFooter: '123',
|
||||
printBackground: 2,
|
||||
pageSize: 'IAmAPageSize'
|
||||
scale: 'not-a-number',
|
||||
pageSize: 'IAmAPageSize',
|
||||
margins: 'terrible',
|
||||
pageRanges: { oops: 'im-not-the-right-key' },
|
||||
headerTemplate: [1, 2, 3],
|
||||
footerTemplate: [4, 5, 6],
|
||||
preferCSSPageSize: 'no'
|
||||
};
|
||||
|
||||
// These will hard crash in Chromium unless we type-check
|
||||
|
@ -1869,10 +1871,7 @@ describe('webContents module', () => {
|
|||
|
||||
it('respects custom settings', async () => {
|
||||
const data = await w.webContents.printToPDF({
|
||||
pageRanges: {
|
||||
from: 0,
|
||||
to: 2
|
||||
},
|
||||
pageRanges: '1-3',
|
||||
landscape: true
|
||||
});
|
||||
|
||||
|
|
|
@ -86,10 +86,11 @@ app.whenReady().then(() => {
|
|||
mainWindow.webContents.print()
|
||||
|
||||
mainWindow.webContents.printToPDF({
|
||||
marginsType: 1,
|
||||
pageSize: 'A3',
|
||||
margins: {
|
||||
top: 1
|
||||
},
|
||||
printBackground: true,
|
||||
printSelectionOnly: true,
|
||||
pageRanges: '1-3',
|
||||
landscape: true
|
||||
}).then((data: Buffer) => console.log(data))
|
||||
|
||||
|
|
|
@ -1110,14 +1110,16 @@ describe('<webview> tag', function () {
|
|||
ifdescribe(features.isPrintingEnabled())('<webview>.printToPDF()', () => {
|
||||
it('rejects on incorrectly typed parameters', async () => {
|
||||
const badTypes = {
|
||||
marginsType: 'terrible',
|
||||
scaleFactor: 'not-a-number',
|
||||
landscape: [],
|
||||
pageRanges: { oops: 'im-not-the-right-key' },
|
||||
headerFooter: '123',
|
||||
printSelectionOnly: 1,
|
||||
displayHeaderFooter: '123',
|
||||
printBackground: 2,
|
||||
pageSize: 'IAmAPageSize'
|
||||
scale: 'not-a-number',
|
||||
pageSize: 'IAmAPageSize',
|
||||
margins: 'terrible',
|
||||
pageRanges: { oops: 'im-not-the-right-key' },
|
||||
headerTemplate: [1, 2, 3],
|
||||
footerTemplate: [4, 5, 6],
|
||||
preferCSSPageSize: 'no'
|
||||
};
|
||||
|
||||
// These will hard crash in Chromium unless we type-check
|
||||
|
|
5
typings/internal-electron.d.ts
vendored
5
typings/internal-electron.d.ts
vendored
|
@ -264,6 +264,11 @@ declare namespace ElectronInternal {
|
|||
is_default?: 'true',
|
||||
}
|
||||
|
||||
type PageSize = {
|
||||
width: number,
|
||||
height: number,
|
||||
}
|
||||
|
||||
type ModuleLoader = () => any;
|
||||
|
||||
interface ModuleEntry {
|
||||
|
|
Loading…
Add table
Reference in a new issue