diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index dfde8126886..da121fa3f12 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1311,6 +1311,8 @@ Returns [`PrinterInfo[]`](structures/printer-info.md) * `success` Boolean - Indicates success of the print call. * `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 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. * `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 (optional) - The page range to print. * `from` Number - the first page to print. * `to` Number - the last page to print (inclusive). * `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. * `printSelectionOnly` Boolean (optional) - Whether to print selection only. diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 1fff4af8e3c..48b2ed05bbd 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -72,6 +72,19 @@ const PDFPageSizes: Record = { } }; +// 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 const defaultPrintingSetting = { // Customizable. @@ -315,13 +328,20 @@ WebContents.prototype.printToPDF = function (options) { const error = new Error('height and width properties are required for pageSize'); 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 = { name: 'CUSTOM', custom_display_name: 'Custom', - height_microns: Math.ceil(pageSize.height), - width_microns: Math.ceil(pageSize.width) + height_microns: height, + width_microns: width }; } else if (Object.prototype.hasOwnProperty.call(PDFPageSizes, pageSize)) { printSettings.mediaSize = PDFPageSizes[pageSize]; @@ -356,12 +376,19 @@ WebContents.prototype.print = function (options = {}, callback) { if (!pageSize.height || !pageSize.width) { throw 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)) { + throw new Error('height and width properties must be minimum 352 microns.'); + } + (options as any).mediaSize = { name: 'CUSTOM', custom_display_name: 'Custom', - height_microns: Math.ceil(pageSize.height), - width_microns: Math.ceil(pageSize.width) + height_microns: height, + width_microns: width }; } else if (PDFPageSizes[pageSize]) { (options as any).mediaSize = PDFPageSizes[pageSize]; diff --git a/patches/chromium/printing.patch b/patches/chromium/printing.patch index 6a8baa609d2..a6941a5823f 100644 --- a/patches/chromium/printing.patch +++ b/patches/chromium/printing.patch @@ -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 -index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc473bbd0da 100644 +index 8a743d0dd74b087059ff812019ae568a22c5fa01..551dbc7b0bfdbf4ca549278bb3dfc4e3abb5cf0f 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc @@ -27,10 +27,7 @@ @@ -194,7 +194,19 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4 #endif 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()); break; } @@ -210,7 +222,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4 NOTREACHED(); break; } -@@ -560,8 +577,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( +@@ -560,8 +582,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( DCHECK(!quit_inner_loop_); DCHECK(query); @@ -223,7 +235,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4 // We can't print if there is no renderer. if (!web_contents()->GetRenderViewHost() || -@@ -582,8 +601,6 @@ bool PrintViewManagerBase::CreateNewPrintJob( +@@ -582,8 +606,6 @@ bool PrintViewManagerBase::CreateNewPrintJob( print_job_->SetSource(source, /*source_id=*/""); #endif @@ -232,7 +244,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4 printing_succeeded_ = false; return true; } -@@ -632,14 +649,22 @@ void PrintViewManagerBase::ReleasePrintJob() { +@@ -632,14 +654,22 @@ void PrintViewManagerBase::ReleasePrintJob() { content::RenderFrameHost* rfh = printing_rfh_; printing_rfh_ = nullptr; @@ -257,7 +269,7 @@ index 8a743d0dd74b087059ff812019ae568a22c5fa01..20c43be03706617a276d210190897dc4 // Don't close the worker thread. print_job_ = nullptr; } -@@ -675,7 +700,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { +@@ -675,7 +705,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { } bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index cf9690b663e..248195a253e 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -141,6 +141,17 @@ describe('webContents module', () => { }).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', () => { expect(() => { w.webContents.print({