1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// Copyright 2023 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_controller.h"
#include <memory>
#include <string>
#include "base/check_op.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/printer_query.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_routing_id.h"
#include "printing/metafile_skia.h"
#include "printing/print_settings.h"
#include "printing/printed_document.h"
namespace printing {
namespace {
void OnPrintSettingsApplied(scoped_refptr<PrintJob> print_job,
std::unique_ptr<MetafileSkia> pdf,
std::unique_ptr<PrinterQuery> query,
uint32_t page_count,
PrintJob::Source source,
const std::string& source_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
CHECK_GT(page_count, 0U);
std::u16string title = query->settings().title();
print_job->Initialize(std::move(query), title, page_count);
print_job->SetSource(source, source_id);
print_job->document()->SetDocument(std::move(pdf));
print_job->StartPrinting();
}
} // namespace
class PendingJob;
// Keeps track of pending jobs and removes them from the storage once
// processed.
class PrintJobController::PendingJobStorage {
public:
PendingJobStorage() = default;
~PendingJobStorage() = default;
PendingJobStorage(const PendingJobStorage&) = delete;
PendingJobStorage& operator=(const PendingJobStorage&) = delete;
void StartWatchingPrintJob(scoped_refptr<PrintJob> print_job,
PrintJobCreatedCallback callback);
void DeletePendingJobPlease(PendingJob* pending_job);
private:
using PendingJobs =
base::flat_set<std::unique_ptr<PendingJob>, base::UniquePtrComparator>;
PendingJobs pending_jobs_;
};
// Observes the given `print_job` and invokes `callback` once the job signals
// OnDocDone() or OnFailed().
class PendingJob : public PrintJob::Observer {
public:
PendingJob(PrintJobController::PendingJobStorage* storage,
scoped_refptr<PrintJob> print_job,
PrintJobController::PrintJobCreatedCallback callback);
~PendingJob() override;
PendingJob(const PendingJob&) = delete;
PendingJob& operator=(const PendingJob&) = delete;
void OnDocDone(int job_id, PrintedDocument* document) override;
void OnFailed() override;
private:
// `storage_` owns `this`.
const raw_ref<PrintJobController::PendingJobStorage> storage_;
scoped_refptr<PrintJob> print_job_;
PrintJobController::PrintJobCreatedCallback callback_;
};
void PrintJobController::PendingJobStorage::StartWatchingPrintJob(
scoped_refptr<PrintJob> print_job,
PrintJobCreatedCallback callback) {
auto pending_job = std::make_unique<PendingJob>(this, std::move(print_job),
std::move(callback));
pending_jobs_.insert(std::move(pending_job));
}
void PrintJobController::PendingJobStorage::DeletePendingJobPlease(
PendingJob* pending_job) {
pending_jobs_.erase(pending_job);
}
PrintJobController::PrintJobController()
: pending_job_storage_(std::make_unique<PendingJobStorage>()) {}
PrintJobController::~PrintJobController() = default;
void PrintJobController::StartWatchingPrintJob(
scoped_refptr<PrintJob> print_job,
PrintJobCreatedCallback callback) {
pending_job_storage_->StartWatchingPrintJob(std::move(print_job),
std::move(callback));
}
PendingJob::PendingJob(PrintJobController::PendingJobStorage* storage,
scoped_refptr<PrintJob> print_job,
PrintJobController::PrintJobCreatedCallback callback)
: storage_(*storage),
print_job_(std::move(print_job)),
callback_(std::move(callback)) {
print_job_->AddObserver(*this);
}
PendingJob::~PendingJob() {
print_job_->RemoveObserver(*this);
}
void PendingJob::OnDocDone(int job_id, PrintedDocument* document) {
auto document_ref = raw_ref<PrintedDocument>::from_ptr(document);
std::move(callback_).Run(PrintJobCreatedInfo{job_id, document_ref});
storage_->DeletePendingJobPlease(this);
}
void PendingJob::OnFailed() {
std::move(callback_).Run(std::nullopt);
storage_->DeletePendingJobPlease(this);
}
void PrintJobController::CreatePrintJob(std::unique_ptr<MetafileSkia> pdf,
std::unique_ptr<PrintSettings> settings,
uint32_t page_count,
PrintJob::Source source,
const std::string& source_id,
PrintJobCreatedCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto print_job =
base::MakeRefCounted<PrintJob>(g_browser_process->print_job_manager());
StartWatchingPrintJob(print_job, std::move(callback));
auto query = PrinterQuery::Create(content::GlobalRenderFrameHostId());
auto* query_ptr = query.get();
query_ptr->SetSettingsFromPOD(
std::move(settings),
base::BindOnce(&OnPrintSettingsApplied, print_job, std::move(pdf),
std::move(query), page_count, source, source_id));
}
} // namespace printing
|