Repository: electron/electron
Pull request: fix: ensure correct `WebContents` when checking `PDFReadyToPrint`

#### Description of Change

Fixes an issue where `-pdf-ready-to-print` was never emitted on WebView webContents as expected. Fix this as well as add a test.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: none

Changed files:
filename: shell/browser/electron_pdf_document_helper_client.cc
patch: @@ -27,13 +27,23 @@ void ElectronPDFDocumentHelperClient::UpdateContentRestrictions(
   // allowed there won't be a printing restriction passed, so we can use this
   // second call to notify that the pdf document is ready to print.
   if (!(content_restrictions & chrome_pdf::kContentRestrictionPrint)) {
-    content::WebContents* web_contents =
-        content::WebContents::FromRenderFrameHost(render_frame_host);
-    electron::api::WebContents* api_web_contents =
-        electron::api::WebContents::From(
-            web_contents->GetOutermostWebContents());
-    if (api_web_contents) {
-      api_web_contents->PDFReadyToPrint();
+    // It's a WebView - emit the event on the WebView webContents.
+    auto* guest_view = extensions::MimeHandlerViewGuest::FromRenderFrameHost(
+        render_frame_host);
+    if (guest_view) {
+      auto* gv_api_wc =
+          electron::api::WebContents::From(guest_view->embedder_web_contents());
+      if (gv_api_wc)
+        gv_api_wc->PDFReadyToPrint();
+      return;
+    }
+
+    auto* wc = content::WebContents::FromRenderFrameHost(render_frame_host);
+    if (wc) {
+      auto* api_wc =
+          electron::api::WebContents::From(wc->GetOuterWebContents());
+      if (api_wc)
+        api_wc->PDFReadyToPrint();
     }
   }
 }

filename: spec/api-web-contents-spec.ts
patch: @@ -5,14 +5,14 @@ import * as path from 'node:path';
 import * as fs from 'node:fs';
 import * as http from 'node:http';
 import * as os from 'node:os';
+import * as url from 'node:url';
 import { BrowserWindow, ipcMain, webContents, session, app, BrowserView, WebContents } from 'electron/main';
 import { closeAllWindows } from './lib/window-helpers';
 import { ifdescribe, defer, waitUntil, listen, ifit } from './lib/spec-helpers';
 import { once } from 'node:events';
 import { setTimeout } from 'node:timers/promises';
 
 const fixturesPath = path.resolve(__dirname, 'fixtures');
-const mainFixturesPath = path.resolve(__dirname, 'fixtures');
 const features = process._linkedBinding('electron_common_features');
 
 describe('webContents module', () => {
@@ -1185,7 +1185,7 @@ describe('webContents module', () => {
       }).to.throw('\'icon\' parameter is required');
 
       expect(() => {
-        w.webContents.startDrag({ file: __filename, icon: path.join(mainFixturesPath, 'blank.png') });
+        w.webContents.startDrag({ file: __filename, icon: path.join(fixturesPath, 'blank.png') });
       }).to.throw(/Failed to load image from path (.+)/);
     });
   });
@@ -2496,6 +2496,43 @@ describe('webContents module', () => {
       expect(pdfInfo.numPages).to.equal(2);
       expect(containsText(pdfInfo.textContent, /Cat: The Ideal Pet/)).to.be.true();
     });
+
+    it('from an existing pdf document in a WebView', async () => {
+      const win = new BrowserWindow({
+        show: false,
+        webPreferences: {
+          webviewTag: true
+        }
+      });
+
+      await win.loadURL('about:blank');
+      const webContentsCreated = once(app, 'web-contents-created') as Promise<[any, WebContents]>;
+
+      const src = url.format({
+        pathname: `${fixturesPath.replaceAll('\\', '/')}/cat.pdf`,
+        protocol: 'file',
+        slashes: true
+      });
+      await win.webContents.executeJavaScript(`
+        new Promise((resolve, reject) => {
+          const webview = new WebView()
+          webview.setAttribute('src', '${src}')
+          document.body.appendChild(webview)
+          webview.addEventListener('did-finish-load', () => {
+            resolve()
+          })
+        })
+      `);
+
+      const [, webContents] = await webContentsCreated;
+
+      await once(webContents, '-pdf-ready-to-print');
+
+      const data = await webContents.printToPDF({});
+      const pdfInfo = await readPDF(data);
+      expect(pdfInfo.numPages).to.equal(2);
+      expect(containsText(pdfInfo.textContent, /Cat: The Ideal Pet/)).to.be.true();
+    });
   });
 
   describe('PictureInPicture video', () => {