blob: 87f1bbb672d50d985a4e7df74fc57612fb425411 [file] [log] [blame]
// 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.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OOP_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OOP_H_
#include <memory>
#include <optional>
#include <string>
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "chrome/browser/printing/print_backend_service_manager.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom.h"
#if !BUILDFLAG(ENABLE_OOP_PRINTING)
#error "OOP printing must be enabled"
#endif
namespace printing {
class PrintedDocument;
// Worker thread code. It manages the PrintingContext and offloads all system
// driver interactions to the Print Backend service. This is the object that
// generates most NOTIFY_PRINT_JOB_EVENT notifications, but they are generated
// through a NotificationTask task to be executed from the right thread, the UI
// thread. PrintJob always outlives its worker instance.
class PrintJobWorkerOop : public PrintJobWorker {
public:
// The `client_id` specifies the print document client registered with
// `PrintBackendServiceManager`. `PrintJobWorkerOop` takes responsibility
// for unregistering the client ID with `PrintBackendServiceManager` once
// printing is completed.
// The `client_id` can be empty. This can occur for placeholder print jobs
// that don't actually initiate printing such as during content analysis.
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(const PrintJobWorkerOop&) = delete;
PrintJobWorkerOop& operator=(const PrintJobWorkerOop&) = delete;
~PrintJobWorkerOop() override;
// `PrintJobWorker` overrides.
void StartPrinting(PrintedDocument* new_document) override;
void Cancel() override;
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
void CleanupAfterContentAnalysisDenial() override;
#endif
protected:
// For testing.
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);
// Local callback wrappers for Print Backend Service mojom call. Virtual to
// support testing.
virtual void OnDidStartPrinting(mojom::ResultCode result, int job_id);
#if BUILDFLAG(IS_WIN)
virtual void OnDidRenderPrintedPage(uint32_t page_index,
mojom::ResultCode result);
#endif
virtual void OnDidRenderPrintedDocument(mojom::ResultCode result);
virtual void OnDidDocumentDone(int job_id, mojom::ResultCode result);
virtual void OnDidCancel(scoped_refptr<PrintJob> job,
mojom::ResultCode cancel_reason);
// `PrintJobWorker` overrides.
#if BUILDFLAG(IS_WIN)
bool SpoolPage(PrintedPage* page) override;
#endif
bool SpoolDocument() override;
void OnDocumentDone() override;
void FinishDocumentDone(int job_id) override;
void OnCancel() override;
void OnFailure() override;
private:
// Support to unregister this worker as a printing client. Applicable any
// time a print job finishes, is canceled, or needs to be restarted.
void UnregisterServiceManagerClient();
// Helper function for restarting a print job after error.
bool TryRestartPrinting();
// Initiate failure handling, including notification to the user.
void NotifyFailure(mojom::ResultCode result);
// Mojo support to send messages from UI thread.
void SendEstablishPrintingContext();
void SendStartPrinting(const std::string& device_name,
const std::u16string& document_name);
#if BUILDFLAG(IS_WIN)
void SendRenderPrintedPage(
const PrintedPage* page,
mojom::MetafileDataType page_data_type,
base::ReadOnlySharedMemoryRegion serialized_page_data);
#endif // BUILDFLAG(IS_WIN)
void SendRenderPrintedDocument(
mojom::MetafileDataType data_type,
base::ReadOnlySharedMemoryRegion serialized_data);
void SendDocumentDone();
void SendCancel(base::OnceClosure on_did_cancel_callback);
// Used to test spooling memory error handling.
const bool simulate_spooling_memory_errors_;
// Client ID with the print backend service manager for this print job.
// Used only from UI thread.
std::optional<PrintBackendServiceManager::ClientId>
service_manager_client_id_;
// The printing context identifier related to this print job.
// Used only from UI thread.
std::optional<PrintBackendServiceManager::ContextId> printing_context_id_;
// The device name used when printing via a service. Used only from the UI
// thread.
std::string device_name_;
// The processed name of the document being printed. Used only from the UI
// thread.
std::u16string document_name_;
// The printed document. Only has read-only access. This reference separate
// from the one already in the base class provides a guarantee that the
// `PrintedDocument` will persist until OOP processing completes, even if
// the `PrintJob` should drop its reference as part of failure/cancel
// processing. Named differently than base (even though both are private)
// to avoid any potential confusion between them.
// Once set at the start of printing on the worker thread, it is only
// referenced thereafter from the UI thread. UI thread accesses only occur
// once the interactions with the Print Backend service occur as a result of
// starting to print the job. Any document access from worker thread happens
// by methods in base class, which use the base `document_` field.
scoped_refptr<PrintedDocument> document_oop_;
// Indicates if the print job was initiated from the print system dialog.
const bool print_from_system_dialog_;
#if BUILDFLAG(IS_WIN)
// Number of pages that have completed printing.
uint32_t pages_printed_count_ = 0;
#endif
// Tracks if a restart for printing has already been attempted.
bool print_retried_ = false;
// Tracks if the service has already been requested to cancel printing the
// document
bool print_cancel_requested_ = false;
// Weak pointers have flags that get bound to the thread where they are
// checked, so it is necessary to use different factories when getting a
// weak pointer to send to the worker task runner vs. to the UI thread.
base::WeakPtrFactory<PrintJobWorkerOop> worker_weak_factory_{this};
base::WeakPtrFactory<PrintJobWorkerOop> ui_weak_factory_{this};
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OOP_H_