fix: always callback error with invalid print settings (#24476)

This commit is contained in:
Shelley Vohr 2020-07-10 09:42:22 -07:00 committed by GitHub
parent 5737fda154
commit 6c4017ff45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 14 deletions

View file

@ -1311,6 +1311,8 @@ Returns [`PrinterInfo[]`](structures/printer-info.md)
* `success` Boolean - Indicates success of the print call. * `success` Boolean - Indicates success of the print call.
* `failureReason` String - Error description called back if the print fails. * `failureReason` String - Error description called back if the print fails.
When a custom `pageSize` is passed, Chromium attempts to validate platform specific minumum values for `width_microns` and `height_microns`. Width and height must both be minimum 353 microns but may be higher on some operating systems.
Prints window's web page. When `silent` is set to `true`, Electron will pick Prints window's web page. When `silent` is set to `true`, Electron will pick
the system's default printer if `deviceName` is empty and the default settings for printing. the system's default printer if `deviceName` is empty and the default settings for printing.
@ -1334,13 +1336,12 @@ win.webContents.print(options, (success, errorType) => {
* `landscape` Boolean (optional) - `true` for landscape, `false` for portrait. * `landscape` Boolean (optional) - `true` for landscape, `false` for portrait.
* `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for * `marginsType` Integer (optional) - Specifies the type of margins to use. Uses 0 for
default margin, 1 for no margin, and 2 for minimum margin. 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. * `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. * `pageRanges` Record<string, number> (optional) - The page range to print.
* `from` Number - the first page to print. * `from` Number - the first page to print.
* `to` Number - the last page to print (inclusive). * `to` Number - the last page to print (inclusive).
* `pageSize` String | Size (optional) - Specify page size of the generated PDF. Can be `A3`, * `pageSize` String | Size (optional) - Specify page size of the generated PDF. 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` in microns.
* `printBackground` Boolean (optional) - Whether to print CSS backgrounds. * `printBackground` Boolean (optional) - Whether to print CSS backgrounds.
* `printSelectionOnly` Boolean (optional) - Whether to print selection only. * `printSelectionOnly` Boolean (optional) - Whether to print selection only.

View file

@ -72,6 +72,19 @@ const PDFPageSizes: Record<string, MediaSize> = {
} }
}; };
// The minimum micron size Chromium accepts is that where:
// Per printing/units.h:
// * kMicronsPerInch - Length of an inch in 0.001mm unit.
// * kPointsPerInch - Length of an inch in CSS's 1pt unit.
//
// Formula: (kPointsPerInch / kMicronsPerInch) * size >= 1
//
// Practically, this means microns need to be > 352 microns.
// We therefore need to verify this or it will silently fail.
const isValidCustomPageSize = (width: number, height: number) => {
return [width, height].every(x => x > 352);
};
// Default printing setting // Default printing setting
const defaultPrintingSetting = { const defaultPrintingSetting = {
// Customizable. // Customizable.
@ -315,13 +328,20 @@ WebContents.prototype.printToPDF = function (options) {
const error = new Error('height and width properties are required for pageSize'); const error = new Error('height and width properties are required for pageSize');
return Promise.reject(error); return Promise.reject(error);
} }
// Dimensions in Microns
// 1 meter = 10^6 microns // 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 = { printSettings.mediaSize = {
name: 'CUSTOM', name: 'CUSTOM',
custom_display_name: 'Custom', custom_display_name: 'Custom',
height_microns: Math.ceil(pageSize.height), height_microns: height,
width_microns: Math.ceil(pageSize.width) width_microns: width
}; };
} else if (Object.prototype.hasOwnProperty.call(PDFPageSizes, pageSize)) { } else if (Object.prototype.hasOwnProperty.call(PDFPageSizes, pageSize)) {
printSettings.mediaSize = PDFPageSizes[pageSize]; printSettings.mediaSize = PDFPageSizes[pageSize];
@ -356,12 +376,19 @@ WebContents.prototype.print = function (options = {}, callback) {
if (!pageSize.height || !pageSize.width) { if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize'); throw new Error('height and width properties are required for pageSize');
} }
// Dimensions in Microns - 1 meter = 10^6 microns // Dimensions in Microns - 1 meter = 10^6 microns
const height = Math.ceil(pageSize.height);
const width = Math.ceil(pageSize.width);
if (!isValidCustomPageSize(width, height)) {
throw new Error('height and width properties must be minimum 352 microns.');
}
(options as any).mediaSize = { (options as any).mediaSize = {
name: 'CUSTOM', name: 'CUSTOM',
custom_display_name: 'Custom', custom_display_name: 'Custom',
height_microns: Math.ceil(pageSize.height), height_microns: height,
width_microns: Math.ceil(pageSize.width) width_microns: width
}; };
} else if (PDFPageSizes[pageSize]) { } else if (PDFPageSizes[pageSize]) {
(options as any).mediaSize = PDFPageSizes[pageSize]; (options as any).mediaSize = PDFPageSizes[pageSize];

View file

@ -90,7 +90,7 @@ index adb208ba3589e32536527219aaf4e89e3ee3311a..301f6416898445eed814d67901254ef8
} }
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc473bbd0da 100644 index 8a743d0dd74b087059ff812019ae568a22c5fa01..551dbc7b0bfdbf4ca549278bb3dfc4e3abb5cf0f 100644
--- a/chrome/browser/printing/print_view_manager_base.cc --- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -27,10 +27,7 @@ @@ -27,10 +27,7 @@
@ -194,7 +194,19 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4
#endif #endif
ReleasePrinterQuery(); ReleasePrinterQuery();
@@ -463,9 +476,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent( @@ -382,6 +395,11 @@ void PrintViewManagerBase::OnScriptedPrint(
}
void PrintViewManagerBase::OnShowInvalidPrinterSettingsError() {
+ if (!callback_.is_null()) {
+ std::string cb_str = "Invalid printer settings";
+ std::move(callback_).Run(printing_succeeded_, cb_str);
+ }
+
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&ShowWarningMessageBox,
l10n_util::GetStringUTF16(
@@ -463,9 +481,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent(
content::NotificationService::NoDetails()); content::NotificationService::NoDetails());
break; break;
} }
@ -210,7 +222,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4
NOTREACHED(); NOTREACHED();
break; break;
} }
@@ -560,8 +577,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( @@ -560,8 +582,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
DCHECK(!quit_inner_loop_); DCHECK(!quit_inner_loop_);
DCHECK(query); DCHECK(query);
@ -223,7 +235,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4
// We can't print if there is no renderer. // We can't print if there is no renderer.
if (!web_contents()->GetRenderViewHost() || if (!web_contents()->GetRenderViewHost() ||
@@ -582,8 +601,6 @@ bool PrintViewManagerBase::CreateNewPrintJob( @@ -582,8 +606,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
print_job_->SetSource(source, /*source_id=*/""); print_job_->SetSource(source, /*source_id=*/"");
#endif #endif
@ -232,7 +244,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4
printing_succeeded_ = false; printing_succeeded_ = false;
return true; return true;
} }
@@ -632,14 +649,22 @@ void PrintViewManagerBase::ReleasePrintJob() { @@ -632,14 +654,22 @@ void PrintViewManagerBase::ReleasePrintJob() {
content::RenderFrameHost* rfh = printing_rfh_; content::RenderFrameHost* rfh = printing_rfh_;
printing_rfh_ = nullptr; printing_rfh_ = nullptr;
@ -257,7 +269,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4
// Don't close the worker thread. // Don't close the worker thread.
print_job_ = nullptr; print_job_ = nullptr;
} }
@@ -675,7 +700,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { @@ -675,7 +705,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
} }
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {

View file

@ -141,6 +141,17 @@ describe('webContents module', () => {
}).to.throw('Unsupported pageSize: i-am-a-bad-pagesize'); }).to.throw('Unsupported pageSize: i-am-a-bad-pagesize');
}); });
it('throws when an invalid custom pageSize is passed', () => {
expect(() => {
w.webContents.print({
pageSize: {
width: 100,
height: 200
}
});
}).to.throw('height and width properties must be minimum 352 microns.');
});
it('does not crash with custom margins', () => { it('does not crash with custom margins', () => {
expect(() => { expect(() => {
w.webContents.print({ w.webContents.print({