[go: nahoru, domu]

blob: cc69527e6596f2b34dc7e156426f743acdeb1763 [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2020 The Chromium Authors
Alan Screen65304d52020-10-29 16:42:222// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/services/printing/print_backend_service_impl.h"
6
Alan Screen366ce3e2021-06-16 23:26:047#include <memory>
Alan Screen65304d52020-10-29 16:42:228#include <string>
9#include <utility>
Alan Screen2166ab12021-09-01 23:09:2510#include <vector>
Alan Screen65304d52020-10-29 16:42:2211
Alan Screen7a30b042022-09-19 17:51:2412#include "base/check.h"
Victor Hugo Vianna Silva08f4b002022-01-17 13:20:0413#include "base/containers/adapters.h"
Alan Screen65304d52020-10-29 16:42:2214#include "base/logging.h"
Keishi Hattorie175ac52022-06-07 06:24:5715#include "base/memory/raw_ptr.h"
Alan Screen65304d52020-10-29 16:42:2216#include "base/notreached.h"
Peter Kasting73f230d02022-09-17 22:29:3017#include "base/ranges/algorithm.h"
Sean Mahere672a662023-01-09 21:42:2818#include "base/task/sequenced_task_runner.h"
Alan Screen2166ab12021-09-01 23:09:2519#include "base/task/task_traits.h"
20#include "base/task/thread_pool.h"
Alan Screencb6421f2021-12-09 21:54:1821#include "base/threading/sequence_bound.h"
Peter Kastinga7066c62023-04-25 02:39:3122#include "base/types/expected.h"
Peter Kastingf115ece2023-08-07 21:09:4423#include "base/types/expected_macros.h"
Alan Screen597675382021-09-11 05:14:5324#include "base/values.h"
Alan Screenc15aea62021-01-08 03:32:1225#include "build/build_config.h"
Lei Zhang3a48a1d2023-03-25 02:10:4626#include "build/chromeos_buildflags.h"
Alan Screenc7874de2022-09-01 21:00:1027#include "chrome/common/printing/printing_init.h"
Alan Screen65304d52020-10-29 16:42:2228#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
Alan Screen366ce3e2021-06-16 23:26:0429#include "components/crash/core/common/crash_keys.h"
Alan Screen65304d52020-10-29 16:42:2230#include "mojo/public/cpp/bindings/pending_receiver.h"
31#include "printing/backend/print_backend.h"
Andrew Rayskiy16f8cab2022-12-15 16:28:3332#include "printing/buildflags/buildflags.h"
Alan Screenbd4f851a2022-03-29 22:53:0533#include "printing/metafile.h"
34#include "printing/metafile_skia.h"
Alan Screen8f86e142021-05-07 09:52:1935#include "printing/mojom/print.mojom.h"
Alan Screen61e1a372021-12-10 03:02:3436#include "printing/printed_document.h"
Alan Screen597675382021-09-11 05:14:5337#include "printing/printing_context.h"
Alan Screen252d9812022-03-29 20:12:0838#include "third_party/abseil-cpp/absl/types/optional.h"
Alan Screen65304d52020-10-29 16:42:2239
Xiaohan Wangd4bc2742022-01-15 19:48:5540#if BUILDFLAG(IS_MAC)
Alan Screenc15aea62021-01-08 03:32:1241#include "base/threading/thread_restrictions.h"
42#include "chrome/common/printing/printer_capabilities_mac.h"
43#endif
44
Andrew Rayskiy16f8cab2022-12-15 16:28:3345#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS)
Alan Screen2166ab12021-09-01 23:09:2546#include "printing/backend/cups_connection_pool.h"
47#endif
48
Alan Screen65a66412022-09-24 02:29:2249#if BUILDFLAG(IS_LINUX)
50#include "base/no_destructor.h"
51#include "ui/linux/linux_ui.h"
52#include "ui/linux/linux_ui_delegate_stub.h"
53#include "ui/linux/linux_ui_factory.h"
54#endif
55
Xiaohan Wangd4bc2742022-01-15 19:48:5556#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:3457#include "base/containers/queue.h"
Andy Phan65e73562022-11-02 17:06:4758#include "base/types/expected.h"
Alan Screenc336bd862022-03-22 18:19:4159#include "base/win/win_util.h"
Andy Phand8ca2432022-10-14 21:11:5260#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
61#include "mojo/public/cpp/bindings/pending_remote.h"
62#include "mojo/public/cpp/bindings/remote.h"
Andy Phan65e73562022-11-02 17:06:4763#include "printing/backend/xps_utils_win.h"
Alan Screen61e1a372021-12-10 03:02:3464#include "printing/emf_win.h"
Alan Screen61e1a372021-12-10 03:02:3465#include "printing/printed_page_win.h"
Andy Phan65e73562022-11-02 17:06:4766#include "printing/printing_features.h"
Alan Screen61e1a372021-12-10 03:02:3467#include "ui/gfx/geometry/rect.h"
68#include "ui/gfx/geometry/size.h"
Alan Screenc336bd862022-03-22 18:19:4169#include "ui/gfx/native_widget_types.h"
Alan Screen61e1a372021-12-10 03:02:3470#endif
71
Alan Screen65304d52020-10-29 16:42:2272namespace printing {
73
Alan Screen2166ab12021-09-01 23:09:2574namespace {
75
Alan Screen65a66412022-09-24 02:29:2276#if BUILDFLAG(IS_LINUX)
77void InstantiateLinuxUiDelegate() {
78 // TODO(crbug.com/809738) Until a real UI can be used in a utility process,
79 // need to use the stub version.
80 static base::NoDestructor<ui::LinuxUiDelegateStub> linux_ui_delegate;
81}
82#endif
83
Alan Screen2166ab12021-09-01 23:09:2584scoped_refptr<base::SequencedTaskRunner> GetPrintingTaskRunner() {
Alan Screen7e8213cc72023-07-13 22:44:3785#if BUILDFLAG(IS_LINUX)
86 // Use task runner associated with equivalent of UI thread. Needed for calls
87 // made through `PrintDialogLinuxInterface` to properly execute.
88 CHECK(base::SequencedTaskRunner::HasCurrentDefault());
Lei Zhang11694fa2023-09-28 08:27:2289 return base::SequencedTaskRunner::GetCurrentDefault();
Alan Screen7e8213cc72023-07-13 22:44:3790#else
91
Alan Screen2166ab12021-09-01 23:09:2592 static constexpr base::TaskTraits kTraits = {
93 base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
94
Andrew Rayskiy16f8cab2022-12-15 16:28:3395#if BUILDFLAG(USE_CUPS)
Alan Screen2166ab12021-09-01 23:09:2596 // CUPS is thread safe, so a task runner can be allocated for each job.
Lei Zhang11694fa2023-09-28 08:27:2297 return base::ThreadPool::CreateSequencedTaskRunner(kTraits);
Xiaohan Wangd4bc2742022-01-15 19:48:5598#elif BUILDFLAG(IS_WIN)
Alan Screen2166ab12021-09-01 23:09:2599 // For Windows, we want a single threaded task runner shared for all print
100 // jobs in the process because Windows printer drivers are oftentimes not
101 // thread-safe. This protects against multiple print jobs to the same device
102 // from running in the driver at the same time.
Lei Zhang11694fa2023-09-28 08:27:22103 return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
Alan Screen2166ab12021-09-01 23:09:25104#else
105 // Be conservative for unsupported platforms, use a single threaded runner
106 // so that concurrent print jobs are not in driver code at the same time.
Lei Zhang11694fa2023-09-28 08:27:22107 return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
Alan Screen2166ab12021-09-01 23:09:25108#endif
Alan Screen7e8213cc72023-07-13 22:44:37109#endif // BUILDFLAG(IS_LINUX)
Alan Screen2166ab12021-09-01 23:09:25110}
111
Alan Screen61e1a372021-12-10 03:02:34112std::unique_ptr<Metafile> CreateMetafile(mojom::MetafileDataType data_type) {
113 switch (data_type) {
114 case mojom::MetafileDataType::kPDF:
115 return std::make_unique<MetafileSkia>();
Alan Screenbd4f851a2022-03-29 22:53:05116#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34117 case mojom::MetafileDataType::kEMF:
118 return std::make_unique<Emf>();
Alan Screenbd4f851a2022-03-29 22:53:05119#endif
Alan Screen61e1a372021-12-10 03:02:34120 }
121}
Alan Screen252d9812022-03-29 20:12:08122
123struct RenderData {
124 std::unique_ptr<uint8_t[]> data_copy;
125 std::unique_ptr<Metafile> metafile;
126};
127
128absl::optional<RenderData> PrepareRenderData(
129 int document_cookie,
130 mojom::MetafileDataType page_data_type,
131 const base::ReadOnlySharedMemoryRegion& serialized_data) {
132 base::ReadOnlySharedMemoryMapping mapping = serialized_data.Map();
133 if (!mapping.IsValid()) {
134 DLOG(ERROR) << "Failure printing document " << document_cookie
135 << ", cannot map input.";
136 return absl::nullopt;
137 }
138
139 RenderData render_data;
140 render_data.metafile = CreateMetafile(page_data_type);
141
142 // For security reasons we need to use a copy of the data, and not operate
143 // on it directly out of shared memory. Make a copy here if the underlying
144 // `Metafile` implementation doesn't do it automatically.
145 // TODO(crbug.com/1135729) Eliminate this copy when the shared memory can't
146 // be written by the sender.
147 base::span<const uint8_t> data = mapping.GetMemoryAsSpan<uint8_t>();
148 if (render_data.metafile->ShouldCopySharedMemoryRegionData()) {
149 render_data.data_copy = std::make_unique<uint8_t[]>(data.size());
Peter Kasting965f02fc2022-10-28 23:35:43150 base::ranges::copy(data, render_data.data_copy.get());
Alan Screen252d9812022-03-29 20:12:08151 data = base::span<const uint8_t>(render_data.data_copy.get(), data.size());
152 }
153 if (!render_data.metafile->InitFromData(data)) {
154 DLOG(ERROR) << "Failure printing document " << document_cookie
155 << ", unable to initialize.";
156 return absl::nullopt;
157 }
158 return render_data;
159}
Alan Screen61e1a372021-12-10 03:02:34160
Alan Screen2166ab12021-09-01 23:09:25161// Local storage of document and associated data needed to submit to job to
Alan Screencb6421f2021-12-09 21:54:18162// the operating system's printing API. All access to the document occurs on
163// a worker task runner.
164class DocumentContainer {
165 public:
Alan Screen9aa46142023-03-24 19:56:25166 DocumentContainer(std::unique_ptr<PrintingContext::Delegate> context_delegate,
167 std::unique_ptr<PrintingContext> context,
Alan Screenfd714c12023-03-24 21:03:29168 scoped_refptr<PrintedDocument> document)
Alan Screen9aa46142023-03-24 19:56:25169 : context_delegate_(std::move(context_delegate)),
170 context_(std::move(context)),
Alan Screenfd714c12023-03-24 21:03:29171 document_(document) {}
Alan Screen2166ab12021-09-01 23:09:25172
173 ~DocumentContainer() = default;
174
Alan Screen61e1a372021-12-10 03:02:34175 // Helper functions that runs on a task runner.
Alan Screencb6421f2021-12-09 21:54:18176 mojom::ResultCode StartPrintingReadyDocument();
Xiaohan Wangd4bc2742022-01-15 19:48:55177#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34178 mojom::ResultCode DoRenderPrintedPage(
179 uint32_t page_index,
180 mojom::MetafileDataType page_data_type,
181 base::ReadOnlySharedMemoryRegion serialized_page,
182 gfx::Size page_size,
183 gfx::Rect page_content_rect,
184 float shrink_factor);
185#endif
Alan Screenbd4f851a2022-03-29 22:53:05186 mojom::ResultCode DoRenderPrintedDocument(
Alan Screena6cebd82022-11-03 19:56:29187 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05188 mojom::MetafileDataType data_type,
189 base::ReadOnlySharedMemoryRegion serialized_document);
Alan Screen6bf1d5fb2022-02-08 15:51:14190 mojom::ResultCode DoDocumentDone();
Alan Screen2a7dcc92022-11-17 04:52:01191 void DoCancel();
Alan Screencb6421f2021-12-09 21:54:18192
193 private:
Alan Screen9aa46142023-03-24 19:56:25194 std::unique_ptr<PrintingContext::Delegate> context_delegate_;
Alan Screencb6421f2021-12-09 21:54:18195 std::unique_ptr<PrintingContext> context_;
Alan Screen2166ab12021-09-01 23:09:25196
Alan Screen9aa46142023-03-24 19:56:25197 scoped_refptr<PrintedDocument> document_;
198
Alan Screencb6421f2021-12-09 21:54:18199 // Ensure all interactions for this document are issued from the same runner.
200 SEQUENCE_CHECKER(sequence_checker_);
201};
202
203mojom::ResultCode DocumentContainer::StartPrintingReadyDocument() {
204 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
205
206 DVLOG(1) << "Start printing for document " << document_->cookie();
207
Alan Screenfd714c12023-03-24 21:03:29208 mojom::ResultCode result = context_->NewDocument(document_->name());
Alan Screencb6421f2021-12-09 21:54:18209 if (result != mojom::ResultCode::kSuccess) {
210 DLOG(ERROR) << "Failure initializing new document " << document_->cookie()
211 << ", error: " << result;
Alan Screenca9c9932022-11-21 19:31:26212 context_->Cancel();
Alan Screencb6421f2021-12-09 21:54:18213 return result;
214 }
215
216 return mojom::ResultCode::kSuccess;
217}
218
Xiaohan Wangd4bc2742022-01-15 19:48:55219#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34220mojom::ResultCode DocumentContainer::DoRenderPrintedPage(
221 uint32_t page_index,
222 mojom::MetafileDataType page_data_type,
223 base::ReadOnlySharedMemoryRegion serialized_page,
224 gfx::Size page_size,
225 gfx::Rect page_content_rect,
226 float shrink_factor) {
227 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
228
229 DVLOG(1) << "Render printed page " << page_index << " for document "
230 << document_->cookie();
231
Alan Screen252d9812022-03-29 20:12:08232 absl::optional<RenderData> render_data =
233 PrepareRenderData(document_->cookie(), page_data_type, serialized_page);
Alan Screenca9c9932022-11-21 19:31:26234 if (!render_data) {
235 DLOG(ERROR) << "Failure preparing render data for document "
236 << document_->cookie();
237 context_->Cancel();
Alan Screen61e1a372021-12-10 03:02:34238 return mojom::ResultCode::kFailed;
Alan Screenca9c9932022-11-21 19:31:26239 }
Alan Screen61e1a372021-12-10 03:02:34240
Alan Screen252d9812022-03-29 20:12:08241 document_->SetPage(page_index, std::move(render_data->metafile),
242 shrink_factor, page_size, page_content_rect);
Alan Screen61e1a372021-12-10 03:02:34243
Alan Screen0ad9df72022-09-27 18:34:35244 mojom::ResultCode result = document_->RenderPrintedPage(
245 *document_->GetPage(page_index), context_.get());
246 if (result != mojom::ResultCode::kSuccess) {
247 DLOG(ERROR) << "Failure rendering page " << page_index << " of document "
248 << document_->cookie() << ", error: " << result;
Alan Screenca9c9932022-11-21 19:31:26249 context_->Cancel();
Alan Screen0ad9df72022-09-27 18:34:35250 }
Alan Screenca9c9932022-11-21 19:31:26251 return result;
Alan Screen61e1a372021-12-10 03:02:34252}
Xiaohan Wangd4bc2742022-01-15 19:48:55253#endif // BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34254
Alan Screenbd4f851a2022-03-29 22:53:05255mojom::ResultCode DocumentContainer::DoRenderPrintedDocument(
Alan Screena6cebd82022-11-03 19:56:29256 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05257 mojom::MetafileDataType data_type,
258 base::ReadOnlySharedMemoryRegion serialized_document) {
259 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
260
261 DVLOG(1) << "Render printed document " << document_->cookie();
262
263 absl::optional<RenderData> render_data =
264 PrepareRenderData(document_->cookie(), data_type, serialized_document);
Alan Screenca9c9932022-11-21 19:31:26265 if (!render_data) {
266 DLOG(ERROR) << "Failure preparing render data for document "
267 << document_->cookie();
268 context_->Cancel();
Alan Screenbd4f851a2022-03-29 22:53:05269 return mojom::ResultCode::kFailed;
Alan Screenca9c9932022-11-21 19:31:26270 }
Alan Screenbd4f851a2022-03-29 22:53:05271
Alan Screena6cebd82022-11-03 19:56:29272 document_->set_page_count(page_count);
Alan Screenbd4f851a2022-03-29 22:53:05273 document_->SetDocument(std::move(render_data->metafile));
274
Alan Screenca9c9932022-11-21 19:31:26275 mojom::ResultCode result = document_->RenderPrintedDocument(context_.get());
276 if (result != mojom::ResultCode::kSuccess) {
277 DLOG(ERROR) << "Failure rendering document " << document_->cookie()
278 << ", error: " << result;
279 context_->Cancel();
280 }
281 return result;
Alan Screenbd4f851a2022-03-29 22:53:05282}
283
Alan Screen6bf1d5fb2022-02-08 15:51:14284mojom::ResultCode DocumentContainer::DoDocumentDone() {
285 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
286
287 DVLOG(1) << "Document done for document " << document_->cookie();
Alan Screenca9c9932022-11-21 19:31:26288 mojom::ResultCode result = context_->DocumentDone();
289 if (result != mojom::ResultCode::kSuccess) {
290 DLOG(ERROR) << "Failure completing document " << document_->cookie()
291 << ", error: " << result;
292 context_->Cancel();
293 }
294 return result;
Alan Screen6bf1d5fb2022-02-08 15:51:14295}
296
Alan Screen2a7dcc92022-11-17 04:52:01297void DocumentContainer::DoCancel() {
298 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
299
300 DVLOG(1) << "Canceling document " << document_->cookie();
301 context_->Cancel();
302}
303
Alan Screencb6421f2021-12-09 21:54:18304} // namespace
305
306// Helper for managing `DocumentContainer` objects. All access to this occurs
307// on the main thread.
308class PrintBackendServiceImpl::DocumentHelper {
309 public:
310 DocumentHelper(
311 int document_cookie,
312 base::SequenceBound<DocumentContainer> document_container,
313 mojom::PrintBackendService::StartPrintingCallback start_printing_callback)
314 : document_cookie_(document_cookie),
315 document_container_(std::move(document_container)),
316 start_printing_callback_(std::move(start_printing_callback)) {}
317
318 ~DocumentHelper() = default;
319
320 int document_cookie() const {
321 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
322 return document_cookie_;
323 }
324
325 base::SequenceBound<DocumentContainer>& document_container() {
326 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
327 return document_container_;
328 }
329
330 mojom::PrintBackendService::StartPrintingCallback
331 TakeStartPrintingCallback() {
332 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
333 return std::move(start_printing_callback_);
334 }
335
336 private:
337 const int document_cookie_;
338
339 base::SequenceBound<DocumentContainer> document_container_;
340
341 // `start_printing_callback_` is held until the document is ready for
Alan Screen2166ab12021-09-01 23:09:25342 // printing.
Alan Screencb6421f2021-12-09 21:54:18343 mojom::PrintBackendService::StartPrintingCallback start_printing_callback_;
Alan Screen2166ab12021-09-01 23:09:25344
Alan Screencb6421f2021-12-09 21:54:18345 // Ensure all interactions for this document are issued from the same runner.
346 SEQUENCE_CHECKER(sequence_checker_);
Alan Screen2166ab12021-09-01 23:09:25347};
348
Alex Gough59a0e962021-09-30 23:42:44349// Sandboxed service helper.
350SandboxedPrintBackendHostImpl::SandboxedPrintBackendHostImpl(
351 mojo::PendingReceiver<mojom::SandboxedPrintBackendHost> receiver)
352 : receiver_(this, std::move(receiver)) {}
353
354SandboxedPrintBackendHostImpl::~SandboxedPrintBackendHostImpl() = default;
355
356void SandboxedPrintBackendHostImpl::BindBackend(
357 mojo::PendingReceiver<mojom::PrintBackendService> receiver) {
358 CHECK(!print_backend_service_)
359 << "Cannot bind service twice in same process.";
360 print_backend_service_ =
361 std::make_unique<PrintBackendServiceImpl>(std::move(receiver));
362}
363
364// Unsandboxed service helper.
365UnsandboxedPrintBackendHostImpl::UnsandboxedPrintBackendHostImpl(
366 mojo::PendingReceiver<mojom::UnsandboxedPrintBackendHost> receiver)
367 : receiver_(this, std::move(receiver)) {}
368
369UnsandboxedPrintBackendHostImpl::~UnsandboxedPrintBackendHostImpl() = default;
370
371void UnsandboxedPrintBackendHostImpl::BindBackend(
372 mojo::PendingReceiver<mojom::PrintBackendService> receiver) {
373 CHECK(!print_backend_service_)
374 << "Cannot bind service twice in same process.";
375 print_backend_service_ =
376 std::make_unique<PrintBackendServiceImpl>(std::move(receiver));
377}
378
Alan Screen2166ab12021-09-01 23:09:25379PrintBackendServiceImpl::PrintingContextDelegate::PrintingContextDelegate() =
380 default;
381PrintBackendServiceImpl::PrintingContextDelegate::~PrintingContextDelegate() =
382 default;
383
384gfx::NativeView
385PrintBackendServiceImpl::PrintingContextDelegate::GetParentView() {
Alan Screen49f16ac2023-01-13 05:38:34386#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
Alan Screenc336bd862022-03-22 18:19:41387 return parent_native_view_;
388#else
Alan Screen2166ab12021-09-01 23:09:25389 NOTREACHED();
390 return nullptr;
Alan Screenc336bd862022-03-22 18:19:41391#endif
Alan Screen2166ab12021-09-01 23:09:25392}
393
394std::string PrintBackendServiceImpl::PrintingContextDelegate::GetAppLocale() {
395 return locale_;
396}
397
Alan Screen49f16ac2023-01-13 05:38:34398#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
Alan Screenc336bd862022-03-22 18:19:41399void PrintBackendServiceImpl::PrintingContextDelegate::SetParentWindow(
400 uint32_t parent_window_id) {
Alan Screen49f16ac2023-01-13 05:38:34401#if BUILDFLAG(IS_WIN)
Alan Screenc336bd862022-03-22 18:19:41402 parent_native_view_ = reinterpret_cast<gfx::NativeView>(
403 base::win::Uint32ToHandle(parent_window_id));
Alan Screen49f16ac2023-01-13 05:38:34404#else
405 NOTREACHED();
406#endif
Alan Screenc336bd862022-03-22 18:19:41407}
408#endif
409
Alan Screen2166ab12021-09-01 23:09:25410void PrintBackendServiceImpl::PrintingContextDelegate::SetAppLocale(
411 const std::string& locale) {
412 locale_ = locale;
413}
414
Alan Screen74c6632f2023-02-24 22:40:07415// Holds the context and associated delegate for persistent usage across
416// multiple settings calls until they are ready to be used to print a
417// document. Required since `PrintingContext` does not own the corresponding
418// delegate object that it relies upon.
419struct PrintBackendServiceImpl::ContextContainer {
420 ContextContainer() = default;
421 ~ContextContainer() = default;
422
423 std::unique_ptr<PrintingContextDelegate> delegate;
424 std::unique_ptr<PrintingContext> context;
425};
426
Alan Screen65304d52020-10-29 16:42:22427PrintBackendServiceImpl::PrintBackendServiceImpl(
428 mojo::PendingReceiver<mojom::PrintBackendService> receiver)
429 : receiver_(this, std::move(receiver)) {}
430
431PrintBackendServiceImpl::~PrintBackendServiceImpl() = default;
432
Andy Phan5f3db322022-11-11 19:53:02433void PrintBackendServiceImpl::InitCommon(
434#if BUILDFLAG(IS_WIN)
435 const std::string& locale,
436 mojo::PendingRemote<mojom::PrinterXmlParser> remote
437#else
438 const std::string& locale
439#endif // BUILDFLAG(IS_WIN)
440) {
Alan Screen74c6632f2023-02-24 22:40:07441 locale_ = locale;
Andy Phan5f3db322022-11-11 19:53:02442#if BUILDFLAG(IS_WIN)
443 if (remote.is_valid())
444 xml_parser_remote_.Bind(std::move(remote));
445#endif // BUILDFLAG(IS_WIN)
Alan Screen71ef2a02022-09-19 23:48:55446}
447
Andy Phan5f3db322022-11-11 19:53:02448void PrintBackendServiceImpl::Init(
449#if BUILDFLAG(IS_WIN)
450 const std::string& locale,
451 mojo::PendingRemote<mojom::PrinterXmlParser> remote
452#else
453 const std::string& locale
454#endif // BUILDFLAG(IS_WIN)
455) {
Alan Screen71ef2a02022-09-19 23:48:55456 // Test classes should not invoke this base initialization method, as process
457 // initialization is very different for test frameworks. Test classes
458 // will also provide their own test version of a `PrintBackend`.
459 // Common initialization for production and testing should instead reside in
460 // `InitCommon()`.
Alan Screenc7874de2022-09-01 21:00:10461 InitializeProcessForPrinting();
Alan Screen65304d52020-10-29 16:42:22462 print_backend_ = PrintBackend::CreateInstance(locale);
Alan Screen65a66412022-09-24 02:29:22463#if BUILDFLAG(IS_LINUX)
464 // Test framework already initializes the UI, so this should not go in
465 // `InitCommon()`. Additionally, low-level Linux UI is not needed when tests
466 // are using `TestPrintingContext`.
467 InstantiateLinuxUiDelegate();
468 ui::LinuxUi::SetInstance(ui::GetDefaultLinuxUi());
Andy Phan5f3db322022-11-11 19:53:02469#endif // BUILDFLAG(IS_LINUX)
Alan Screen71ef2a02022-09-19 23:48:55470
Andy Phan5f3db322022-11-11 19:53:02471#if BUILDFLAG(IS_WIN)
472 InitCommon(locale, std::move(remote));
473#else
Alan Screen71ef2a02022-09-19 23:48:55474 InitCommon(locale);
Andy Phan5f3db322022-11-11 19:53:02475#endif // BUILDFLAG(IS_WIN)
Alan Screen65304d52020-10-29 16:42:22476}
477
Alan Screen5754f542021-07-09 00:43:50478// TODO(crbug.com/1225111) Do nothing, this is just to assist an idle timeout
479// change by providing a low-cost call to ensure it is applied.
480void PrintBackendServiceImpl::Poke() {}
481
Alan Screen2a5c54262021-02-11 10:44:29482void PrintBackendServiceImpl::EnumeratePrinters(
483 mojom::PrintBackendService::EnumeratePrintersCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24484 DCHECK(print_backend_);
Alan Screen2a5c54262021-02-11 10:44:29485 PrinterList printer_list;
Alan Screenb92927f2022-06-14 21:27:20486 mojom::ResultCode result = print_backend_->EnumeratePrinters(printer_list);
Alan Screen5ad643b2021-05-13 16:40:18487 if (result != mojom::ResultCode::kSuccess) {
488 std::move(callback).Run(mojom::PrinterListResult::NewResultCode(result));
Alan Screen2a5c54262021-02-11 10:44:29489 return;
490 }
Alan Screen5ad643b2021-05-13 16:40:18491 std::move(callback).Run(
492 mojom::PrinterListResult::NewPrinterList(std::move(printer_list)));
Alan Screen2a5c54262021-02-11 10:44:29493}
494
Alan Screen65304d52020-10-29 16:42:22495void PrintBackendServiceImpl::GetDefaultPrinterName(
496 mojom::PrintBackendService::GetDefaultPrinterNameCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24497 DCHECK(print_backend_);
Alan Screen322ed6182021-06-03 15:26:47498 std::string default_printer;
499 mojom::ResultCode result =
500 print_backend_->GetDefaultPrinterName(default_printer);
501 if (result != mojom::ResultCode::kSuccess) {
502 std::move(callback).Run(
503 mojom::DefaultPrinterNameResult::NewResultCode(result));
504 return;
505 }
506 std::move(callback).Run(
507 mojom::DefaultPrinterNameResult::NewDefaultPrinterName(default_printer));
Alan Screen65304d52020-10-29 16:42:22508}
509
Lei Zhang3a48a1d2023-03-25 02:10:46510#if BUILDFLAG(IS_CHROMEOS_ASH)
Alan Screend00ff1d2020-12-08 04:17:40511void PrintBackendServiceImpl::GetPrinterSemanticCapsAndDefaults(
512 const std::string& printer_name,
513 mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
514 callback) {
Alan Screen7a30b042022-09-19 17:51:24515 DCHECK(print_backend_);
Alan Screen366ce3e2021-06-16 23:26:04516 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
517 print_backend_->GetPrinterDriverInfo(printer_name));
518
Alan Screend00ff1d2020-12-08 04:17:40519 PrinterSemanticCapsAndDefaults printer_caps;
Alan Screen8f86e142021-05-07 09:52:19520 const mojom::ResultCode result =
521 print_backend_->GetPrinterSemanticCapsAndDefaults(printer_name,
522 &printer_caps);
523 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18524 std::move(callback).Run(
525 mojom::PrinterSemanticCapsAndDefaultsResult::NewResultCode(result));
Alan Screend00ff1d2020-12-08 04:17:40526 return;
527 }
Alan Screen5ad643b2021-05-13 16:40:18528 std::move(callback).Run(
529 mojom::PrinterSemanticCapsAndDefaultsResult::NewPrinterCaps(
530 std::move(printer_caps)));
Alan Screend00ff1d2020-12-08 04:17:40531}
Lei Zhang3a48a1d2023-03-25 02:10:46532#endif // BUILDFLAG(IS_CHROMEOS_ASH)
Alan Screend00ff1d2020-12-08 04:17:40533
Alan Screenc15aea62021-01-08 03:32:12534void PrintBackendServiceImpl::FetchCapabilities(
535 const std::string& printer_name,
536 mojom::PrintBackendService::FetchCapabilitiesCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24537 DCHECK(print_backend_);
Alan Screen366ce3e2021-06-16 23:26:04538 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
539 print_backend_->GetPrinterDriverInfo(printer_name));
540
Alan Screenc15aea62021-01-08 03:32:12541 PrinterBasicInfo printer_info;
Alan Screen8f86e142021-05-07 09:52:19542 mojom::ResultCode result =
Alan Screenc15aea62021-01-08 03:32:12543 print_backend_->GetPrinterBasicInfo(printer_name, &printer_info);
Alan Screen8f86e142021-05-07 09:52:19544 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18545 std::move(callback).Run(
546 mojom::PrinterCapsAndInfoResult::NewResultCode(result));
Alan Screenc15aea62021-01-08 03:32:12547 return;
548 }
Lei Zhang0ce71b42023-02-15 23:02:06549
Alan Screenc15aea62021-01-08 03:32:12550 PrinterSemanticCapsAndDefaults caps;
551 result =
552 print_backend_->GetPrinterSemanticCapsAndDefaults(printer_name, &caps);
Alan Screen8f86e142021-05-07 09:52:19553 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18554 std::move(callback).Run(
555 mojom::PrinterCapsAndInfoResult::NewResultCode(result));
Alan Screenc15aea62021-01-08 03:32:12556 return;
557 }
Lei Zhang0ce71b42023-02-15 23:02:06558
Andy Phan65e73562022-11-02 17:06:47559#if BUILDFLAG(IS_WIN)
560 if (xml_parser_remote_.is_bound() &&
561 base::FeatureList::IsEnabled(features::kReadPrinterCapabilitiesWithXps)) {
Peter Kastingf115ece2023-08-07 21:09:44562 ASSIGN_OR_RETURN(
563 XpsCapabilities xps_capabilities, GetXpsCapabilities(printer_name),
564 [&](mojom::ResultCode error) {
565 return std::move(callback).Run(
566 mojom::PrinterCapsAndInfoResult::NewResultCode(error));
567 });
Andy Phan65e73562022-11-02 17:06:47568
Peter Kastingf115ece2023-08-07 21:09:44569 MergeXpsCapabilities(std::move(xps_capabilities), caps);
Andy Phan65e73562022-11-02 17:06:47570 }
571#endif // BUILDFLAG(IS_WIN)
Lei Zhang0ce71b42023-02-15 23:02:06572
573#if BUILDFLAG(IS_MAC)
574 {
575 // Blocking is needed here for when macOS reads paper sizes from file.
576 //
577 // Fetching capabilities in the browser process happens from the thread
578 // pool with the MayBlock() trait for macOS. However this call can also
579 // run from a utility process's main thread where blocking is not
580 // implicitly allowed. In order to preserve ordering, the utility process
581 // must process this synchronously by blocking.
582 //
583 // TODO(crbug.com/1163635): Investigate whether utility process main
584 // thread should be allowed to block like in-process workers are.
585 base::ScopedAllowBlocking allow_blocking;
586 caps.user_defined_papers = GetMacCustomPaperSizes();
587 }
588#endif
589
590 mojom::PrinterCapsAndInfoPtr caps_and_info =
591 mojom::PrinterCapsAndInfo::New(std::move(printer_info), std::move(caps));
Alan Screen5ad643b2021-05-13 16:40:18592 std::move(callback).Run(
593 mojom::PrinterCapsAndInfoResult::NewPrinterCapsAndInfo(
594 std::move(caps_and_info)));
Alan Screenc15aea62021-01-08 03:32:12595}
596
Alan Screen9fcfd3722023-04-24 20:29:49597#if BUILDFLAG(IS_WIN)
598void PrintBackendServiceImpl::GetPaperPrintableArea(
599 const std::string& printer_name,
600 const PrintSettings::RequestedMedia& media,
601 mojom::PrintBackendService::GetPaperPrintableAreaCallback callback) {
602 CHECK(print_backend_);
603 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
604 print_backend_->GetPrinterDriverInfo(printer_name));
605
606 absl::optional<gfx::Rect> printable_area_um =
607 print_backend_->GetPaperPrintableArea(printer_name, media.vendor_id,
608 media.size_microns);
609 std::move(callback).Run(printable_area_um.value_or(gfx::Rect()));
610}
611#endif
612
Alan Screen74c6632f2023-02-24 22:40:07613void PrintBackendServiceImpl::EstablishPrintingContext(uint32_t context_id
614#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
615 ,
616 uint32_t parent_window_id
617#endif
618) {
619 auto context_container = std::make_unique<ContextContainer>();
620
621 context_container->delegate = CreatePrintingContextDelegate();
622#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
623 context_container->delegate->SetParentWindow(parent_window_id);
624#endif
625
626 context_container->context = PrintingContext::Create(
Alan Screen96a123952023-11-06 21:53:16627 context_container->delegate.get(),
628 PrintingContext::ProcessBehavior::kOopEnabledPerformSystemCalls);
Alan Screen74c6632f2023-02-24 22:40:07629
630 bool inserted = persistent_printing_contexts_
631 .insert({context_id, std::move(context_container)})
632 .second;
633 DCHECK(inserted);
634}
635
Alan Screenfa756fb2022-02-15 00:02:24636void PrintBackendServiceImpl::UseDefaultSettings(
Alan Screen9aa46142023-03-24 19:56:25637 uint32_t context_id,
Alan Screenfa756fb2022-02-15 00:02:24638 mojom::PrintBackendService::UseDefaultSettingsCallback callback) {
Alan Screen9aa46142023-03-24 19:56:25639 PrintingContext* context = GetPrintingContext(context_id);
640 CHECK(context) << "No context found for id " << context_id;
641 mojom::ResultCode result = context->UseDefaultSettings();
Alan Screenfa756fb2022-02-15 00:02:24642 if (result != mojom::ResultCode::kSuccess) {
Alan Screen01cd3bc2022-02-15 02:38:47643 DLOG(ERROR) << "Failure getting default settings of default printer, "
644 << "error: " << result;
Alan Screen9aa46142023-03-24 19:56:25645 persistent_printing_contexts_.erase(context_id);
Alan Screenfa756fb2022-02-15 00:02:24646 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
647 return;
648 }
649 std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
650 *context->TakeAndResetSettings()));
651}
652
Alan Screen49f16ac2023-01-13 05:38:34653#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
Alan Screenc336bd862022-03-22 18:19:41654void PrintBackendServiceImpl::AskUserForSettings(
Alan Screen9aa46142023-03-24 19:56:25655 uint32_t context_id,
Alan Screenc336bd862022-03-22 18:19:41656 int max_pages,
657 bool has_selection,
658 bool is_scripted,
659 mojom::PrintBackendService::AskUserForSettingsCallback callback) {
Alan Screen9aa46142023-03-24 19:56:25660 // Safe to use `base::Unretained(this)` because `this` outlives the async
661 // call and callback. The entire service process goes away when `this`
662 // lifetime expires.
663 PrintingContext* context = GetPrintingContext(context_id);
664 CHECK(context) << "No context found for id " << context_id;
665 context->AskUserForSettings(
Alan Screenc336bd862022-03-22 18:19:41666 max_pages, has_selection, is_scripted,
Alan Screen9aa46142023-03-24 19:56:25667 base::BindOnce(&PrintBackendServiceImpl::OnDidAskUserForSettings,
668 base::Unretained(this), context_id, std::move(callback)));
Alan Screenc336bd862022-03-22 18:19:41669}
Alan Screen49f16ac2023-01-13 05:38:34670#endif // BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
Alan Screenc336bd862022-03-22 18:19:41671
Alan Screen597675382021-09-11 05:14:53672void PrintBackendServiceImpl::UpdatePrintSettings(
Alan Screenfd714c12023-03-24 21:03:29673 uint32_t context_id,
Lei Zhang15e92b92022-04-12 20:06:23674 base::Value::Dict job_settings,
Alan Screen597675382021-09-11 05:14:53675 mojom::PrintBackendService::UpdatePrintSettingsCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24676 DCHECK(print_backend_);
Alan Screen597675382021-09-11 05:14:53677
Lei Zhang15e92b92022-04-12 20:06:23678 const std::string* printer_name = job_settings.FindString(kSettingDeviceName);
Alan Screen7a30b042022-09-19 17:51:24679 DCHECK(printer_name);
Alan Screen597675382021-09-11 05:14:53680
681 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
Lei Zhang15e92b92022-04-12 20:06:23682 print_backend_->GetPrinterDriverInfo(*printer_name));
Alan Screen597675382021-09-11 05:14:53683
Andrew Rayskiy16f8cab2022-12-15 16:28:33684#if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS)
Alan Screen597675382021-09-11 05:14:53685 // Try to fill in advanced settings based upon basic info options.
686 PrinterBasicInfo basic_info;
Lei Zhang15e92b92022-04-12 20:06:23687 if (print_backend_->GetPrinterBasicInfo(*printer_name, &basic_info) ==
Alan Screen597675382021-09-11 05:14:53688 mojom::ResultCode::kSuccess) {
Lei Zhang15e92b92022-04-12 20:06:23689 base::Value::Dict advanced_settings;
Alan Screen597675382021-09-11 05:14:53690 for (const auto& pair : basic_info.options)
Lei Zhang15e92b92022-04-12 20:06:23691 advanced_settings.Set(pair.first, pair.second);
Alan Screen597675382021-09-11 05:14:53692
Lei Zhang15e92b92022-04-12 20:06:23693 job_settings.Set(kSettingAdvancedSettings, std::move(advanced_settings));
Alan Screen597675382021-09-11 05:14:53694 }
Andrew Rayskiy16f8cab2022-12-15 16:28:33695#endif // BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS)
Alan Screen597675382021-09-11 05:14:53696
Alan Screenfd714c12023-03-24 21:03:29697 PrintingContext* context = GetPrintingContext(context_id);
698 CHECK(context) << "No context found for id " << context_id;
Alan Screen202e49a2021-09-21 06:34:28699 mojom::ResultCode result =
Lei Zhang4bc852972022-04-12 20:22:19700 context->UpdatePrintSettings(std::move(job_settings));
Alan Screen597675382021-09-11 05:14:53701
Alan Screen202e49a2021-09-21 06:34:28702 if (result != mojom::ResultCode::kSuccess) {
Alan Screen39bc7632023-04-25 18:04:58703 persistent_printing_contexts_.erase(context_id);
Alan Screen202e49a2021-09-21 06:34:28704 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
Alan Screen597675382021-09-11 05:14:53705 return;
706 }
707
Alan Screenfd714c12023-03-24 21:03:29708 std::move(callback).Run(
709 mojom::PrintSettingsResult::NewSettings(context->settings()));
Alan Screen597675382021-09-11 05:14:53710}
711
Alan Screen2166ab12021-09-01 23:09:25712void PrintBackendServiceImpl::StartPrinting(
Alan Screen9aa46142023-03-24 19:56:25713 uint32_t context_id,
Alan Screen2166ab12021-09-01 23:09:25714 int document_cookie,
715 const std::u16string& document_name,
Alan Screenfd714c12023-03-24 21:03:29716#if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
717 const absl::optional<PrintSettings>& settings,
718#endif
Alan Screen2166ab12021-09-01 23:09:25719 mojom::PrintBackendService::StartPrintingCallback callback) {
Andrew Rayskiy16f8cab2022-12-15 16:28:33720#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS)
Alan Screen2166ab12021-09-01 23:09:25721 CupsConnectionPool* connection_pool = CupsConnectionPool::GetInstance();
722 if (connection_pool) {
723 // If a pool exists then this document can only proceed with printing if
724 // there is a connection available for use by a `PrintingContext`.
725 if (!connection_pool->IsConnectionAvailable()) {
726 // This document has to wait until a connection becomes available. Hold
727 // off on issuing the callback.
728 // TODO(crbug.com/809738) Place this in a queue of waiting jobs.
729 DLOG(ERROR) << "Need queue for print jobs awaiting a connection";
730 std::move(callback).Run(mojom::ResultCode::kFailed);
731 return;
732 }
733 }
734#endif
735
Alan Screen9aa46142023-03-24 19:56:25736 // This job takes ownership of this printing context and associates it with
737 // the document.
738 auto item = persistent_printing_contexts_.find(context_id);
739 CHECK(item != persistent_printing_contexts_.end())
740 << "No context found for id " << context_id;
741 std::unique_ptr<ContextContainer> context_container = std::move(item->second);
742 persistent_printing_contexts_.erase(item);
743
Alan Screenfd714c12023-03-24 21:03:29744#if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
745 if (settings) {
746 // Apply the settings from the in-browser system dialog to the context.
Alan Screen2750f09052023-09-01 22:32:33747 context_container->context->SetPrintSettings(*settings);
Alan Screenfd714c12023-03-24 21:03:29748 }
749#endif
750
Alan Screen4b7ebf782021-12-07 19:10:02751 // Save all the document settings for use through the print job, until the
752 // time that this document can complete printing. Track the order of
753 // received documents with position in `documents_`.
754 auto document = base::MakeRefCounted<PrintedDocument>(
Alan Screenfd714c12023-03-24 21:03:29755 std::make_unique<PrintSettings>(context_container->context->settings()),
756 document_name, document_cookie);
Alan Screencb6421f2021-12-09 21:54:18757 base::SequenceBound<DocumentContainer> document_container(
Alan Screen9aa46142023-03-24 19:56:25758 GetPrintingTaskRunner(), std::move(context_container->delegate),
Alan Screenfd714c12023-03-24 21:03:29759 std::move(context_container->context), document);
Alan Screencb6421f2021-12-09 21:54:18760 documents_.push_back(std::make_unique<DocumentHelper>(
761 document_cookie, std::move(document_container), std::move(callback)));
762 DocumentHelper& document_helper = *documents_.back();
Alan Screen4b7ebf782021-12-07 19:10:02763
Alan Screencb6421f2021-12-09 21:54:18764 // Safe to use `base::Unretained(this)` because `this` outlives the async
765 // call and callback. The entire service process goes away when `this`
766 // lifetime expires.
767 document_helper.document_container()
768 .AsyncCall(&DocumentContainer::StartPrintingReadyDocument)
769 .Then(base::BindOnce(
770 &PrintBackendServiceImpl::OnDidStartPrintingReadyDocument,
771 base::Unretained(this), std::ref(document_helper)));
Alan Screen2166ab12021-09-01 23:09:25772}
773
Xiaohan Wangd4bc2742022-01-15 19:48:55774#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34775void PrintBackendServiceImpl::RenderPrintedPage(
776 int32_t document_cookie,
777 uint32_t page_index,
778 mojom::MetafileDataType page_data_type,
779 base::ReadOnlySharedMemoryRegion serialized_page,
780 const gfx::Size& page_size,
781 const gfx::Rect& page_content_rect,
782 float shrink_factor,
783 mojom::PrintBackendService::RenderPrintedPageCallback callback) {
Alan Screen61e1a372021-12-10 03:02:34784 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24785 DCHECK(document_helper);
Alan Screen61e1a372021-12-10 03:02:34786
Alan Screen61e1a372021-12-10 03:02:34787 document_helper->document_container()
788 .AsyncCall(&DocumentContainer::DoRenderPrintedPage)
789 .WithArgs(page_index, page_data_type, std::move(serialized_page),
790 page_size, page_content_rect, shrink_factor)
Alan Screenca9c9932022-11-21 19:31:26791 .Then(std::move(callback));
Alan Screen61e1a372021-12-10 03:02:34792}
Xiaohan Wangd4bc2742022-01-15 19:48:55793#endif // BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34794
Alan Screenbd4f851a2022-03-29 22:53:05795void PrintBackendServiceImpl::RenderPrintedDocument(
796 int32_t document_cookie,
Alan Screena6cebd82022-11-03 19:56:29797 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05798 mojom::MetafileDataType data_type,
799 base::ReadOnlySharedMemoryRegion serialized_document,
800 mojom::PrintBackendService::RenderPrintedDocumentCallback callback) {
Alan Screenbd4f851a2022-03-29 22:53:05801 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24802 DCHECK(document_helper);
Alan Screenbd4f851a2022-03-29 22:53:05803
Alan Screenbd4f851a2022-03-29 22:53:05804 document_helper->document_container()
805 .AsyncCall(&DocumentContainer::DoRenderPrintedDocument)
Alan Screena6cebd82022-11-03 19:56:29806 .WithArgs(page_count, data_type, std::move(serialized_document))
Alan Screenca9c9932022-11-21 19:31:26807 .Then(std::move(callback));
Alan Screenbd4f851a2022-03-29 22:53:05808}
809
Alan Screen6bf1d5fb2022-02-08 15:51:14810void PrintBackendServiceImpl::DocumentDone(
811 int document_cookie,
812 mojom::PrintBackendService::DocumentDoneCallback callback) {
Alan Screen6bf1d5fb2022-02-08 15:51:14813 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24814 DCHECK(document_helper);
Alan Screen6bf1d5fb2022-02-08 15:51:14815
816 // Safe to use `base::Unretained(this)` because `this` outlives the async
817 // call and callback. The entire service process goes away when `this`
818 // lifetime expires.
819 document_helper->document_container()
820 .AsyncCall(&DocumentContainer::DoDocumentDone)
821 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidDocumentDone,
822 base::Unretained(this), std::ref(*document_helper),
823 std::move(callback)));
824}
825
Alan Screen2a7dcc92022-11-17 04:52:01826void PrintBackendServiceImpl::Cancel(
827 int document_cookie,
828 mojom::PrintBackendService::CancelCallback callback) {
829 DCHECK(print_backend_);
830 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
831 DCHECK(document_helper);
832
833 // Safe to use `base::Unretained(this)` because `this` outlives the async
834 // call and callback. The entire service process goes away when `this`
835 // lifetime expires.
836 document_helper->document_container()
837 .AsyncCall(&DocumentContainer::DoCancel)
838 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidCancel,
839 base::Unretained(this), std::ref(*document_helper),
840 std::move(callback)));
841}
842
Alan Screen9aa46142023-03-24 19:56:25843#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
844void PrintBackendServiceImpl::OnDidAskUserForSettings(
845 uint32_t context_id,
846 mojom::PrintBackendService::AskUserForSettingsCallback callback,
847 mojom::ResultCode result) {
848 auto* context = GetPrintingContext(context_id);
849 DCHECK(context);
850 if (result != mojom::ResultCode::kSuccess) {
851 DLOG(ERROR) << "Did not get user settings, error: " << result;
852 persistent_printing_contexts_.erase(context_id);
853 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
854 return;
855 }
856 std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
857 *context->TakeAndResetSettings()));
858}
859#endif // BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
860
Alan Screen2166ab12021-09-01 23:09:25861void PrintBackendServiceImpl::OnDidStartPrintingReadyDocument(
Alan Screencb6421f2021-12-09 21:54:18862 DocumentHelper& document_helper,
Alan Screen2166ab12021-09-01 23:09:25863 mojom::ResultCode result) {
Alan Screen61e1a372021-12-10 03:02:34864 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
Alan Screencb6421f2021-12-09 21:54:18865 document_helper.TakeStartPrintingCallback().Run(result);
Alan Screenbd4f851a2022-03-29 22:53:05866}
867
Alan Screen6bf1d5fb2022-02-08 15:51:14868void PrintBackendServiceImpl::OnDidDocumentDone(
869 DocumentHelper& document_helper,
870 mojom::PrintBackendService::DocumentDoneCallback callback,
871 mojom::ResultCode result) {
872 std::move(callback).Run(result);
873
Alan Screenca9c9932022-11-21 19:31:26874 // The service expects that the calling process will call `Cancel()` if there
875 // are any errors during printing.
876 if (result == mojom::ResultCode::kSuccess) {
877 // All complete for this document.
878 RemoveDocumentHelper(document_helper);
879 }
Alan Screen6bf1d5fb2022-02-08 15:51:14880}
881
Alan Screen2a7dcc92022-11-17 04:52:01882void PrintBackendServiceImpl::OnDidCancel(
883 DocumentHelper& document_helper,
884 mojom::PrintBackendService::CancelCallback callback) {
885 std::move(callback).Run();
886
887 // Do nothing more with this document.
888 RemoveDocumentHelper(document_helper);
889}
890
Alan Screen74c6632f2023-02-24 22:40:07891std::unique_ptr<PrintBackendServiceImpl::PrintingContextDelegate>
892PrintBackendServiceImpl::CreatePrintingContextDelegate() {
893 auto context_delegate = std::make_unique<PrintingContextDelegate>();
894 context_delegate->SetAppLocale(locale_);
895 return context_delegate;
896}
897
Alan Screen9aa46142023-03-24 19:56:25898PrintingContext* PrintBackendServiceImpl::GetPrintingContext(
899 uint32_t context_id) {
900 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
901 auto item = persistent_printing_contexts_.find(context_id);
902 if (item == persistent_printing_contexts_.end()) {
903 return nullptr;
904 }
905 return item->second->context.get();
906}
907
Alan Screen61e1a372021-12-10 03:02:34908PrintBackendServiceImpl::DocumentHelper*
909PrintBackendServiceImpl::GetDocumentHelper(int document_cookie) {
910 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
911
912 // Most new calls are expected to be relevant to the most recently added
913 // document, which would be at the end of the list. So search the list
914 // backwards to hopefully reduce the time to find the document.
Victor Hugo Vianna Silva08f4b002022-01-17 13:20:04915 for (const std::unique_ptr<DocumentHelper>& helper :
916 base::Reversed(documents_)) {
Alan Screen61e1a372021-12-10 03:02:34917 if (helper->document_cookie() == document_cookie) {
Victor Hugo Vianna Silva08f4b002022-01-17 13:20:04918 return helper.get();
Alan Screen61e1a372021-12-10 03:02:34919 }
920 }
921 return nullptr;
922}
923
924void PrintBackendServiceImpl::RemoveDocumentHelper(
925 DocumentHelper& document_helper) {
926 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
927
928 // Must search forwards because std::vector::erase() doesn't work with a
929 // reverse iterator.
Alan Screencb6421f2021-12-09 21:54:18930 int cookie = document_helper.document_cookie();
931 auto item =
Peter Kasting73f230d02022-09-17 22:29:30932 base::ranges::find(documents_, cookie, &DocumentHelper::document_cookie);
Alan Screen2166ab12021-09-01 23:09:25933 DCHECK(item != documents_.end())
Alan Screencb6421f2021-12-09 21:54:18934 << "Document " << cookie << " to be deleted not found";
Alan Screen2166ab12021-09-01 23:09:25935 documents_.erase(item);
936
937 // TODO(crbug.com/809738) This releases a connection; try to start the
938 // next job waiting to be started (if any).
939}
940
Andy Phan65e73562022-11-02 17:06:47941#if BUILDFLAG(IS_WIN)
942base::expected<XpsCapabilities, mojom::ResultCode>
943PrintBackendServiceImpl::GetXpsCapabilities(const std::string& printer_name) {
Peter Kastingf115ece2023-08-07 21:09:44944 ASSIGN_OR_RETURN(
945 std::string xml,
946 print_backend_->GetXmlPrinterCapabilitiesForXpsDriver(printer_name),
947 [&](mojom::ResultCode error) {
948 DLOG(ERROR) << "Failure getting XPS capabilities of printer "
949 << printer_name << ", error: " << error;
950 return error;
951 });
Andy Phan65e73562022-11-02 17:06:47952
953 mojom::PrinterCapabilitiesValueResultPtr value_result;
Peter Kastingf115ece2023-08-07 21:09:44954 xml_parser_remote_->ParseXmlForPrinterCapabilities(xml, &value_result);
Andy Phan65e73562022-11-02 17:06:47955 if (value_result->is_result_code()) {
956 DLOG(ERROR) << "Failure parsing XML of XPS capabilities of printer "
Peter Kasting1841e692023-04-24 19:50:52957 << printer_name
958 << ", error: " << value_result->get_result_code();
Andy Phan65e73562022-11-02 17:06:47959 return base::unexpected(value_result->get_result_code());
960 }
961
Peter Kastinga7066c62023-04-25 02:39:31962 return ParseValueForXpsPrinterCapabilities(value_result->get_capabilities())
963 .transform_error([&](mojom::ResultCode code) {
964 DLOG(ERROR) << "Failure parsing value of XPS capabilities of printer "
965 << printer_name << ", error: " << code;
966 return code;
967 });
Andy Phan65e73562022-11-02 17:06:47968}
969#endif // BUILDFLAG(IS_WIN)
970
Alan Screen65304d52020-10-29 16:42:22971} // namespace printing