refactor: enable OOPIF printing to PDF (#36051)

This commit is contained in:
Shelley Vohr 2022-10-20 11:30:40 -07:00 committed by GitHub
parent 289bdbe4bc
commit 7921fec761
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 187 deletions

View file

@ -232,6 +232,8 @@ static_library("chrome") {
"//chrome/browser/printing/printing_service.h", "//chrome/browser/printing/printing_service.h",
"//components/printing/browser/print_to_pdf/pdf_print_job.cc", "//components/printing/browser/print_to_pdf/pdf_print_job.cc",
"//components/printing/browser/print_to_pdf/pdf_print_job.h", "//components/printing/browser/print_to_pdf/pdf_print_job.h",
"//components/printing/browser/print_to_pdf/pdf_print_result.cc",
"//components/printing/browser/print_to_pdf/pdf_print_result.h",
"//components/printing/browser/print_to_pdf/pdf_print_utils.cc", "//components/printing/browser/print_to_pdf/pdf_print_utils.cc",
"//components/printing/browser/print_to_pdf/pdf_print_utils.h", "//components/printing/browser/print_to_pdf/pdf_print_utils.h",
] ]

View file

@ -172,6 +172,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_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_utils.h" #include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
#include "printing/backend/print_backend.h" // nogncheck #include "printing/backend/print_backend.h" // nogncheck
#include "printing/mojom/print.mojom.h" // nogncheck #include "printing/mojom/print.mojom.h" // nogncheck
@ -2902,12 +2903,12 @@ v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) {
void WebContents::OnPDFCreated( void WebContents::OnPDFCreated(
gin_helper::Promise<v8::Local<v8::Value>> promise, gin_helper::Promise<v8::Local<v8::Value>> promise,
PrintViewManagerElectron::PrintResult print_result, print_to_pdf::PdfPrintResult print_result,
scoped_refptr<base::RefCountedMemory> data) { scoped_refptr<base::RefCountedMemory> data) {
if (print_result != PrintViewManagerElectron::PrintResult::kPrintSuccess) { if (print_result != print_to_pdf::PdfPrintResult::kPrintSuccess) {
promise.RejectWithErrorMessage( promise.RejectWithErrorMessage(
"Failed to generate PDF: " + "Failed to generate PDF: " +
PrintViewManagerElectron::PrintResultToString(print_result)); print_to_pdf::PdfPrintResultToString(print_result));
return; return;
} }

View file

@ -46,6 +46,7 @@
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#if BUILDFLAG(ENABLE_PRINTING) #if BUILDFLAG(ENABLE_PRINTING)
#include "components/printing/browser/print_to_pdf/pdf_print_result.h"
#include "shell/browser/printing/print_view_manager_electron.h" #include "shell/browser/printing/print_view_manager_electron.h"
#endif #endif
@ -227,7 +228,7 @@ class WebContents : public ExclusiveAccessContext,
// Print current page as PDF. // Print current page as PDF.
v8::Local<v8::Promise> PrintToPDF(const base::Value& settings); v8::Local<v8::Promise> PrintToPDF(const base::Value& settings);
void OnPDFCreated(gin_helper::Promise<v8::Local<v8::Value>> promise, void OnPDFCreated(gin_helper::Promise<v8::Local<v8::Value>> promise,
PrintViewManagerElectron::PrintResult print_result, print_to_pdf::PdfPrintResult print_result,
scoped_refptr<base::RefCountedMemory> data); scoped_refptr<base::RefCountedMemory> data);
#endif #endif

View file

@ -60,124 +60,36 @@ void PrintViewManagerElectron::BindPrintManagerHost(
print_manager->BindReceiver(std::move(receiver), rfh); print_manager->BindReceiver(std::move(receiver), rfh);
} }
// static void PrintViewManagerElectron::DidPrintToPdf(
std::string PrintViewManagerElectron::PrintResultToString(PrintResult result) { int cookie,
switch (result) { PrintToPdfCallback callback,
case kPrintSuccess: print_to_pdf::PdfPrintResult result,
return std::string(); // no error message scoped_refptr<base::RefCountedMemory> memory) {
case kPrintFailure: base::Erase(pdf_jobs_, cookie);
return "Printing failed"; std::move(callback).Run(result, memory);
case kInvalidPrinterSettings:
return "Show invalid printer settings error";
case kInvalidMemoryHandle:
return "Invalid memory handle";
case kMetafileMapError:
return "Map to shared memory error";
case kMetafileInvalidHeader:
return "Invalid metafile header";
case kMetafileGetDataError:
return "Get data from metafile error";
case kSimultaneousPrintActive:
return "The previous printing job hasn't finished";
case kPageRangeSyntaxError:
return "Page range syntax error";
case kPageRangeInvalidRange:
return "Page range is invalid (start > end)";
case kPageCountExceeded:
return "Page range exceeds page count";
case kPrintingInProgress:
return "Page is already being printed";
default:
NOTREACHED();
return "Unknown PrintResult";
}
} }
void PrintViewManagerElectron::PrintToPdf( void PrintViewManagerElectron::PrintToPdf(
content::RenderFrameHost* rfh, content::RenderFrameHost* rfh,
const std::string& page_ranges, const std::string& page_ranges,
printing::mojom::PrintPagesParamsPtr print_pages_params, printing::mojom::PrintPagesParamsPtr print_pages_params,
PrintToPDFCallback callback) { PrintToPdfCallback callback) {
DCHECK(callback); // Store cookie in order to track job uniqueness and differentiate
// between regular and headless print jobs.
int cookie = print_pages_params->params->document_cookie;
pdf_jobs_.emplace_back(cookie);
if (callback_) { print_to_pdf::PdfPrintJob::StartJob(
std::move(callback).Run(kSimultaneousPrintActive, web_contents(), rfh, GetPrintRenderFrame(rfh), page_ranges,
base::MakeRefCounted<base::RefCountedString>());
return;
}
if (!rfh->IsRenderFrameLive()) {
std::move(callback).Run(kPrintFailure,
base::MakeRefCounted<base::RefCountedString>());
return;
}
absl::variant<printing::PageRanges, print_to_pdf::PdfPrintResult>
parsed_ranges = print_to_pdf::TextPageRangesToPageRanges(page_ranges);
if (absl::holds_alternative<print_to_pdf::PdfPrintResult>(parsed_ranges)) {
DCHECK_NE(absl::get<print_to_pdf::PdfPrintResult>(parsed_ranges),
print_to_pdf::PdfPrintResult::kPrintSuccess);
std::move(callback).Run(
static_cast<PrintResult>(
absl::get<print_to_pdf::PdfPrintResult>(parsed_ranges)),
base::MakeRefCounted<base::RefCountedString>());
return;
}
printing_rfh_ = rfh;
print_pages_params->pages = absl::get<printing::PageRanges>(parsed_ranges);
headless_jobs_.emplace_back(print_pages_params->params->document_cookie);
callback_ = std::move(callback);
// There is no need for a weak pointer here since the mojo proxy is held
// in the base class. If we're gone, mojo will discard the callback.
GetPrintRenderFrame(rfh)->PrintWithParams(
std::move(print_pages_params), std::move(print_pages_params),
base::BindOnce(&PrintViewManagerElectron::OnDidPrintWithParams, base::BindOnce(&PrintViewManagerElectron::DidPrintToPdf,
base::Unretained(this))); weak_factory_.GetWeakPtr(), cookie, std::move(callback)));
}
void PrintViewManagerElectron::OnDidPrintWithParams(
printing::mojom::PrintWithParamsResultPtr result) {
if (result->is_failure_reason()) {
switch (result->get_failure_reason()) {
case printing::mojom::PrintFailureReason::kGeneralFailure:
FailJob(kPrintFailure);
return;
case printing::mojom::PrintFailureReason::kInvalidPageRange:
FailJob(kPageCountExceeded);
return;
case printing::mojom::PrintFailureReason::kPrintingInProgress:
FailJob(kPrintingInProgress);
return;
}
}
printing::mojom::DidPrintDocumentParamsPtr& params = result->get_params();
auto& content = *params->content;
if (!content.metafile_data_region.IsValid()) {
FailJob(kInvalidMemoryHandle);
return;
}
base::ReadOnlySharedMemoryMapping map = content.metafile_data_region.Map();
if (!map.IsValid()) {
FailJob(kMetafileMapError);
return;
}
std::string data =
std::string(static_cast<const char*>(map.memory()), map.size());
std::move(callback_).Run(kPrintSuccess,
base::RefCountedString::TakeString(&data));
base::Erase(headless_jobs_, params->document_cookie);
Reset();
} }
void PrintViewManagerElectron::GetDefaultPrintSettings( void PrintViewManagerElectron::GetDefaultPrintSettings(
GetDefaultPrintSettingsCallback callback) { GetDefaultPrintSettingsCallback callback) {
if (printing_rfh_) { // This isn't ideal, but we're not able to access the document cookie here.
if (pdf_jobs_.size() > 0) {
LOG(ERROR) << "Scripted print is not supported"; LOG(ERROR) << "Scripted print is not supported";
std::move(callback).Run(printing::mojom::PrintParams::New()); std::move(callback).Run(printing::mojom::PrintParams::New());
} else { } else {
@ -188,9 +100,8 @@ void PrintViewManagerElectron::GetDefaultPrintSettings(
void PrintViewManagerElectron::ScriptedPrint( void PrintViewManagerElectron::ScriptedPrint(
printing::mojom::ScriptedPrintParamsPtr params, printing::mojom::ScriptedPrintParamsPtr params,
ScriptedPrintCallback callback) { ScriptedPrintCallback callback) {
auto entry = auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), params->cookie);
std::find(headless_jobs_.begin(), headless_jobs_.end(), params->cookie); if (entry == pdf_jobs_.end()) {
if (entry == headless_jobs_.end()) {
PrintViewManagerBase::ScriptedPrint(std::move(params), std::move(callback)); PrintViewManagerBase::ScriptedPrint(std::move(params), std::move(callback));
return; return;
} }
@ -201,22 +112,13 @@ void PrintViewManagerElectron::ScriptedPrint(
std::move(callback).Run(std::move(default_param), /*cancelled*/ false); std::move(callback).Run(std::move(default_param), /*cancelled*/ false);
} }
void PrintViewManagerElectron::ShowInvalidPrinterSettingsError() {
if (headless_jobs_.size() == 0) {
PrintViewManagerBase::ShowInvalidPrinterSettingsError();
return;
}
FailJob(kInvalidPrinterSettings);
}
#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void PrintViewManagerElectron::UpdatePrintSettings( void PrintViewManagerElectron::UpdatePrintSettings(
int32_t cookie, int32_t cookie,
base::Value::Dict job_settings, base::Value::Dict job_settings,
UpdatePrintSettingsCallback callback) { UpdatePrintSettingsCallback callback) {
auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie); auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), cookie);
if (entry == headless_jobs_.end()) { if (entry == pdf_jobs_.end()) {
PrintViewManagerBase::UpdatePrintSettings(cookie, std::move(job_settings), PrintViewManagerBase::UpdatePrintSettings(cookie, std::move(job_settings),
std::move(callback)); std::move(callback));
return; return;
@ -247,40 +149,14 @@ void PrintViewManagerElectron::CheckForCancel(int32_t preview_ui_id,
} }
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
void PrintViewManagerElectron::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
PrintViewManagerBase::RenderFrameDeleted(render_frame_host);
if (printing_rfh_ != render_frame_host)
return;
FailJob(kPrintFailure);
}
void PrintViewManagerElectron::DidGetPrintedPagesCount(int32_t cookie, void PrintViewManagerElectron::DidGetPrintedPagesCount(int32_t cookie,
uint32_t number_pages) { uint32_t number_pages) {
auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie); auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), cookie);
if (entry == headless_jobs_.end()) { if (entry == pdf_jobs_.end()) {
PrintViewManagerBase::DidGetPrintedPagesCount(cookie, number_pages); PrintViewManagerBase::DidGetPrintedPagesCount(cookie, number_pages);
} }
} }
void PrintViewManagerElectron::Reset() {
printing_rfh_ = nullptr;
callback_.Reset();
data_.clear();
}
void PrintViewManagerElectron::FailJob(PrintResult result) {
DCHECK_NE(result, kPrintSuccess);
if (callback_) {
std::move(callback_).Run(result,
base::MakeRefCounted<base::RefCountedString>());
}
Reset();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerElectron); WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerElectron);
} // namespace electron } // namespace electron

View file

@ -13,6 +13,7 @@
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/printing/print_view_manager_base.h" #include "chrome/browser/printing/print_view_manager_base.h"
#include "components/printing/browser/print_to_pdf/pdf_print_job.h"
#include "components/printing/common/print.mojom.h" #include "components/printing/common/print.mojom.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
@ -21,29 +22,12 @@
namespace electron { namespace electron {
using PrintToPdfCallback = print_to_pdf::PdfPrintJob::PrintToPdfCallback;
class PrintViewManagerElectron class PrintViewManagerElectron
: public printing::PrintViewManagerBase, : public printing::PrintViewManagerBase,
public content::WebContentsUserData<PrintViewManagerElectron> { public content::WebContentsUserData<PrintViewManagerElectron> {
public: public:
enum PrintResult {
kPrintSuccess,
kPrintFailure,
kInvalidPrinterSettings,
kInvalidMemoryHandle,
kMetafileMapError,
kMetafileInvalidHeader,
kMetafileGetDataError,
kSimultaneousPrintActive,
kPageRangeSyntaxError,
kPageRangeInvalidRange,
kPageCountExceeded,
kPrintingInProgress
};
using PrintToPDFCallback =
base::OnceCallback<void(PrintResult,
scoped_refptr<base::RefCountedMemory>)>;
~PrintViewManagerElectron() override; ~PrintViewManagerElectron() override;
PrintViewManagerElectron(const PrintViewManagerElectron&) = delete; PrintViewManagerElectron(const PrintViewManagerElectron&) = delete;
@ -54,30 +38,26 @@ class PrintViewManagerElectron
receiver, receiver,
content::RenderFrameHost* rfh); content::RenderFrameHost* rfh);
static std::string PrintResultToString(PrintResult result); void DidPrintToPdf(int cookie,
PrintToPdfCallback callback,
print_to_pdf::PdfPrintResult result,
scoped_refptr<base::RefCountedMemory> memory);
void PrintToPdf(content::RenderFrameHost* rfh, void PrintToPdf(content::RenderFrameHost* rfh,
const std::string& page_ranges, const std::string& page_ranges,
printing::mojom::PrintPagesParamsPtr print_page_params, printing::mojom::PrintPagesParamsPtr print_page_params,
PrintToPDFCallback callback); PrintToPdfCallback callback);
private: private:
friend class content::WebContentsUserData<PrintViewManagerElectron>; friend class content::WebContentsUserData<PrintViewManagerElectron>;
explicit PrintViewManagerElectron(content::WebContents* web_contents); explicit PrintViewManagerElectron(content::WebContents* web_contents);
void OnDidPrintWithParams(printing::mojom::PrintWithParamsResultPtr result);
// WebContentsObserver overrides (via PrintManager):
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
// printing::mojom::PrintManagerHost: // printing::mojom::PrintManagerHost:
void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override; void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
void GetDefaultPrintSettings( void GetDefaultPrintSettings(
GetDefaultPrintSettingsCallback callback) override; GetDefaultPrintSettingsCallback callback) override;
void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params, void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params,
ScriptedPrintCallback callback) override; ScriptedPrintCallback callback) override;
void ShowInvalidPrinterSettingsError() override;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void UpdatePrintSettings(int32_t cookie, void UpdatePrintSettings(int32_t cookie,
base::Value::Dict job_settings, base::Value::Dict job_settings,
@ -91,14 +71,9 @@ class PrintViewManagerElectron
int32_t request_id, int32_t request_id,
CheckForCancelCallback callback) override; CheckForCancelCallback callback) override;
#endif #endif
std::vector<int32_t> pdf_jobs_;
void FailJob(PrintResult result); base::WeakPtrFactory<PrintViewManagerElectron> weak_factory_{this};
void Reset();
raw_ptr<content::RenderFrameHost> printing_rfh_ = nullptr;
PrintToPDFCallback callback_;
std::string data_;
std::vector<int32_t> headless_jobs_;
WEB_CONTENTS_USER_DATA_KEY_DECL(); WEB_CONTENTS_USER_DATA_KEY_DECL();
}; };