#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 {
enum class PrintOopResult { … };
constexpr char kPrintOopPrintResultHistogramName[] = …;
}
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) {
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;
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()) {
VLOG(1) << "All pages printed for document";
SendDocumentDone();
}
}
#endif
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
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);
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
void PrintJobWorkerOop::SendRenderPrintedDocument(
mojom::MetafileDataType data_type,
base::ReadOnlySharedMemoryRegion serialized_data) { … }
void PrintJobWorkerOop::SendDocumentDone() { … }
void PrintJobWorkerOop::SendCancel(base::OnceClosure on_did_cancel_callback) { … }
}