mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
refactor: match upstream print preview handling (#24452)
This commit is contained in:
@@ -1371,6 +1371,8 @@ An example of `webContents.printToPDF`:
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com')
|
||||
@@ -1378,12 +1380,13 @@ win.loadURL('http://github.com')
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
fs.writeFile('/tmp/print.pdf', data, (error) => {
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log('Write PDF successfully.')
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
console.log(`Failed to write PDF to ${pdfPath}: `, error)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@@ -215,7 +215,9 @@ WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (code, h
|
||||
};
|
||||
|
||||
// Translate the options of printToPDF.
|
||||
WebContents.prototype.printToPDF = function (options) {
|
||||
|
||||
let pendingPromise;
|
||||
WebContents.prototype.printToPDF = async function (options) {
|
||||
const printSettings = {
|
||||
...defaultPrintingSetting,
|
||||
requestID: getNextId()
|
||||
@@ -341,7 +343,12 @@ WebContents.prototype.printToPDF = function (options) {
|
||||
// PrinterType enum from //printing/print_job_constants.h
|
||||
printSettings.printerType = 2;
|
||||
if (this._printToPDF) {
|
||||
return this._printToPDF(printSettings);
|
||||
if (pendingPromise) {
|
||||
pendingPromise = pendingPromise.then(() => this._printToPDF(printSettings));
|
||||
} else {
|
||||
pendingPromise = this._printToPDF(printSettings);
|
||||
}
|
||||
return pendingPromise;
|
||||
} else {
|
||||
const error = new Error('Printing feature is disabled');
|
||||
return Promise.reject(error);
|
||||
|
||||
@@ -83,7 +83,6 @@ delay_lock_the_protocol_scheme_registry.patch
|
||||
gpu_notify_when_dxdiag_request_fails.patch
|
||||
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
||||
feat_add_onclose_to_messageport.patch
|
||||
fix_account_for_print_preview_disabled_when_printing_to_pdf.patch
|
||||
web_contents.patch
|
||||
ui_gtk_public_header.patch
|
||||
refactor_expose_cursor_changes_to_the_webcontentsobserver.patch
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andy Locascio <andy@slack-corp.com>
|
||||
Date: Thu, 2 Apr 2020 15:05:00 -0700
|
||||
Subject: fix: account for print preview disabled when printing to pdf
|
||||
|
||||
Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2068936
|
||||
|
||||
Avoid an optimization introduced in the above CL. In my limited
|
||||
understanding, it seems like we slightly misuse the print preview API
|
||||
and this is fallout from using it in a way the code doesn't expect.
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index fc39f8874402904021e804a5b7fc754709f25353..40c80983f0d2d45058ee49a3542825d3fa822a8b 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -1491,6 +1491,7 @@ PrintRenderFrameHelper::CreatePreviewDocument() {
|
||||
const std::vector<int>& pages = print_pages_params_->pages;
|
||||
|
||||
bool require_document_metafile =
|
||||
+ !g_is_preview_enabled ||
|
||||
print_renderer_ ||
|
||||
print_params.printed_doc_type != mojom::SkiaDocumentType::kMSKP;
|
||||
if (!print_preview_context_.CreatePreviewDocument(
|
||||
@@ -67,6 +67,9 @@ bool PrintPreviewMessageHandler::OnMessageReceived(
|
||||
render_frame_host)
|
||||
IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting,
|
||||
OnMetafileReadyForPrinting)
|
||||
IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage, OnDidPreviewPage)
|
||||
IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrepareDocumentForPreview,
|
||||
OnDidPrepareForDocumentToPdf)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return handled;
|
||||
@@ -79,13 +82,14 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
|
||||
// Always try to stop the worker.
|
||||
StopWorker(params.document_cookie);
|
||||
|
||||
const base::ReadOnlySharedMemoryRegion& metafile =
|
||||
params.content->metafile_data_region;
|
||||
if (!metafile.IsValid() || params.expected_pages_count <= 0) {
|
||||
if (params.expected_pages_count == 0) {
|
||||
RejectPromise(ids.request_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const base::ReadOnlySharedMemoryRegion& metafile =
|
||||
params.content->metafile_data_region;
|
||||
|
||||
if (printing::IsOopifEnabled()) {
|
||||
auto* client =
|
||||
printing::PrintCompositeClient::FromWebContents(web_contents());
|
||||
@@ -94,8 +98,9 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
|
||||
auto callback = base::BindOnce(
|
||||
&PrintPreviewMessageHandler::OnCompositeDocumentToPdfDone,
|
||||
weak_ptr_factory_.GetWeakPtr(), ids);
|
||||
client->DoCompositeDocumentToPdf(
|
||||
params.document_cookie, render_frame_host, *(params.content),
|
||||
|
||||
client->DoCompleteDocumentToPdf(
|
||||
params.document_cookie, params.expected_pages_count,
|
||||
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
|
||||
std::move(callback),
|
||||
printing::mojom::PrintCompositor::Status::kCompositingFailure,
|
||||
@@ -107,6 +112,37 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
|
||||
}
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::OnPrepareForDocumentToPdfDone(
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (status != printing::mojom::PrintCompositor::Status::kSuccess) {
|
||||
LOG(ERROR) << "Preparing document for pdf failed with error " << status;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::OnDidPrepareForDocumentToPdf(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
int document_cookie,
|
||||
const PrintHostMsg_PreviewIds& ids) {
|
||||
if (printing::IsOopifEnabled()) {
|
||||
auto* client =
|
||||
printing::PrintCompositeClient::FromWebContents(web_contents());
|
||||
DCHECK(client);
|
||||
|
||||
if (client->GetIsDocumentConcurrentlyComposited(document_cookie))
|
||||
return;
|
||||
|
||||
client->DoPrepareForDocumentToPdf(
|
||||
document_cookie, render_frame_host,
|
||||
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
|
||||
base::BindOnce(
|
||||
&PrintPreviewMessageHandler::OnPrepareForDocumentToPdfDone,
|
||||
weak_ptr_factory_.GetWeakPtr(), ids),
|
||||
printing::mojom::PrintCompositor::Status::kCompositingFailure));
|
||||
}
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::OnCompositeDocumentToPdfDone(
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
@@ -114,7 +150,7 @@ void PrintPreviewMessageHandler::OnCompositeDocumentToPdfDone(
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
if (status != printing::mojom::PrintCompositor::Status::kSuccess) {
|
||||
DLOG(ERROR) << "Compositing pdf failed with error " << status;
|
||||
LOG(ERROR) << "Compositing pdf failed with error " << status;
|
||||
RejectPromise(ids.request_id);
|
||||
return;
|
||||
}
|
||||
@@ -124,6 +160,49 @@ void PrintPreviewMessageHandler::OnCompositeDocumentToPdfDone(
|
||||
base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region));
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::OnCompositePdfPageDone(
|
||||
int page_number,
|
||||
int document_cookie,
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
base::ReadOnlySharedMemoryRegion region) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (status != printing::mojom::PrintCompositor::Status::kSuccess) {
|
||||
LOG(ERROR) << "Compositing pdf failed on page: " << page_number
|
||||
<< " with error: " << status;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::OnDidPreviewPage(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const printing::mojom::DidPreviewPageParams& params,
|
||||
const PrintHostMsg_PreviewIds& ids) {
|
||||
int page_number = params.page_number;
|
||||
const printing::mojom::DidPrintContentParams& content = *params.content;
|
||||
|
||||
if (page_number < printing::FIRST_PAGE_INDEX ||
|
||||
!content.metafile_data_region.IsValid()) {
|
||||
RejectPromise(ids.request_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (printing::IsOopifEnabled()) {
|
||||
auto* client =
|
||||
printing::PrintCompositeClient::FromWebContents(web_contents());
|
||||
DCHECK(client);
|
||||
|
||||
// Use utility process to convert skia metafile to pdf.
|
||||
client->DoCompositePageToPdf(
|
||||
params.document_cookie, render_frame_host, content,
|
||||
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
|
||||
base::BindOnce(&PrintPreviewMessageHandler::OnCompositePdfPageDone,
|
||||
weak_ptr_factory_.GetWeakPtr(), page_number,
|
||||
params.document_cookie, ids),
|
||||
printing::mojom::PrintCompositor::Status::kCompositingFailure,
|
||||
base::ReadOnlySharedMemoryRegion()));
|
||||
}
|
||||
}
|
||||
|
||||
void PrintPreviewMessageHandler::PrintPreviewFailed(int32_t document_cookie,
|
||||
int32_t request_id) {
|
||||
StopWorker(document_cookie);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
struct PrintHostMsg_DidPreviewDocument_Params;
|
||||
struct PrintHostMsg_DidPreviewPage_Params;
|
||||
struct PrintHostMsg_PreviewIds;
|
||||
|
||||
namespace content {
|
||||
@@ -55,6 +57,20 @@ class PrintPreviewMessageHandler
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
base::ReadOnlySharedMemoryRegion region);
|
||||
void OnPrepareForDocumentToPdfDone(
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status);
|
||||
void OnDidPrepareForDocumentToPdf(content::RenderFrameHost* render_frame_host,
|
||||
int document_cookie,
|
||||
const PrintHostMsg_PreviewIds& ids);
|
||||
void OnCompositePdfPageDone(int page_number,
|
||||
int document_cookie,
|
||||
const PrintHostMsg_PreviewIds& ids,
|
||||
printing::mojom::PrintCompositor::Status status,
|
||||
base::ReadOnlySharedMemoryRegion region);
|
||||
void OnDidPreviewPage(content::RenderFrameHost* render_frame_host,
|
||||
const printing::mojom::DidPreviewPageParams& params,
|
||||
const PrintHostMsg_PreviewIds& ids);
|
||||
|
||||
// printing::mojo::PrintPreviewUI:
|
||||
void SetOptionsFromDocument(
|
||||
|
||||
@@ -1662,16 +1662,29 @@ describe('webContents module', () => {
|
||||
expect(width).to.be.greaterThan(height);
|
||||
});
|
||||
|
||||
it('does not crash when called multiple times', async () => {
|
||||
it('does not crash when called multiple times in parallel', async () => {
|
||||
const promises = [];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
promises.push(w.webContents.printToPDF({}));
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
for (const data of results) {
|
||||
expect(data).to.be.an.instanceof(Buffer).that.is.not.empty();
|
||||
}
|
||||
});
|
||||
|
||||
it('does not crash when called multiple times in sequence', async () => {
|
||||
const results = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const result = await w.webContents.printToPDF({});
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
for (const data of results) {
|
||||
expect(data).to.be.an.instanceof(Buffer).that.is.not.empty();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('PictureInPicture video', () => {
|
||||
|
||||
Reference in New Issue
Block a user