Browse Source

refactor: enable OOPIF printing to PDF (#36095)

Co-authored-by: Shelley Vohr <[email protected]>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <[email protected]>
trop[bot] 2 years ago
parent
commit
51f6a644e9

+ 2 - 0
chromium_src/BUILD.gn

@@ -232,6 +232,8 @@ static_library("chrome") {
       "//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.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.h",
     ]

+ 4 - 3
shell/browser/api/electron_api_web_contents.cc

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

+ 2 - 1
shell/browser/api/electron_api_web_contents.h

@@ -46,6 +46,7 @@
 #include "ui/gfx/image/image.h"
 
 #if BUILDFLAG(ENABLE_PRINTING)
+#include "components/printing/browser/print_to_pdf/pdf_print_result.h"
 #include "shell/browser/printing/print_view_manager_electron.h"
 #endif
 
@@ -227,7 +228,7 @@ class WebContents : public ExclusiveAccessContext,
   // Print current page as PDF.
   v8::Local<v8::Promise> PrintToPDF(const base::Value& settings);
   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);
 #endif
 

+ 25 - 149
shell/browser/printing/print_view_manager_electron.cc

@@ -60,124 +60,36 @@ void PrintViewManagerElectron::BindPrintManagerHost(
   print_manager->BindReceiver(std::move(receiver), rfh);
 }
 
-// static
-std::string PrintViewManagerElectron::PrintResultToString(PrintResult result) {
-  switch (result) {
-    case kPrintSuccess:
-      return std::string();  // no error message
-    case kPrintFailure:
-      return "Printing failed";
-    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::DidPrintToPdf(
+    int cookie,
+    PrintToPdfCallback callback,
+    print_to_pdf::PdfPrintResult result,
+    scoped_refptr<base::RefCountedMemory> memory) {
+  base::Erase(pdf_jobs_, cookie);
+  std::move(callback).Run(result, memory);
 }
 
 void PrintViewManagerElectron::PrintToPdf(
     content::RenderFrameHost* rfh,
     const std::string& page_ranges,
     printing::mojom::PrintPagesParamsPtr print_pages_params,
-    PrintToPDFCallback callback) {
-  DCHECK(callback);
-
-  if (callback_) {
-    std::move(callback).Run(kSimultaneousPrintActive,
-                            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(
+    PrintToPdfCallback 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);
+
+  print_to_pdf::PdfPrintJob::StartJob(
+      web_contents(), rfh, GetPrintRenderFrame(rfh), page_ranges,
       std::move(print_pages_params),
-      base::BindOnce(&PrintViewManagerElectron::OnDidPrintWithParams,
-                     base::Unretained(this)));
-}
-
-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();
+      base::BindOnce(&PrintViewManagerElectron::DidPrintToPdf,
+                     weak_factory_.GetWeakPtr(), cookie, std::move(callback)));
 }
 
 void PrintViewManagerElectron::GetDefaultPrintSettings(
     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";
     std::move(callback).Run(printing::mojom::PrintParams::New());
   } else {
@@ -188,9 +100,8 @@ void PrintViewManagerElectron::GetDefaultPrintSettings(
 void PrintViewManagerElectron::ScriptedPrint(
     printing::mojom::ScriptedPrintParamsPtr params,
     ScriptedPrintCallback callback) {
-  auto entry =
-      std::find(headless_jobs_.begin(), headless_jobs_.end(), params->cookie);
-  if (entry == headless_jobs_.end()) {
+  auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), params->cookie);
+  if (entry == pdf_jobs_.end()) {
     PrintViewManagerBase::ScriptedPrint(std::move(params), std::move(callback));
     return;
   }
@@ -201,22 +112,13 @@ void PrintViewManagerElectron::ScriptedPrint(
   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)
 void PrintViewManagerElectron::UpdatePrintSettings(
     int32_t cookie,
     base::Value::Dict job_settings,
     UpdatePrintSettingsCallback callback) {
-  auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie);
-  if (entry == headless_jobs_.end()) {
+  auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), cookie);
+  if (entry == pdf_jobs_.end()) {
     PrintViewManagerBase::UpdatePrintSettings(cookie, std::move(job_settings),
                                               std::move(callback));
     return;
@@ -247,40 +149,14 @@ void PrintViewManagerElectron::CheckForCancel(int32_t preview_ui_id,
 }
 #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,
                                                        uint32_t number_pages) {
-  auto entry = std::find(headless_jobs_.begin(), headless_jobs_.end(), cookie);
-  if (entry == headless_jobs_.end()) {
+  auto entry = std::find(pdf_jobs_.begin(), pdf_jobs_.end(), cookie);
+  if (entry == pdf_jobs_.end()) {
     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);
 
 }  // namespace electron

+ 10 - 35
shell/browser/printing/print_view_manager_electron.h

@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "build/build_config.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 "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -21,29 +22,12 @@
 
 namespace electron {
 
+using PrintToPdfCallback = print_to_pdf::PdfPrintJob::PrintToPdfCallback;
+
 class PrintViewManagerElectron
     : public printing::PrintViewManagerBase,
       public content::WebContentsUserData<PrintViewManagerElectron> {
  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(const PrintViewManagerElectron&) = delete;
@@ -54,30 +38,26 @@ class PrintViewManagerElectron
           receiver,
       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,
                   const std::string& page_ranges,
                   printing::mojom::PrintPagesParamsPtr print_page_params,
-                  PrintToPDFCallback callback);
+                  PrintToPdfCallback callback);
 
  private:
   friend class content::WebContentsUserData<PrintViewManagerElectron>;
 
   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:
   void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
   void GetDefaultPrintSettings(
       GetDefaultPrintSettingsCallback callback) override;
   void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params,
                      ScriptedPrintCallback callback) override;
-  void ShowInvalidPrinterSettingsError() override;
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   void UpdatePrintSettings(int32_t cookie,
                            base::Value::Dict job_settings,
@@ -91,14 +71,9 @@ class PrintViewManagerElectron
                       int32_t request_id,
                       CheckForCancelCallback callback) override;
 #endif
+  std::vector<int32_t> pdf_jobs_;
 
-  void FailJob(PrintResult result);
-  void Reset();
-
-  raw_ptr<content::RenderFrameHost> printing_rfh_ = nullptr;
-  PrintToPDFCallback callback_;
-  std::string data_;
-  std::vector<int32_t> headless_jobs_;
+  base::WeakPtrFactory<PrintViewManagerElectron> weak_factory_{this};
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };