refactor: printToPDF should be headless (#33654)

This commit is contained in:
Shelley Vohr 2022-05-31 08:21:25 +02:00 committed by GitHub
parent 0d69067dee
commit 93b39b92b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 648 additions and 414 deletions

View file

@ -25,6 +25,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_view_manager_base.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
#include "chrome/common/pref_names.h"
@ -165,9 +166,10 @@
#if BUILDFLAG(ENABLE_PRINTING)
#include "components/printing/browser/print_manager_utils.h"
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
#include "printing/backend/print_backend.h" // nogncheck
#include "printing/mojom/print.mojom.h" // nogncheck
#include "shell/browser/printing/print_preview_message_handler.h"
#include "printing/page_range.h"
#include "shell/browser/printing/print_view_manager_electron.h"
#if BUILDFLAG(IS_WIN)
@ -919,10 +921,7 @@ void WebContents::InitWithWebContents(
web_contents->SetDelegate(this);
#if BUILDFLAG(ENABLE_PRINTING)
PrintPreviewMessageHandler::CreateForWebContents(web_contents.get());
PrintViewManagerElectron::CreateForWebContents(web_contents.get());
printing::CreateCompositeClientIfNeeded(web_contents.get(),
browser_context->GetUserAgent());
#endif
#if BUILDFLAG(ENABLE_PDF_VIEWER)
@ -2807,14 +2806,87 @@ void WebContents::Print(gin::Arguments* args) {
std::move(callback), device_name, silent));
}
v8::Local<v8::Promise> WebContents::PrintToPDF(base::DictionaryValue settings) {
// Partially duplicated and modified from
// headless/lib/browser/protocol/page_handler.cc;l=41
v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
PrintPreviewMessageHandler::FromWebContents(web_contents())
->PrintToPDF(std::move(settings), std::move(promise));
// This allows us to track headless printing calls.
auto unique_id = settings.GetDict().FindInt(printing::kPreviewRequestID);
auto landscape = settings.GetDict().FindBool("landscape");
auto display_header_footer =
settings.GetDict().FindBool("displayHeaderFooter");
auto print_background = settings.GetDict().FindBool("shouldPrintBackgrounds");
auto scale = settings.GetDict().FindDouble("scale");
auto paper_width = settings.GetDict().FindInt("paperWidth");
auto paper_height = settings.GetDict().FindInt("paperHeight");
auto margin_top = settings.GetDict().FindIntByDottedPath("margins.top");
auto margin_bottom = settings.GetDict().FindIntByDottedPath("margins.bottom");
auto margin_left = settings.GetDict().FindIntByDottedPath("margins.left");
auto margin_right = settings.GetDict().FindIntByDottedPath("margins.right");
auto page_ranges = *settings.GetDict().FindString("pageRanges");
auto header_template = *settings.GetDict().FindString("headerTemplate");
auto footer_template = *settings.GetDict().FindString("footerTemplate");
auto prefer_css_page_size = settings.GetDict().FindBool("preferCSSPageSize");
absl::variant<printing::mojom::PrintPagesParamsPtr, std::string>
print_pages_params = print_to_pdf::GetPrintPagesParams(
web_contents()->GetMainFrame()->GetLastCommittedURL(), landscape,
display_header_footer, print_background, scale, paper_width,
paper_height, margin_top, margin_bottom, margin_left, margin_right,
absl::make_optional(header_template),
absl::make_optional(footer_template), prefer_css_page_size);
if (absl::holds_alternative<std::string>(print_pages_params)) {
auto error = absl::get<std::string>(print_pages_params);
promise.RejectWithErrorMessage("Invalid print parameters: " + error);
return handle;
}
auto* manager = PrintViewManagerElectron::FromWebContents(web_contents());
if (!manager) {
promise.RejectWithErrorMessage("Failed to find print manager");
return handle;
}
auto params = std::move(
absl::get<printing::mojom::PrintPagesParamsPtr>(print_pages_params));
params->params->document_cookie = unique_id.value_or(0);
manager->PrintToPdf(web_contents()->GetMainFrame(), page_ranges,
std::move(params),
base::BindOnce(&WebContents::OnPDFCreated, GetWeakPtr(),
std::move(promise)));
return handle;
}
void WebContents::OnPDFCreated(
gin_helper::Promise<v8::Local<v8::Value>> promise,
PrintViewManagerElectron::PrintResult print_result,
scoped_refptr<base::RefCountedMemory> data) {
if (print_result != PrintViewManagerElectron::PrintResult::PRINT_SUCCESS) {
promise.RejectWithErrorMessage(
"Failed to generate PDF: " +
PrintViewManagerElectron::PrintResultToString(print_result));
return;
}
v8::Isolate* isolate = promise.isolate();
gin_helper::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(
v8::Local<v8::Context>::New(isolate, promise.GetContext()));
v8::Local<v8::Value> buffer =
node::Buffer::Copy(isolate, reinterpret_cast<const char*>(data->front()),
data->size())
.ToLocalChecked();
promise.Resolve(buffer);
}
#endif
void WebContents::AddWorkSpace(gin::Arguments* args,