Allow print() only in response to a user gesture

This prevents the print dialog opening automatically when a PDF is
embedded in a web-page.

As part of this change, move the existing tests from document_methods.in
to mouse_events.in, and extend the mouse_events.in tests to check that
print can only be called in response to a user gesture.

BUG=chromium:968914

Change-Id: Ib55808cf500288460f79c940af0c4d2738bb93e5
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/56790
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fxjs/cjs_document.cpp b/fxjs/cjs_document.cpp
index 4fc8803..cd9beeb 100644
--- a/fxjs/cjs_document.cpp
+++ b/fxjs/cjs_document.cpp
@@ -508,6 +508,11 @@
   if (!m_pFormFillEnv)
     return CJS_Result::Failure(JSMessage::kBadObjectError);
 
+  CJS_EventRecorder* pHandler =
+      pRuntime->GetCurrentEventContext()->GetEventRecorder();
+  if (!pHandler->IsUserGesture())
+    return CJS_Result::Failure(JSMessage::kUserGestureRequiredError);
+
   m_pFormFillEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit,
                               bPrintAsImage, bReverse, bAnnotations);
   return CJS_Result::Success();
diff --git a/testing/resources/javascript/document_methods.in b/testing/resources/javascript/document_methods.in
index 1f2dd29..9571e55 100644
--- a/testing/resources/javascript/document_methods.in
+++ b/testing/resources/javascript/document_methods.in
@@ -274,16 +274,11 @@
 }
 
 function testPrint() {
-   // Method is present.
-   expect('typeof this.print', 'function');
+  // Method is present.
+  expect('typeof this.print', 'function');
 
-  // TODO(tsepez): test success cases.
-  expect('this.print()', undefined);
-  expect('this.print(false, 1, 10, true, true, true, true, true)', undefined);
-  expect('this.print({})', undefined);
-  expect('this.print({"bUi": false, "nStart": 42, "nEnd": 17, ' +
-            '"bSilent": true, "bShrinkToFit": true, "bPrintAsImage": true, ' +
-            '"bReverse": true, "bAnnotations": true, "bogus": "yes"})', undefined);
+  // Successful only when invoked by a user gesture.
+  expectError('this.print()', undefined);
 }
 
 function testRemoveField() {
diff --git a/testing/resources/javascript/document_methods_expected.txt b/testing/resources/javascript/document_methods_expected.txt
index 495c2fb..ec42224 100644
--- a/testing/resources/javascript/document_methods_expected.txt
+++ b/testing/resources/javascript/document_methods_expected.txt
@@ -131,14 +131,7 @@
 Mail Msg: 0, to=user@example.com, cc=cc@example.com, bcc=bcc@example.com, subject=LotteryWinner, body=You won the lottery!
 Alert: PASS: this.mailForm({"bUI": false, "cTo": "user@example.com", "cCc": "cc@example.com", "cBcc": "bcc@example.com", "cSubject": "LotteryWinner", "cMsg": "You won the lottery!", "bogus": "yes"}) = undefined
 Alert: PASS: typeof this.print = function
-Doc Print: 1, 0, 0, 0, 0, 0, 0, 0
-Alert: PASS: this.print() = undefined
-Doc Print: 0, 1, 10, 1, 1, 1, 1, 1
-Alert: PASS: this.print(false, 1, 10, true, true, true, true, true) = undefined
-Doc Print: 1, 0, 0, 0, 0, 0, 0, 0
-Alert: PASS: this.print({}) = undefined
-Doc Print: 1, 42, 17, 1, 1, 1, 1, 1
-Alert: PASS: this.print({"bUi": false, "nStart": 42, "nEnd": 17, "bSilent": true, "bShrinkToFit": true, "bPrintAsImage": true, "bReverse": true, "bAnnotations": true, "bogus": "yes"}) = undefined
+Alert: PASS: this.print() threw Document.print: User gesture required.
 Alert: PASS: typeof this.removeField = function
 Alert: PASS: this.removeField() threw Document.removeField: Incorrect number of parameters passed to function.
 Alert: PASS: typeof this.resetForm = function
diff --git a/testing/resources/javascript/mouse_events.in b/testing/resources/javascript/mouse_events.in
index 353961c..9480e94 100644
--- a/testing/resources/javascript/mouse_events.in
+++ b/testing/resources/javascript/mouse_events.in
@@ -61,6 +61,13 @@
     } catch \(e\) {
        app.alert\("PASS: this.submitForm blocked with " + e\);
     }
+
+    try {
+       this.print\(\);
+       app.alert\("ERROR: this.print\(\) must not be allowed to execute"\);
+    } catch \(e\) {
+       app.alert\("PASS: this.print blocked with " + e\);
+    }
   )
 >>
 endobj
@@ -75,6 +82,13 @@
     } catch \(e\) {
        app.alert\("PASS: this.submitForm blocked with " + e\);
     }
+
+    try {
+       this.print\(\);
+       app.alert\("ERROR: this.print\(\) must not be allowed to execute"\);
+    } catch \(e\) {
+       app.alert\("PASS: this.print blocked with " + e\);
+    }
   )
 >>
 endobj
@@ -88,6 +102,17 @@
     } catch \(e\) {
        app.alert\("ERROR: " + e\);
     }
+
+    try {
+       this.print\(\);
+       this.print\(false, 1, 10, true, true, true, true, true\);
+       this.print\({}\);
+       this.print\({"bUi": false, "nStart": 42, "nEnd": 17,
+            "bSilent": true, "bShrinkToFit": true, "bPrintAsImage": true,
+            "bReverse": true, "bAnnotations": true, "bogus": "yes"}\);
+    } catch \(e\) {
+       app.alert\("ERROR: " + e\);
+    }
   )
 >>
 endobj
@@ -101,6 +126,12 @@
     } catch \(e\) {
        app.alert\("ERROR: " + e\);
     }
+
+    try {
+       this.print\(\);
+    } catch \(e\) {
+       app.alert\("ERROR: " + e\);
+    }
   )
 >>
 endobj
@@ -115,6 +146,13 @@
     } catch \(e\) {
        app.alert\("PASS: this.submitForm blocked with " + e\);
     }
+
+    try {
+       this.print\(\);
+       app.alert\("ERROR: this.print\(\) must not be allowed to execute"\);
+    } catch \(e\) {
+       app.alert\("PASS: this.print blocked with " + e\);
+    }
   )
 >>
 endobj
@@ -129,6 +167,13 @@
     } catch \(e\) {
        app.alert\("PASS: this.submitForm blocked with " + e\);
     }
+
+    try {
+       this.print\(\);
+       app.alert\("ERROR: this.print\(\) must not be allowed to execute"\);
+    } catch \(e\) {
+       app.alert\("PASS: this.print blocked with " + e\);
+    }
   )
 >>
 endobj
diff --git a/testing/resources/javascript/mouse_events_expected.txt b/testing/resources/javascript/mouse_events_expected.txt
index da031bf..8e87e1a 100644
--- a/testing/resources/javascript/mouse_events_expected.txt
+++ b/testing/resources/javascript/mouse_events_expected.txt
@@ -1,20 +1,33 @@
 Alert: enter
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: exit
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: enter
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: down
 Doc Submit Form: url=myform
+Doc Print: 1, 0, 0, 0, 0, 0, 0, 0
+Doc Print: 0, 1, 10, 1, 1, 1, 1, 1
+Doc Print: 1, 0, 0, 0, 0, 0, 0, 0
+Doc Print: 1, 42, 17, 1, 1, 1, 1, 1
 Alert: focus
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: up
 Doc Submit Form: url=myform
+Doc Print: 1, 0, 0, 0, 0, 0, 0, 0
 Alert: exit
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: enter
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: focus
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.
 Alert: exit
 Alert: PASS: this.submitForm blocked with Document.submitForm: User gesture required.
+Alert: PASS: this.print blocked with Document.print: User gesture required.