[go: nahoru, domu]

blob: d8a0c00cb1bf94d1bffb5bed8deed54c85d43c57 [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"
Alan Screen2166ab12021-09-01 23:09:2518#include "base/task/task_traits.h"
19#include "base/task/thread_pool.h"
Alan Screencb6421f2021-12-09 21:54:1820#include "base/threading/sequence_bound.h"
Alan Screen597675382021-09-11 05:14:5321#include "base/values.h"
Alan Screenc15aea62021-01-08 03:32:1222#include "build/build_config.h"
Alan Screenc7874de2022-09-01 21:00:1023#include "chrome/common/printing/printing_init.h"
Alan Screen65304d52020-10-29 16:42:2224#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
Alan Screen366ce3e2021-06-16 23:26:0425#include "components/crash/core/common/crash_keys.h"
Alan Screen65304d52020-10-29 16:42:2226#include "mojo/public/cpp/bindings/pending_receiver.h"
27#include "printing/backend/print_backend.h"
Alan Screenbd4f851a2022-03-29 22:53:0528#include "printing/metafile.h"
29#include "printing/metafile_skia.h"
Alan Screen8f86e142021-05-07 09:52:1930#include "printing/mojom/print.mojom.h"
Alan Screen61e1a372021-12-10 03:02:3431#include "printing/printed_document.h"
Alan Screen597675382021-09-11 05:14:5332#include "printing/printing_context.h"
Alan Screen252d9812022-03-29 20:12:0833#include "third_party/abseil-cpp/absl/types/optional.h"
Alan Screen65304d52020-10-29 16:42:2234
Xiaohan Wangd4bc2742022-01-15 19:48:5535#if BUILDFLAG(IS_MAC)
Alan Screenc15aea62021-01-08 03:32:1236#include "base/threading/thread_restrictions.h"
37#include "chrome/common/printing/printer_capabilities_mac.h"
38#endif
39
Xiaohan Wangd4bc2742022-01-15 19:48:5540#if BUILDFLAG(IS_CHROMEOS) && defined(USE_CUPS)
Alan Screen2166ab12021-09-01 23:09:2541#include "printing/backend/cups_connection_pool.h"
42#endif
43
Alan Screen65a66412022-09-24 02:29:2244#if BUILDFLAG(IS_LINUX)
45#include "base/no_destructor.h"
46#include "ui/linux/linux_ui.h"
47#include "ui/linux/linux_ui_delegate_stub.h"
48#include "ui/linux/linux_ui_factory.h"
49#endif
50
Xiaohan Wangd4bc2742022-01-15 19:48:5551#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:3452#include "base/containers/queue.h"
Andy Phan65e73562022-11-02 17:06:4753#include "base/types/expected.h"
Alan Screenc336bd862022-03-22 18:19:4154#include "base/win/win_util.h"
Andy Phand8ca2432022-10-14 21:11:5255#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
56#include "mojo/public/cpp/bindings/pending_remote.h"
57#include "mojo/public/cpp/bindings/remote.h"
Andy Phan65e73562022-11-02 17:06:4758#include "printing/backend/xps_utils_win.h"
Alan Screen61e1a372021-12-10 03:02:3459#include "printing/emf_win.h"
Alan Screen61e1a372021-12-10 03:02:3460#include "printing/printed_page_win.h"
Andy Phan65e73562022-11-02 17:06:4761#include "printing/printing_features.h"
Alan Screen61e1a372021-12-10 03:02:3462#include "ui/gfx/geometry/rect.h"
63#include "ui/gfx/geometry/size.h"
Alan Screenc336bd862022-03-22 18:19:4164#include "ui/gfx/native_widget_types.h"
Alan Screen61e1a372021-12-10 03:02:3465#endif
66
Alan Screen65304d52020-10-29 16:42:2267namespace printing {
68
Alan Screen2166ab12021-09-01 23:09:2569namespace {
70
Alan Screen65a66412022-09-24 02:29:2271#if BUILDFLAG(IS_LINUX)
72void InstantiateLinuxUiDelegate() {
73 // TODO(crbug.com/809738) Until a real UI can be used in a utility process,
74 // need to use the stub version.
75 static base::NoDestructor<ui::LinuxUiDelegateStub> linux_ui_delegate;
76}
77#endif
78
Alan Screen2166ab12021-09-01 23:09:2579scoped_refptr<base::SequencedTaskRunner> GetPrintingTaskRunner() {
80 static constexpr base::TaskTraits kTraits = {
81 base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
82
83#if defined(USE_CUPS)
84 // CUPS is thread safe, so a task runner can be allocated for each job.
85 scoped_refptr<base::SequencedTaskRunner> task_runner =
86 base::ThreadPool::CreateSequencedTaskRunner(kTraits);
Xiaohan Wangd4bc2742022-01-15 19:48:5587#elif BUILDFLAG(IS_WIN)
Alan Screen2166ab12021-09-01 23:09:2588 // For Windows, we want a single threaded task runner shared for all print
89 // jobs in the process because Windows printer drivers are oftentimes not
90 // thread-safe. This protects against multiple print jobs to the same device
91 // from running in the driver at the same time.
92 static scoped_refptr<base::SequencedTaskRunner> task_runner =
93 base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
94#else
95 // Be conservative for unsupported platforms, use a single threaded runner
96 // so that concurrent print jobs are not in driver code at the same time.
97 static scoped_refptr<base::SequencedTaskRunner> task_runner =
98 base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
99#endif
100
101 return task_runner;
102}
103
Xiaohan Wangd4bc2742022-01-15 19:48:55104#if BUILDFLAG(IS_WIN)
Alan Screenc336bd862022-03-22 18:19:41105void OnDidAskUserForSettings(
106 std::unique_ptr<PrintingContext> context,
107 mojom::PrintBackendService::AskUserForSettingsCallback callback,
108 mojom::ResultCode result) {
109 if (result != mojom::ResultCode::kSuccess) {
110 DLOG(ERROR) << "Did not get user settings, error: " << result;
111 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
112 return;
113 }
114 std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
115 *context->TakeAndResetSettings()));
116}
Alan Screenbd4f851a2022-03-29 22:53:05117#endif // BUILDFLAG(IS_WIN)
Alan Screenc336bd862022-03-22 18:19:41118
Alan Screen61e1a372021-12-10 03:02:34119std::unique_ptr<Metafile> CreateMetafile(mojom::MetafileDataType data_type) {
120 switch (data_type) {
121 case mojom::MetafileDataType::kPDF:
122 return std::make_unique<MetafileSkia>();
Alan Screenbd4f851a2022-03-29 22:53:05123#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34124 case mojom::MetafileDataType::kEMF:
125 return std::make_unique<Emf>();
Alan Screenbd4f851a2022-03-29 22:53:05126#endif
Alan Screen61e1a372021-12-10 03:02:34127 }
128}
Alan Screen252d9812022-03-29 20:12:08129
130struct RenderData {
131 std::unique_ptr<uint8_t[]> data_copy;
132 std::unique_ptr<Metafile> metafile;
133};
134
135absl::optional<RenderData> PrepareRenderData(
136 int document_cookie,
137 mojom::MetafileDataType page_data_type,
138 const base::ReadOnlySharedMemoryRegion& serialized_data) {
139 base::ReadOnlySharedMemoryMapping mapping = serialized_data.Map();
140 if (!mapping.IsValid()) {
141 DLOG(ERROR) << "Failure printing document " << document_cookie
142 << ", cannot map input.";
143 return absl::nullopt;
144 }
145
146 RenderData render_data;
147 render_data.metafile = CreateMetafile(page_data_type);
148
149 // For security reasons we need to use a copy of the data, and not operate
150 // on it directly out of shared memory. Make a copy here if the underlying
151 // `Metafile` implementation doesn't do it automatically.
152 // TODO(crbug.com/1135729) Eliminate this copy when the shared memory can't
153 // be written by the sender.
154 base::span<const uint8_t> data = mapping.GetMemoryAsSpan<uint8_t>();
155 if (render_data.metafile->ShouldCopySharedMemoryRegionData()) {
156 render_data.data_copy = std::make_unique<uint8_t[]>(data.size());
Peter Kasting965f02fc2022-10-28 23:35:43157 base::ranges::copy(data, render_data.data_copy.get());
Alan Screen252d9812022-03-29 20:12:08158 data = base::span<const uint8_t>(render_data.data_copy.get(), data.size());
159 }
160 if (!render_data.metafile->InitFromData(data)) {
161 DLOG(ERROR) << "Failure printing document " << document_cookie
162 << ", unable to initialize.";
163 return absl::nullopt;
164 }
165 return render_data;
166}
Alan Screen61e1a372021-12-10 03:02:34167
Alan Screen2166ab12021-09-01 23:09:25168// Local storage of document and associated data needed to submit to job to
Alan Screencb6421f2021-12-09 21:54:18169// the operating system's printing API. All access to the document occurs on
170// a worker task runner.
171class DocumentContainer {
172 public:
173 DocumentContainer(PrintingContext::Delegate* context_delegate,
174 scoped_refptr<PrintedDocument> document,
175 mojom::PrintTargetType target_type)
176 : context_delegate_(context_delegate),
177 document_(document),
178 target_type_(target_type) {}
Alan Screen2166ab12021-09-01 23:09:25179
180 ~DocumentContainer() = default;
181
Alan Screen61e1a372021-12-10 03:02:34182 // Helper functions that runs on a task runner.
Alan Screencb6421f2021-12-09 21:54:18183 mojom::ResultCode StartPrintingReadyDocument();
Xiaohan Wangd4bc2742022-01-15 19:48:55184#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34185 mojom::ResultCode DoRenderPrintedPage(
186 uint32_t page_index,
187 mojom::MetafileDataType page_data_type,
188 base::ReadOnlySharedMemoryRegion serialized_page,
189 gfx::Size page_size,
190 gfx::Rect page_content_rect,
191 float shrink_factor);
192#endif
Alan Screenbd4f851a2022-03-29 22:53:05193 mojom::ResultCode DoRenderPrintedDocument(
Alan Screena6cebd82022-11-03 19:56:29194 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05195 mojom::MetafileDataType data_type,
196 base::ReadOnlySharedMemoryRegion serialized_document);
Alan Screen6bf1d5fb2022-02-08 15:51:14197 mojom::ResultCode DoDocumentDone();
Alan Screen2a7dcc92022-11-17 04:52:01198 void DoCancel();
Alan Screencb6421f2021-12-09 21:54:18199
200 private:
Keishi Hattorie175ac52022-06-07 06:24:57201 raw_ptr<PrintingContext::Delegate> context_delegate_;
Alan Screencb6421f2021-12-09 21:54:18202 scoped_refptr<PrintedDocument> document_;
Alan Screen2166ab12021-09-01 23:09:25203
204 // `context` is not initialized until the document is ready for printing.
Alan Screencb6421f2021-12-09 21:54:18205 std::unique_ptr<PrintingContext> context_;
Alan Screen2166ab12021-09-01 23:09:25206
Alan Screencb6421f2021-12-09 21:54:18207 // Parameter required for the delayed call to `UpdatePrinterSettings()`.
208 mojom::PrintTargetType target_type_;
Alan Screen2166ab12021-09-01 23:09:25209
Alan Screencb6421f2021-12-09 21:54:18210 // Ensure all interactions for this document are issued from the same runner.
211 SEQUENCE_CHECKER(sequence_checker_);
212};
213
214mojom::ResultCode DocumentContainer::StartPrintingReadyDocument() {
215 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
216
217 DVLOG(1) << "Start printing for document " << document_->cookie();
218
219 // Create a printing context that will work with this document for the
220 // duration of the print job.
221 context_ =
222 PrintingContext::Create(context_delegate_, /*skip_system_calls=*/false);
223
224 // With out-of-process printing the printer settings no longer get updated
225 // from `PrintingContext::UpdatePrintSettings()`, so we need to apply that
226 // now to our new context.
227 // TODO(crbug.com/1245679) Replumb `mojom::PrintTargetType` into
228 // `PrintingContext::UpdatePrinterSettings()`.
229 PrintingContext::PrinterSettings printer_settings {
Xiaohan Wangd4bc2742022-01-15 19:48:55230#if BUILDFLAG(IS_MAC)
Alan Screencb6421f2021-12-09 21:54:18231 .external_preview =
232 target_type_ == mojom::PrintTargetType::kExternalPreview,
233#endif
234 .show_system_dialog = target_type_ == mojom::PrintTargetType::kSystemDialog,
Xiaohan Wangd4bc2742022-01-15 19:48:55235#if BUILDFLAG(IS_WIN)
Alan Screencb6421f2021-12-09 21:54:18236 .page_count = 0,
237#endif
238 };
239 context_->ApplyPrintSettings(document_->settings());
240 mojom::ResultCode result = context_->UpdatePrinterSettings(printer_settings);
241 if (result != mojom::ResultCode::kSuccess) {
242 DLOG(ERROR) << "Failure updating printer settings for document "
243 << document_->cookie() << ", error: " << result;
244 return result;
245 }
246
247 result = context_->NewDocument(document_->name());
248 if (result != mojom::ResultCode::kSuccess) {
249 DLOG(ERROR) << "Failure initializing new document " << document_->cookie()
250 << ", error: " << result;
251 return result;
252 }
253
254 return mojom::ResultCode::kSuccess;
255}
256
Xiaohan Wangd4bc2742022-01-15 19:48:55257#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34258mojom::ResultCode DocumentContainer::DoRenderPrintedPage(
259 uint32_t page_index,
260 mojom::MetafileDataType page_data_type,
261 base::ReadOnlySharedMemoryRegion serialized_page,
262 gfx::Size page_size,
263 gfx::Rect page_content_rect,
264 float shrink_factor) {
265 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
266
267 DVLOG(1) << "Render printed page " << page_index << " for document "
268 << document_->cookie();
269
Alan Screen252d9812022-03-29 20:12:08270 absl::optional<RenderData> render_data =
271 PrepareRenderData(document_->cookie(), page_data_type, serialized_page);
272 if (!render_data)
Alan Screen61e1a372021-12-10 03:02:34273 return mojom::ResultCode::kFailed;
Alan Screen61e1a372021-12-10 03:02:34274
Alan Screen252d9812022-03-29 20:12:08275 document_->SetPage(page_index, std::move(render_data->metafile),
276 shrink_factor, page_size, page_content_rect);
Alan Screen61e1a372021-12-10 03:02:34277
Alan Screen0ad9df72022-09-27 18:34:35278 mojom::ResultCode result = document_->RenderPrintedPage(
279 *document_->GetPage(page_index), context_.get());
280 if (result != mojom::ResultCode::kSuccess) {
281 DLOG(ERROR) << "Failure rendering page " << page_index << " of document "
282 << document_->cookie() << ", error: " << result;
283 return result;
284 }
285
286 return mojom::ResultCode::kSuccess;
Alan Screen61e1a372021-12-10 03:02:34287}
Xiaohan Wangd4bc2742022-01-15 19:48:55288#endif // BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34289
Alan Screenbd4f851a2022-03-29 22:53:05290mojom::ResultCode DocumentContainer::DoRenderPrintedDocument(
Alan Screena6cebd82022-11-03 19:56:29291 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05292 mojom::MetafileDataType data_type,
293 base::ReadOnlySharedMemoryRegion serialized_document) {
294 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
295
296 DVLOG(1) << "Render printed document " << document_->cookie();
297
298 absl::optional<RenderData> render_data =
299 PrepareRenderData(document_->cookie(), data_type, serialized_document);
300 if (!render_data)
301 return mojom::ResultCode::kFailed;
302
Alan Screena6cebd82022-11-03 19:56:29303 document_->set_page_count(page_count);
Alan Screenbd4f851a2022-03-29 22:53:05304 document_->SetDocument(std::move(render_data->metafile));
305
306 return document_->RenderPrintedDocument(context_.get());
307}
308
Alan Screen6bf1d5fb2022-02-08 15:51:14309mojom::ResultCode DocumentContainer::DoDocumentDone() {
310 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
311
312 DVLOG(1) << "Document done for document " << document_->cookie();
313 return context_->DocumentDone();
314}
315
Alan Screen2a7dcc92022-11-17 04:52:01316void DocumentContainer::DoCancel() {
317 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
318
319 DVLOG(1) << "Canceling document " << document_->cookie();
320 context_->Cancel();
321}
322
Alan Screencb6421f2021-12-09 21:54:18323} // namespace
324
325// Helper for managing `DocumentContainer` objects. All access to this occurs
326// on the main thread.
327class PrintBackendServiceImpl::DocumentHelper {
328 public:
329 DocumentHelper(
330 int document_cookie,
331 base::SequenceBound<DocumentContainer> document_container,
332 mojom::PrintBackendService::StartPrintingCallback start_printing_callback)
333 : document_cookie_(document_cookie),
334 document_container_(std::move(document_container)),
335 start_printing_callback_(std::move(start_printing_callback)) {}
336
337 ~DocumentHelper() = default;
338
339 int document_cookie() const {
340 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
341 return document_cookie_;
342 }
343
344 base::SequenceBound<DocumentContainer>& document_container() {
345 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
346 return document_container_;
347 }
348
349 mojom::PrintBackendService::StartPrintingCallback
350 TakeStartPrintingCallback() {
351 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
352 return std::move(start_printing_callback_);
353 }
354
355 private:
356 const int document_cookie_;
357
358 base::SequenceBound<DocumentContainer> document_container_;
359
360 // `start_printing_callback_` is held until the document is ready for
Alan Screen2166ab12021-09-01 23:09:25361 // printing.
Alan Screencb6421f2021-12-09 21:54:18362 mojom::PrintBackendService::StartPrintingCallback start_printing_callback_;
Alan Screen2166ab12021-09-01 23:09:25363
Alan Screencb6421f2021-12-09 21:54:18364 // Ensure all interactions for this document are issued from the same runner.
365 SEQUENCE_CHECKER(sequence_checker_);
Alan Screen2166ab12021-09-01 23:09:25366};
367
Alex Gough59a0e962021-09-30 23:42:44368// Sandboxed service helper.
369SandboxedPrintBackendHostImpl::SandboxedPrintBackendHostImpl(
370 mojo::PendingReceiver<mojom::SandboxedPrintBackendHost> receiver)
371 : receiver_(this, std::move(receiver)) {}
372
373SandboxedPrintBackendHostImpl::~SandboxedPrintBackendHostImpl() = default;
374
375void SandboxedPrintBackendHostImpl::BindBackend(
376 mojo::PendingReceiver<mojom::PrintBackendService> receiver) {
377 CHECK(!print_backend_service_)
378 << "Cannot bind service twice in same process.";
379 print_backend_service_ =
380 std::make_unique<PrintBackendServiceImpl>(std::move(receiver));
381}
382
383// Unsandboxed service helper.
384UnsandboxedPrintBackendHostImpl::UnsandboxedPrintBackendHostImpl(
385 mojo::PendingReceiver<mojom::UnsandboxedPrintBackendHost> receiver)
386 : receiver_(this, std::move(receiver)) {}
387
388UnsandboxedPrintBackendHostImpl::~UnsandboxedPrintBackendHostImpl() = default;
389
390void UnsandboxedPrintBackendHostImpl::BindBackend(
391 mojo::PendingReceiver<mojom::PrintBackendService> receiver) {
392 CHECK(!print_backend_service_)
393 << "Cannot bind service twice in same process.";
394 print_backend_service_ =
395 std::make_unique<PrintBackendServiceImpl>(std::move(receiver));
396}
397
Alan Screen2166ab12021-09-01 23:09:25398PrintBackendServiceImpl::PrintingContextDelegate::PrintingContextDelegate() =
399 default;
400PrintBackendServiceImpl::PrintingContextDelegate::~PrintingContextDelegate() =
401 default;
402
403gfx::NativeView
404PrintBackendServiceImpl::PrintingContextDelegate::GetParentView() {
Alan Screenc336bd862022-03-22 18:19:41405#if BUILDFLAG(IS_WIN)
406 return parent_native_view_;
407#else
Alan Screen2166ab12021-09-01 23:09:25408 NOTREACHED();
409 return nullptr;
Alan Screenc336bd862022-03-22 18:19:41410#endif
Alan Screen2166ab12021-09-01 23:09:25411}
412
413std::string PrintBackendServiceImpl::PrintingContextDelegate::GetAppLocale() {
414 return locale_;
415}
416
Alan Screenc336bd862022-03-22 18:19:41417#if BUILDFLAG(IS_WIN)
418void PrintBackendServiceImpl::PrintingContextDelegate::SetParentWindow(
419 uint32_t parent_window_id) {
420 parent_native_view_ = reinterpret_cast<gfx::NativeView>(
421 base::win::Uint32ToHandle(parent_window_id));
422}
423#endif
424
Alan Screen2166ab12021-09-01 23:09:25425void PrintBackendServiceImpl::PrintingContextDelegate::SetAppLocale(
426 const std::string& locale) {
427 locale_ = locale;
428}
429
Alan Screen65304d52020-10-29 16:42:22430PrintBackendServiceImpl::PrintBackendServiceImpl(
431 mojo::PendingReceiver<mojom::PrintBackendService> receiver)
432 : receiver_(this, std::move(receiver)) {}
433
434PrintBackendServiceImpl::~PrintBackendServiceImpl() = default;
435
Andy Phan5f3db322022-11-11 19:53:02436void PrintBackendServiceImpl::InitCommon(
437#if BUILDFLAG(IS_WIN)
438 const std::string& locale,
439 mojo::PendingRemote<mojom::PrinterXmlParser> remote
440#else
441 const std::string& locale
442#endif // BUILDFLAG(IS_WIN)
443) {
Alan Screen71ef2a02022-09-19 23:48:55444 context_delegate_.SetAppLocale(locale);
Andy Phan5f3db322022-11-11 19:53:02445#if BUILDFLAG(IS_WIN)
446 if (remote.is_valid())
447 xml_parser_remote_.Bind(std::move(remote));
448#endif // BUILDFLAG(IS_WIN)
Alan Screen71ef2a02022-09-19 23:48:55449}
450
Andy Phan5f3db322022-11-11 19:53:02451void PrintBackendServiceImpl::Init(
452#if BUILDFLAG(IS_WIN)
453 const std::string& locale,
454 mojo::PendingRemote<mojom::PrinterXmlParser> remote
455#else
456 const std::string& locale
457#endif // BUILDFLAG(IS_WIN)
458) {
Alan Screen71ef2a02022-09-19 23:48:55459 // Test classes should not invoke this base initialization method, as process
460 // initialization is very different for test frameworks. Test classes
461 // will also provide their own test version of a `PrintBackend`.
462 // Common initialization for production and testing should instead reside in
463 // `InitCommon()`.
Alan Screenc7874de2022-09-01 21:00:10464 InitializeProcessForPrinting();
Alan Screen65304d52020-10-29 16:42:22465 print_backend_ = PrintBackend::CreateInstance(locale);
Alan Screen65a66412022-09-24 02:29:22466#if BUILDFLAG(IS_LINUX)
467 // Test framework already initializes the UI, so this should not go in
468 // `InitCommon()`. Additionally, low-level Linux UI is not needed when tests
469 // are using `TestPrintingContext`.
470 InstantiateLinuxUiDelegate();
471 ui::LinuxUi::SetInstance(ui::GetDefaultLinuxUi());
Andy Phan5f3db322022-11-11 19:53:02472#endif // BUILDFLAG(IS_LINUX)
Alan Screen71ef2a02022-09-19 23:48:55473
Andy Phan5f3db322022-11-11 19:53:02474#if BUILDFLAG(IS_WIN)
475 InitCommon(locale, std::move(remote));
476#else
Alan Screen71ef2a02022-09-19 23:48:55477 InitCommon(locale);
Andy Phan5f3db322022-11-11 19:53:02478#endif // BUILDFLAG(IS_WIN)
Alan Screen65304d52020-10-29 16:42:22479}
480
Alan Screen5754f542021-07-09 00:43:50481// TODO(crbug.com/1225111) Do nothing, this is just to assist an idle timeout
482// change by providing a low-cost call to ensure it is applied.
483void PrintBackendServiceImpl::Poke() {}
484
Alan Screen2a5c54262021-02-11 10:44:29485void PrintBackendServiceImpl::EnumeratePrinters(
486 mojom::PrintBackendService::EnumeratePrintersCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24487 DCHECK(print_backend_);
Alan Screen2a5c54262021-02-11 10:44:29488 PrinterList printer_list;
Alan Screenb92927f2022-06-14 21:27:20489 mojom::ResultCode result = print_backend_->EnumeratePrinters(printer_list);
Alan Screen5ad643b2021-05-13 16:40:18490 if (result != mojom::ResultCode::kSuccess) {
491 std::move(callback).Run(mojom::PrinterListResult::NewResultCode(result));
Alan Screen2a5c54262021-02-11 10:44:29492 return;
493 }
Alan Screen5ad643b2021-05-13 16:40:18494 std::move(callback).Run(
495 mojom::PrinterListResult::NewPrinterList(std::move(printer_list)));
Alan Screen2a5c54262021-02-11 10:44:29496}
497
Alan Screen65304d52020-10-29 16:42:22498void PrintBackendServiceImpl::GetDefaultPrinterName(
499 mojom::PrintBackendService::GetDefaultPrinterNameCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24500 DCHECK(print_backend_);
Alan Screen322ed6182021-06-03 15:26:47501 std::string default_printer;
502 mojom::ResultCode result =
503 print_backend_->GetDefaultPrinterName(default_printer);
504 if (result != mojom::ResultCode::kSuccess) {
505 std::move(callback).Run(
506 mojom::DefaultPrinterNameResult::NewResultCode(result));
507 return;
508 }
509 std::move(callback).Run(
510 mojom::DefaultPrinterNameResult::NewDefaultPrinterName(default_printer));
Alan Screen65304d52020-10-29 16:42:22511}
512
Alan Screend00ff1d2020-12-08 04:17:40513void PrintBackendServiceImpl::GetPrinterSemanticCapsAndDefaults(
514 const std::string& printer_name,
515 mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
516 callback) {
Alan Screen7a30b042022-09-19 17:51:24517 DCHECK(print_backend_);
Alan Screen366ce3e2021-06-16 23:26:04518 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
519 print_backend_->GetPrinterDriverInfo(printer_name));
520
Alan Screend00ff1d2020-12-08 04:17:40521 PrinterSemanticCapsAndDefaults printer_caps;
Alan Screen8f86e142021-05-07 09:52:19522 const mojom::ResultCode result =
523 print_backend_->GetPrinterSemanticCapsAndDefaults(printer_name,
524 &printer_caps);
525 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18526 std::move(callback).Run(
527 mojom::PrinterSemanticCapsAndDefaultsResult::NewResultCode(result));
Alan Screend00ff1d2020-12-08 04:17:40528 return;
529 }
Alan Screen5ad643b2021-05-13 16:40:18530 std::move(callback).Run(
531 mojom::PrinterSemanticCapsAndDefaultsResult::NewPrinterCaps(
532 std::move(printer_caps)));
Alan Screend00ff1d2020-12-08 04:17:40533}
534
Alan Screenc15aea62021-01-08 03:32:12535void PrintBackendServiceImpl::FetchCapabilities(
536 const std::string& printer_name,
537 mojom::PrintBackendService::FetchCapabilitiesCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24538 DCHECK(print_backend_);
Alan Screen366ce3e2021-06-16 23:26:04539 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
540 print_backend_->GetPrinterDriverInfo(printer_name));
541
Alan Screenc15aea62021-01-08 03:32:12542 PrinterSemanticCapsAndDefaults::Papers user_defined_papers;
Xiaohan Wangd4bc2742022-01-15 19:48:55543#if BUILDFLAG(IS_MAC)
Alan Screenc15aea62021-01-08 03:32:12544 {
545 // Blocking is needed here for when macOS reads paper sizes from file.
546 //
547 // Fetching capabilities in the browser process happens from the thread
548 // pool with the MayBlock() trait for macOS. However this call can also
549 // run from a utility process's main thread where blocking is not
550 // implicitly allowed. In order to preserve ordering, the utility process
551 // must process this synchronously by blocking.
552 //
553 // TODO(crbug.com/1163635): Investigate whether utility process main
554 // thread should be allowed to block like in-process workers are.
555 base::ScopedAllowBlocking allow_blocking;
556 user_defined_papers = GetMacCustomPaperSizes();
557 }
558#endif
559
560 PrinterBasicInfo printer_info;
Alan Screen8f86e142021-05-07 09:52:19561 mojom::ResultCode result =
Alan Screenc15aea62021-01-08 03:32:12562 print_backend_->GetPrinterBasicInfo(printer_name, &printer_info);
Alan Screen8f86e142021-05-07 09:52:19563 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18564 std::move(callback).Run(
565 mojom::PrinterCapsAndInfoResult::NewResultCode(result));
Alan Screenc15aea62021-01-08 03:32:12566 return;
567 }
568 PrinterSemanticCapsAndDefaults caps;
569 result =
570 print_backend_->GetPrinterSemanticCapsAndDefaults(printer_name, &caps);
Alan Screen8f86e142021-05-07 09:52:19571 if (result != mojom::ResultCode::kSuccess) {
Alan Screen5ad643b2021-05-13 16:40:18572 std::move(callback).Run(
573 mojom::PrinterCapsAndInfoResult::NewResultCode(result));
Alan Screenc15aea62021-01-08 03:32:12574 return;
575 }
Andy Phan65e73562022-11-02 17:06:47576#if BUILDFLAG(IS_WIN)
577 if (xml_parser_remote_.is_bound() &&
578 base::FeatureList::IsEnabled(features::kReadPrinterCapabilitiesWithXps)) {
579 base::expected<XpsCapabilities, mojom::ResultCode> xps_capabilities =
580 GetXpsCapabilities(printer_name);
581 if (!xps_capabilities.has_value()) {
582 std::move(callback).Run(mojom::PrinterCapsAndInfoResult::NewResultCode(
583 xps_capabilities.error()));
584 return;
585 }
586
587 MergeXpsCapabilities(std::move(xps_capabilities.value()), caps);
588 }
589#endif // BUILDFLAG(IS_WIN)
Alan Screen5ad643b2021-05-13 16:40:18590 mojom::PrinterCapsAndInfoPtr caps_and_info = mojom::PrinterCapsAndInfo::New(
591 std::move(printer_info), std::move(user_defined_papers), std::move(caps));
592 std::move(callback).Run(
593 mojom::PrinterCapsAndInfoResult::NewPrinterCapsAndInfo(
594 std::move(caps_and_info)));
Alan Screenc15aea62021-01-08 03:32:12595}
596
Alan Screenfa756fb2022-02-15 00:02:24597void PrintBackendServiceImpl::UseDefaultSettings(
598 mojom::PrintBackendService::UseDefaultSettingsCallback callback) {
Alan Screenfa756fb2022-02-15 00:02:24599 // Use a one-time `PrintingContext` to get the print settings.
600 std::unique_ptr<PrintingContext> context =
601 PrintingContext::Create(&context_delegate_, /*skip_system_calls=*/false);
602 mojom::ResultCode result = context.get()->UseDefaultSettings();
603 if (result != mojom::ResultCode::kSuccess) {
Alan Screen01cd3bc2022-02-15 02:38:47604 DLOG(ERROR) << "Failure getting default settings of default printer, "
605 << "error: " << result;
Alan Screenfa756fb2022-02-15 00:02:24606 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
607 return;
608 }
609 std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
610 *context->TakeAndResetSettings()));
611}
612
Alan Screenc336bd862022-03-22 18:19:41613#if BUILDFLAG(IS_WIN)
614void PrintBackendServiceImpl::AskUserForSettings(
615 uint32_t parent_window_id,
616 int max_pages,
617 bool has_selection,
618 bool is_scripted,
619 mojom::PrintBackendService::AskUserForSettingsCallback callback) {
Alan Screenc336bd862022-03-22 18:19:41620 // Provide the window which owns the print dialog. On Windows the call to
621 // `AskUserForSettings()` is a blocking call. Additionally, the browser
622 // process is to have logic to avoid even making a concurrent call to the
623 // service. That means there is no concern here about a possible concurrent
624 // call overwriting the parent window ID of `context_delegate_`.
625 // TODO(crbug.com/809738) When updating for Linux, add extra protection to
626 // guarantee that the parent window ID cannot be overwritten by a concurrent
627 // system print request.
628 context_delegate_.SetParentWindow(parent_window_id);
629
630 // Use a one-time `PrintingContext` to ask for the print settings.
631 // We do not yet know which device (if any) will be selected.
632 std::unique_ptr<PrintingContext> context =
633 PrintingContext::Create(&context_delegate_, /*skip_system_calls=*/false);
634 PrintingContext* context_ptr = context.get();
635 context_ptr->AskUserForSettings(
636 max_pages, has_selection, is_scripted,
637 base::BindOnce(&OnDidAskUserForSettings, std::move(context),
638 std::move(callback)));
639}
640#endif // BUILDFLAG(IS_WIN)
641
Alan Screen597675382021-09-11 05:14:53642void PrintBackendServiceImpl::UpdatePrintSettings(
Lei Zhang15e92b92022-04-12 20:06:23643 base::Value::Dict job_settings,
Alan Screen597675382021-09-11 05:14:53644 mojom::PrintBackendService::UpdatePrintSettingsCallback callback) {
Alan Screen7a30b042022-09-19 17:51:24645 DCHECK(print_backend_);
Alan Screen597675382021-09-11 05:14:53646
Lei Zhang15e92b92022-04-12 20:06:23647 const std::string* printer_name = job_settings.FindString(kSettingDeviceName);
Alan Screen7a30b042022-09-19 17:51:24648 DCHECK(printer_name);
Alan Screen597675382021-09-11 05:14:53649
650 crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
Lei Zhang15e92b92022-04-12 20:06:23651 print_backend_->GetPrinterDriverInfo(*printer_name));
Alan Screen597675382021-09-11 05:14:53652
Xiaohan Wangd4bc2742022-01-15 19:48:55653#if BUILDFLAG(IS_LINUX) && defined(USE_CUPS)
Alan Screen597675382021-09-11 05:14:53654 // Try to fill in advanced settings based upon basic info options.
655 PrinterBasicInfo basic_info;
Lei Zhang15e92b92022-04-12 20:06:23656 if (print_backend_->GetPrinterBasicInfo(*printer_name, &basic_info) ==
Alan Screen597675382021-09-11 05:14:53657 mojom::ResultCode::kSuccess) {
Lei Zhang15e92b92022-04-12 20:06:23658 base::Value::Dict advanced_settings;
Alan Screen597675382021-09-11 05:14:53659 for (const auto& pair : basic_info.options)
Lei Zhang15e92b92022-04-12 20:06:23660 advanced_settings.Set(pair.first, pair.second);
Alan Screen597675382021-09-11 05:14:53661
Lei Zhang15e92b92022-04-12 20:06:23662 job_settings.Set(kSettingAdvancedSettings, std::move(advanced_settings));
Alan Screen597675382021-09-11 05:14:53663 }
Xiaohan Wangd4bc2742022-01-15 19:48:55664#endif // BUILDFLAG(IS_LINUX) && defined(USE_CUPS)
Alan Screen597675382021-09-11 05:14:53665
666 // Use a one-time `PrintingContext` to do the update to print settings.
667 // Intentionally do not cache this context here since the process model does
668 // not guarantee that we will return to this same process when
669 // `StartPrinting()` might be called.
670 std::unique_ptr<PrintingContext> context =
Alan Screene9ed54a2021-11-24 18:22:46671 PrintingContext::Create(&context_delegate_, /*skip_system_calls=*/false);
Alan Screen202e49a2021-09-21 06:34:28672 mojom::ResultCode result =
Lei Zhang4bc852972022-04-12 20:22:19673 context->UpdatePrintSettings(std::move(job_settings));
Alan Screen597675382021-09-11 05:14:53674
Alan Screen202e49a2021-09-21 06:34:28675 if (result != mojom::ResultCode::kSuccess) {
676 std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(result));
Alan Screen597675382021-09-11 05:14:53677 return;
678 }
679
680 std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
681 *context->TakeAndResetSettings()));
682}
683
Alan Screen2166ab12021-09-01 23:09:25684void PrintBackendServiceImpl::StartPrinting(
685 int document_cookie,
686 const std::u16string& document_name,
687 mojom::PrintTargetType target_type,
Alan Screen2166ab12021-09-01 23:09:25688 const PrintSettings& settings,
689 mojom::PrintBackendService::StartPrintingCallback callback) {
Xiaohan Wangd4bc2742022-01-15 19:48:55690#if BUILDFLAG(IS_CHROMEOS) && defined(USE_CUPS)
Alan Screen2166ab12021-09-01 23:09:25691 CupsConnectionPool* connection_pool = CupsConnectionPool::GetInstance();
692 if (connection_pool) {
693 // If a pool exists then this document can only proceed with printing if
694 // there is a connection available for use by a `PrintingContext`.
695 if (!connection_pool->IsConnectionAvailable()) {
696 // This document has to wait until a connection becomes available. Hold
697 // off on issuing the callback.
698 // TODO(crbug.com/809738) Place this in a queue of waiting jobs.
699 DLOG(ERROR) << "Need queue for print jobs awaiting a connection";
700 std::move(callback).Run(mojom::ResultCode::kFailed);
701 return;
702 }
703 }
704#endif
705
Alan Screen4b7ebf782021-12-07 19:10:02706 // Save all the document settings for use through the print job, until the
707 // time that this document can complete printing. Track the order of
708 // received documents with position in `documents_`.
709 auto document = base::MakeRefCounted<PrintedDocument>(
710 std::make_unique<PrintSettings>(settings), document_name,
711 document_cookie);
Alan Screencb6421f2021-12-09 21:54:18712 base::SequenceBound<DocumentContainer> document_container(
713 GetPrintingTaskRunner(), &context_delegate_, document, target_type);
714 documents_.push_back(std::make_unique<DocumentHelper>(
715 document_cookie, std::move(document_container), std::move(callback)));
716 DocumentHelper& document_helper = *documents_.back();
Alan Screen4b7ebf782021-12-07 19:10:02717
Alan Screencb6421f2021-12-09 21:54:18718 // Safe to use `base::Unretained(this)` because `this` outlives the async
719 // call and callback. The entire service process goes away when `this`
720 // lifetime expires.
721 document_helper.document_container()
722 .AsyncCall(&DocumentContainer::StartPrintingReadyDocument)
723 .Then(base::BindOnce(
724 &PrintBackendServiceImpl::OnDidStartPrintingReadyDocument,
725 base::Unretained(this), std::ref(document_helper)));
Alan Screen2166ab12021-09-01 23:09:25726}
727
Xiaohan Wangd4bc2742022-01-15 19:48:55728#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34729void PrintBackendServiceImpl::RenderPrintedPage(
730 int32_t document_cookie,
731 uint32_t page_index,
732 mojom::MetafileDataType page_data_type,
733 base::ReadOnlySharedMemoryRegion serialized_page,
734 const gfx::Size& page_size,
735 const gfx::Rect& page_content_rect,
736 float shrink_factor,
737 mojom::PrintBackendService::RenderPrintedPageCallback callback) {
Alan Screen61e1a372021-12-10 03:02:34738 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24739 DCHECK(document_helper);
Alan Screen61e1a372021-12-10 03:02:34740
741 // Safe to use `base::Unretained(this)` because `this` outlives the async
742 // call and callback. The entire service process goes away when `this`
743 // lifetime expires.
744 document_helper->document_container()
745 .AsyncCall(&DocumentContainer::DoRenderPrintedPage)
746 .WithArgs(page_index, page_data_type, std::move(serialized_page),
747 page_size, page_content_rect, shrink_factor)
748 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidRenderPrintedPage,
749 base::Unretained(this), std::ref(*document_helper),
750 std::move(callback)));
751}
Xiaohan Wangd4bc2742022-01-15 19:48:55752#endif // BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34753
Alan Screenbd4f851a2022-03-29 22:53:05754void PrintBackendServiceImpl::RenderPrintedDocument(
755 int32_t document_cookie,
Alan Screena6cebd82022-11-03 19:56:29756 uint32_t page_count,
Alan Screenbd4f851a2022-03-29 22:53:05757 mojom::MetafileDataType data_type,
758 base::ReadOnlySharedMemoryRegion serialized_document,
759 mojom::PrintBackendService::RenderPrintedDocumentCallback callback) {
Alan Screenbd4f851a2022-03-29 22:53:05760 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24761 DCHECK(document_helper);
Alan Screenbd4f851a2022-03-29 22:53:05762
763 // Safe to use `base::Unretained(this)` because `this` outlives the async
764 // call and callback. The entire service process goes away when `this`
765 // lifetime expires.
766 document_helper->document_container()
767 .AsyncCall(&DocumentContainer::DoRenderPrintedDocument)
Alan Screena6cebd82022-11-03 19:56:29768 .WithArgs(page_count, data_type, std::move(serialized_document))
Alan Screenbd4f851a2022-03-29 22:53:05769 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidRenderPrintedDocument,
770 base::Unretained(this), std::ref(*document_helper),
771 std::move(callback)));
772}
773
Alan Screen6bf1d5fb2022-02-08 15:51:14774void PrintBackendServiceImpl::DocumentDone(
775 int document_cookie,
776 mojom::PrintBackendService::DocumentDoneCallback callback) {
Alan Screen6bf1d5fb2022-02-08 15:51:14777 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
Alan Screen7a30b042022-09-19 17:51:24778 DCHECK(document_helper);
Alan Screen6bf1d5fb2022-02-08 15:51:14779
780 // Safe to use `base::Unretained(this)` because `this` outlives the async
781 // call and callback. The entire service process goes away when `this`
782 // lifetime expires.
783 document_helper->document_container()
784 .AsyncCall(&DocumentContainer::DoDocumentDone)
785 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidDocumentDone,
786 base::Unretained(this), std::ref(*document_helper),
787 std::move(callback)));
788}
789
Alan Screen2a7dcc92022-11-17 04:52:01790void PrintBackendServiceImpl::Cancel(
791 int document_cookie,
792 mojom::PrintBackendService::CancelCallback callback) {
793 DCHECK(print_backend_);
794 DocumentHelper* document_helper = GetDocumentHelper(document_cookie);
795 DCHECK(document_helper);
796
797 // Safe to use `base::Unretained(this)` because `this` outlives the async
798 // call and callback. The entire service process goes away when `this`
799 // lifetime expires.
800 document_helper->document_container()
801 .AsyncCall(&DocumentContainer::DoCancel)
802 .Then(base::BindOnce(&PrintBackendServiceImpl::OnDidCancel,
803 base::Unretained(this), std::ref(*document_helper),
804 std::move(callback)));
805}
806
Alan Screen2166ab12021-09-01 23:09:25807void PrintBackendServiceImpl::OnDidStartPrintingReadyDocument(
Alan Screencb6421f2021-12-09 21:54:18808 DocumentHelper& document_helper,
Alan Screen2166ab12021-09-01 23:09:25809 mojom::ResultCode result) {
Alan Screen61e1a372021-12-10 03:02:34810 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
Alan Screencb6421f2021-12-09 21:54:18811 document_helper.TakeStartPrintingCallback().Run(result);
Alan Screen2166ab12021-09-01 23:09:25812 if (result == mojom::ResultCode::kSuccess)
813 return;
814
815 // Remove this document due to the failure to do setup.
Alan Screen61e1a372021-12-10 03:02:34816 RemoveDocumentHelper(document_helper);
817}
818
Xiaohan Wangd4bc2742022-01-15 19:48:55819#if BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34820void PrintBackendServiceImpl::OnDidRenderPrintedPage(
Alan Screenbd4f851a2022-03-29 22:53:05821 DocumentHelper& document_helper,
Alan Screen61e1a372021-12-10 03:02:34822 mojom::PrintBackendService::RenderPrintedPageCallback callback,
823 mojom::ResultCode result) {
824 std::move(callback).Run(result);
825 if (result == mojom::ResultCode::kSuccess)
826 return;
827
828 // Remove this document due to the rendering failure.
829 RemoveDocumentHelper(document_helper);
830}
Xiaohan Wangd4bc2742022-01-15 19:48:55831#endif // BUILDFLAG(IS_WIN)
Alan Screen61e1a372021-12-10 03:02:34832
Alan Screenbd4f851a2022-03-29 22:53:05833void PrintBackendServiceImpl::OnDidRenderPrintedDocument(
834 DocumentHelper& document_helper,
835 mojom::PrintBackendService::RenderPrintedDocumentCallback callback,
836 mojom::ResultCode result) {
837 std::move(callback).Run(result);
838 if (result == mojom::ResultCode::kSuccess)
839 return;
840
841 // Remove this document due to the rendering failure.
842 RemoveDocumentHelper(document_helper);
843}
844
Alan Screen6bf1d5fb2022-02-08 15:51:14845void PrintBackendServiceImpl::OnDidDocumentDone(
846 DocumentHelper& document_helper,
847 mojom::PrintBackendService::DocumentDoneCallback callback,
848 mojom::ResultCode result) {
849 std::move(callback).Run(result);
850
851 // All complete for this document.
852 RemoveDocumentHelper(document_helper);
853}
854
Alan Screen2a7dcc92022-11-17 04:52:01855void PrintBackendServiceImpl::OnDidCancel(
856 DocumentHelper& document_helper,
857 mojom::PrintBackendService::CancelCallback callback) {
858 std::move(callback).Run();
859
860 // Do nothing more with this document.
861 RemoveDocumentHelper(document_helper);
862}
863
Alan Screen61e1a372021-12-10 03:02:34864PrintBackendServiceImpl::DocumentHelper*
865PrintBackendServiceImpl::GetDocumentHelper(int document_cookie) {
866 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
867
868 // Most new calls are expected to be relevant to the most recently added
869 // document, which would be at the end of the list. So search the list
870 // backwards to hopefully reduce the time to find the document.
Victor Hugo Vianna Silva08f4b002022-01-17 13:20:04871 for (const std::unique_ptr<DocumentHelper>& helper :
872 base::Reversed(documents_)) {
Alan Screen61e1a372021-12-10 03:02:34873 if (helper->document_cookie() == document_cookie) {
Victor Hugo Vianna Silva08f4b002022-01-17 13:20:04874 return helper.get();
Alan Screen61e1a372021-12-10 03:02:34875 }
876 }
877 return nullptr;
878}
879
880void PrintBackendServiceImpl::RemoveDocumentHelper(
881 DocumentHelper& document_helper) {
882 DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
883
884 // Must search forwards because std::vector::erase() doesn't work with a
885 // reverse iterator.
Alan Screencb6421f2021-12-09 21:54:18886 int cookie = document_helper.document_cookie();
887 auto item =
Peter Kasting73f230d02022-09-17 22:29:30888 base::ranges::find(documents_, cookie, &DocumentHelper::document_cookie);
Alan Screen2166ab12021-09-01 23:09:25889 DCHECK(item != documents_.end())
Alan Screencb6421f2021-12-09 21:54:18890 << "Document " << cookie << " to be deleted not found";
Alan Screen2166ab12021-09-01 23:09:25891 documents_.erase(item);
892
893 // TODO(crbug.com/809738) This releases a connection; try to start the
894 // next job waiting to be started (if any).
895}
896
Andy Phan65e73562022-11-02 17:06:47897#if BUILDFLAG(IS_WIN)
898base::expected<XpsCapabilities, mojom::ResultCode>
899PrintBackendServiceImpl::GetXpsCapabilities(const std::string& printer_name) {
900 base::expected<std::string, mojom::ResultCode> xml =
901 print_backend_->GetXmlPrinterCapabilitiesForXpsDriver(printer_name);
902 if (!xml.has_value()) {
903 DLOG(ERROR) << "Failure getting XPS capabilities of printer "
904 << printer_name << ", error: " << xml.error();
905 return base::unexpected(xml.error());
906 }
907
908 mojom::PrinterCapabilitiesValueResultPtr value_result;
909 xml_parser_remote_->ParseXmlForPrinterCapabilities(xml.value(),
910 &value_result);
911 if (value_result->is_result_code()) {
912 DLOG(ERROR) << "Failure parsing XML of XPS capabilities of printer "
913 << printer_name << ", error: " << xml.error();
914 return base::unexpected(value_result->get_result_code());
915 }
916
917 base::expected<XpsCapabilities, mojom::ResultCode> xps_capabilities =
918 ParseValueForXpsPrinterCapabilities(value_result->get_capabilities());
919 if (!xps_capabilities.has_value()) {
920 DLOG(ERROR) << "Failure parsing value of XPS capabilities of printer "
921 << printer_name << ", error: " << xml.error();
922 return base::unexpected(xps_capabilities.error());
923 }
924 return std::move(xps_capabilities).value();
925}
926#endif // BUILDFLAG(IS_WIN)
927
Alan Screen65304d52020-10-29 16:42:22928} // namespace printing