fix: webContents.printToPDF() with cross-process subframes (#46218)

fix: webContents.printToPDF() with cross-process subframes
This commit is contained in:
Shelley Vohr 2025-03-25 14:16:47 +01:00 committed by GitHub
parent 8e856dfdb8
commit 1d6cb348b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 1 deletions

View file

@ -176,6 +176,7 @@
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
#include "chrome/browser/printing/print_view_manager_base.h" #include "chrome/browser/printing/print_view_manager_base.h"
#include "components/printing/browser/print_composite_client.h"
#include "components/printing/browser/print_manager_utils.h" #include "components/printing/browser/print_manager_utils.h"
#include "components/printing/browser/print_to_pdf/pdf_print_result.h" #include "components/printing/browser/print_to_pdf/pdf_print_result.h"
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h" #include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
@ -1023,6 +1024,7 @@ void WebContents::InitWithWebContents(
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
PrintViewManagerElectron::CreateForWebContents(web_contents.get()); PrintViewManagerElectron::CreateForWebContents(web_contents.get());
printing::CreateCompositeClientIfNeeded(web_contents.get(), GetUserAgent());
#endif #endif
// Determine whether the WebContents is offscreen. // Determine whether the WebContents is offscreen.
@ -1983,6 +1985,17 @@ void WebContents::DraggableRegionsChanged(
draggable_region_ = DraggableRegionsToSkRegion(regions); draggable_region_ = DraggableRegionsToSkRegion(regions);
} }
void WebContents::PrintCrossProcessSubframe(
content::WebContents* web_contents,
const gfx::Rect& rect,
int document_cookie,
content::RenderFrameHost* subframe_host) const {
if (auto* client =
printing::PrintCompositeClient::FromWebContents(web_contents)) {
client->PrintCrossProcessSubframe(rect, document_cookie, subframe_host);
}
}
SkRegion* WebContents::draggable_region() { SkRegion* WebContents::draggable_region() {
return g_disable_draggable_regions ? nullptr : draggable_region_.get(); return g_disable_draggable_regions ? nullptr : draggable_region_.get();
} }

View file

@ -585,6 +585,11 @@ class WebContents final : public ExclusiveAccessContext,
void DraggableRegionsChanged( void DraggableRegionsChanged(
const std::vector<blink::mojom::DraggableRegionPtr>& regions, const std::vector<blink::mojom::DraggableRegionPtr>& regions,
content::WebContents* contents) override; content::WebContents* contents) override;
void PrintCrossProcessSubframe(
content::WebContents* web_contents,
const gfx::Rect& rect,
int document_cookie,
content::RenderFrameHost* subframe_host) const override;
// content::WebContentsObserver: // content::WebContentsObserver:
void BeforeUnloadFired(bool proceed) override; void BeforeUnloadFired(bool proceed) override;

View file

@ -90,6 +90,7 @@ void ElectronExtensionsAPIClient::AttachWebContentsHelpers(
content::WebContents* web_contents) const { content::WebContents* web_contents) const {
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
electron::PrintViewManagerElectron::CreateForWebContents(web_contents); electron::PrintViewManagerElectron::CreateForWebContents(web_contents);
printing::CreateCompositeClientIfNeeded(web_contents, std::string());
#endif #endif
extensions::ElectronExtensionWebContentsObserver::CreateForWebContents( extensions::ElectronExtensionWebContentsObserver::CreateForWebContents(

View file

@ -2440,6 +2440,7 @@ describe('webContents module', () => {
}); });
ifdescribe(features.isPrintingEnabled())('printToPDF()', () => { ifdescribe(features.isPrintingEnabled())('printToPDF()', () => {
let server: http.Server | null;
const readPDF = async (data: any) => { const readPDF = async (data: any) => {
const tmpDir = await fs.promises.mkdtemp(path.resolve(os.tmpdir(), 'e-spec-printtopdf-')); const tmpDir = await fs.promises.mkdtemp(path.resolve(os.tmpdir(), 'e-spec-printtopdf-'));
const pdfPath = path.resolve(tmpDir, 'test.pdf'); const pdfPath = path.resolve(tmpDir, 'test.pdf');
@ -2483,7 +2484,12 @@ describe('webContents module', () => {
}); });
}); });
afterEach(closeAllWindows); afterEach(() => {
closeAllWindows();
if (server) {
server.close();
}
});
it('rejects on incorrectly typed parameters', async () => { it('rejects on incorrectly typed parameters', async () => {
const badTypes = { const badTypes = {
@ -2644,6 +2650,32 @@ describe('webContents module', () => {
expect(pdfInfo.markInfo).to.be.null(); expect(pdfInfo.markInfo).to.be.null();
}); });
it('can print same-origin iframes', async () => {
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'print-to-pdf-same-origin.html'));
const data = await w.webContents.printToPDF({});
const pdfInfo = await readPDF(data);
expect(containsText(pdfInfo.textContent, /Virtual member functions/)).to.be.true();
});
// TODO(codebytere): OOPIF printing is disabled on Linux at the moment due to crashes.
ifit(process.platform !== 'linux')('can print cross-origin iframes', async () => {
server = http.createServer((_, res) => {
res.writeHead(200);
res.end(`
<title>cross-origin iframe</title>
<p>This page is displayed in an iframe.</p>
`);
});
const { port } = await listen(server);
await w.loadURL(`data:text/html,<iframe src="http://localhost:${port}"></iframe>`);
const data = await w.webContents.printToPDF({});
const pdfInfo = await readPDF(data);
expect(containsText(pdfInfo.textContent, /This page is displayed in an iframe./)).to.be.true();
});
it('can generate tag data for PDFs', async () => { it('can generate tag data for PDFs', async () => {
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'print-to-pdf-small.html')); await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'print-to-pdf-small.html'));

View file

@ -0,0 +1,11 @@
<html>
<head>
<title>Your Title Here</title>
</head>
<body style="background: green;">
<iframe src="../pages/content.html"</iframe>
</body>
</html>