chromium/chrome/browser/printing/print_job_worker_oop.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_job_worker_oop.h"

#include <optional>
#include <utility>

#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/printing/oop_features.h"
#include "chrome/browser/printing/print_backend_service_manager.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
#include "components/device_event_log/device_event_log.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_routing_id.h"
#include "printing/buildflags/buildflags.h"
#include "printing/metafile.h"
#include "printing/printed_document.h"

#if BUILDFLAG(IS_WIN)
#include "printing/printed_page_win.h"
#endif

BrowserThread;

namespace printing {

namespace {

// Enumeration of printing events when submitting a job to a print driver.
// This must stay in sync with the corresponding histogram in `histograms.xml`.
// These values are persisted to logs.  Entries should not be renumbered and
// numeric values should never be reused.
enum class PrintOopResult {};

constexpr char kPrintOopPrintResultHistogramName[] =;

}  // namespace

PrintJobWorkerOop::PrintJobWorkerOop(
    std::unique_ptr<PrintingContext::Delegate> printing_context_delegate,
    std::unique_ptr<PrintingContext> printing_context,
    std::optional<PrintBackendServiceManager::ClientId> client_id,
    std::optional<PrintBackendServiceManager::ContextId> context_id,
    PrintJob* print_job,
    bool print_from_system_dialog)
    :{}

PrintJobWorkerOop::PrintJobWorkerOop(
    std::unique_ptr<PrintingContext::Delegate> printing_context_delegate,
    std::unique_ptr<PrintingContext> printing_context,
    std::optional<PrintBackendServiceManager::ClientId> client_id,
    std::optional<PrintBackendServiceManager::ContextId> context_id,
    PrintJob* print_job,
    bool print_from_system_dialog,
    bool simulate_spooling_memory_errors)
    :{}

PrintJobWorkerOop::~PrintJobWorkerOop() {}

void PrintJobWorkerOop::StartPrinting(PrintedDocument* new_document) {}

void PrintJobWorkerOop::Cancel() {}

#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
void PrintJobWorkerOop::CleanupAfterContentAnalysisDenial() {}
#endif

void PrintJobWorkerOop::OnDidStartPrinting(mojom::ResultCode result,
                                           int job_id) {}

#if BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::OnDidRenderPrintedPage(uint32_t page_index,
                                               mojom::ResultCode result) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  if (result != mojom::ResultCode::kSuccess) {
    // Once an error happens during rendering, there could be multiple calls
    // to here as the queue of sent pages all return back with error.
    PRINTER_LOG(ERROR)
        << "Error rendering printed page via service for document "
        << document_oop_->cookie() << ": " << result;
    NotifyFailure(result);
    return;
  }
  scoped_refptr<PrintedPage> page = document_oop_->GetPage(page_index);
  if (!page) {
    PRINTER_LOG(ERROR) << "Unable to get page " << page_index
                       << " via service for document "
                       << document_oop_->cookie();
    NotifyFailure(mojom::ResultCode::kFailed);
    return;
  }
  VLOG(1) << "Rendered printed page via service for document "
          << document_oop_->cookie() << " page " << page_index;

  // Signal everyone that the page is printed.
  print_job()->PostTask(FROM_HERE,
                        base::BindOnce(&PrintJob::OnPageDone, print_job(),
                                       base::RetainedRef(page)));

  ++pages_printed_count_;
  if (pages_printed_count_ == document_oop_->expected_page_count()) {
    // The last page has printed, can proceed to document done processing.
    VLOG(1) << "All pages printed for document";
    SendDocumentDone();
  }
}
#endif  // BUILDFLAG(IS_WIN)

void PrintJobWorkerOop::OnDidRenderPrintedDocument(mojom::ResultCode result) {}

void PrintJobWorkerOop::OnDidDocumentDone(int job_id,
                                          mojom::ResultCode result) {}

void PrintJobWorkerOop::OnDidCancel(scoped_refptr<PrintJob> job,
                                    mojom::ResultCode cancel_reason) {}

#if BUILDFLAG(IS_WIN)
bool PrintJobWorkerOop::SpoolPage(PrintedPage* page) {
  DCHECK(task_runner()->RunsTasksInCurrentSequence());
  DCHECK_NE(page_number(), PageNumber::npos());

#if !defined(NDEBUG)
  DCHECK(document()->IsPageInList(*page));
#endif

  const MetafilePlayer* metafile = page->metafile();
  DCHECK(metafile);
  base::MappedReadOnlyRegion region_mapping =
      metafile->GetDataAsSharedMemoryRegion();
  if (simulate_spooling_memory_errors_ || !region_mapping.IsValid()) {
    PRINTER_LOG(ERROR)
        << "Spooling page via service failed due to shared memory error.";
    content::GetUIThreadTaskRunner({})->PostTask(
        FROM_HERE, base::BindOnce(&PrintJobWorkerOop::NotifyFailure,
                                  ui_weak_factory_.GetWeakPtr(),
                                  mojom::ResultCode::kFailed));
    return false;
  }

  VLOG(1) << "Spooling page " << page_number() << " to print via service";
  content::GetUIThreadTaskRunner({})->PostTask(
      FROM_HERE,
      base::BindOnce(&PrintJobWorkerOop::SendRenderPrintedPage,
                     ui_weak_factory_.GetWeakPtr(), base::RetainedRef(page),
                     metafile->GetDataType(),
                     std::move(region_mapping.region)));
  return true;
}
#endif  // BUILDFLAG(IS_WIN)

bool PrintJobWorkerOop::SpoolDocument() {}

void PrintJobWorkerOop::OnDocumentDone() {}

void PrintJobWorkerOop::FinishDocumentDone(int job_id) {}

void PrintJobWorkerOop::OnCancel() {}

void PrintJobWorkerOop::OnFailure() {}

void PrintJobWorkerOop::UnregisterServiceManagerClient() {}

bool PrintJobWorkerOop::TryRestartPrinting() {}

void PrintJobWorkerOop::NotifyFailure(mojom::ResultCode result) {}

void PrintJobWorkerOop::SendEstablishPrintingContext() {}

void PrintJobWorkerOop::SendStartPrinting(const std::string& device_name,
                                          const std::u16string& document_name) {}

#if BUILDFLAG(IS_WIN)
void PrintJobWorkerOop::SendRenderPrintedPage(
    const PrintedPage* page,
    mojom::MetafileDataType page_data_type,
    base::ReadOnlySharedMemoryRegion serialized_page_data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  // Page numbers are 0-based for the printing context.
  const uint32_t page_index = page->page_number() - 1;
  const int32_t document_cookie = document_oop_->cookie();
  if (print_cancel_requested_) {
    VLOG(1) << "Dropping page " << page_index << " of document "
            << document_cookie << " to `" << device_name_
            << "` because job was canceled";
    return;
  }

  VLOG(1) << "Sending page " << page_index << " of document " << document_cookie
          << " to `" << device_name_ << "` for printing";
  PrintBackendServiceManager& service_mgr =
      PrintBackendServiceManager::GetInstance();
  service_mgr.RenderPrintedPage(
      *service_manager_client_id_, device_name_, document_cookie, *page,
      page_data_type, std::move(serialized_page_data),
      base::BindOnce(&PrintJobWorkerOop::OnDidRenderPrintedPage,
                     ui_weak_factory_.GetWeakPtr(), page_index));
}
#endif  // BUILDFLAG(IS_WIN)

void PrintJobWorkerOop::SendRenderPrintedDocument(
    mojom::MetafileDataType data_type,
    base::ReadOnlySharedMemoryRegion serialized_data) {}

void PrintJobWorkerOop::SendDocumentDone() {}

void PrintJobWorkerOop::SendCancel(base::OnceClosure on_did_cancel_callback) {}

}  // namespace printing