Browse Source

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

* fix: always callback error with invalid print settings

* fixup printing patch

Co-authored-by: John Kleinschmidt <[email protected]>
Shelley Vohr 4 years ago
parent
commit
f59d898f5c

+ 3 - 2
docs/api/web-contents.md

@@ -1298,6 +1298,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.
 
@@ -1321,13 +1323,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<string, number> (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.
 

+ 33 - 6
lib/browser/api/web-contents.js

@@ -63,6 +63,19 @@ const PDFPageSizes = {
   }
 };
 
+// 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, height) => {
+  return [width, height].every(x => x > 352);
+};
+
 // Default printing setting
 const defaultPrintingSetting = {
   // Customizable.
@@ -317,13 +330,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 (PDFPageSizes[pageSize]) {
       printSettings.mediaSize = PDFPageSizes[pageSize];
@@ -358,12 +378,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.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.mediaSize = PDFPageSizes[pageSize];

+ 17 - 6
patches/chromium/printing.patch

@@ -63,7 +63,7 @@ index 33e17f0df3563726767d912fb828ab959c8ec252..780967949746cbe957cd7b3487507892
  }
  
 diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
-index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635ed323b7db 100644
+index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..6c6d5c885f41412e25ddfc3b884b9c39fabc4f10 100644
 --- a/chrome/browser/printing/print_view_manager_base.cc
 +++ b/chrome/browser/printing/print_view_manager_base.cc
 @@ -27,10 +27,7 @@
@@ -167,7 +167,18 @@ index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635e
  #endif
  
    ReleasePrinterQuery();
-@@ -461,9 +474,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent(
+@@ -380,6 +393,10 @@ 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(
+@@ -461,9 +478,13 @@ void PrintViewManagerBase::OnNotifyPrintJobEvent(
            content::NotificationService::NoDetails());
        break;
      }
@@ -183,7 +194,7 @@ index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635e
        NOTREACHED();
        break;
      }
-@@ -558,8 +575,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
+@@ -558,8 +579,10 @@ bool PrintViewManagerBase::CreateNewPrintJob(
    DCHECK(!quit_inner_loop_);
    DCHECK(query);
  
@@ -196,7 +207,7 @@ index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635e
  
    // We can't print if there is no renderer.
    if (!web_contents()->GetRenderViewHost() ||
-@@ -574,8 +593,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
+@@ -574,8 +597,6 @@ bool PrintViewManagerBase::CreateNewPrintJob(
    print_job_->SetSource(PrintJob::Source::PRINT_PREVIEW, /*source_id=*/"");
  #endif  // defined(OS_CHROMEOS)
  
@@ -205,7 +216,7 @@ index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635e
    printing_succeeded_ = false;
    return true;
  }
-@@ -624,14 +641,22 @@ void PrintViewManagerBase::ReleasePrintJob() {
+@@ -624,14 +645,22 @@ void PrintViewManagerBase::ReleasePrintJob() {
    content::RenderFrameHost* rfh = printing_rfh_;
    printing_rfh_ = nullptr;
  
@@ -230,7 +241,7 @@ index 3378f34bd8e3b1cf8156e86d0e9bea97120c101e..c7c611486b158095c10db7d8e425635e
    // Don't close the worker thread.
    print_job_ = nullptr;
  }
-@@ -667,7 +692,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
+@@ -667,7 +696,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
  }
  
  bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {

+ 11 - 0
spec-main/api-web-contents-spec.ts

@@ -135,6 +135,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({