[go: nahoru, domu]

Add UpdatePrintSettings to Print Backend Service

Incorporate support in the Print Backend service to convert job
settings into print settings.  This involves a conversion and some
incorporation of the printer's driver settings.  This is effectively
incorporating the bulk of the work of
PrintJobWorker::UpdatePrintSettings() into the Print Backend service.
For Linux with CUPS, this includes extending the provided job setting's
advanced settings with the driver's basic info options.

The platform-specific implementations for
PrintingContext::UpdatePrinterSettings() can involve overriding some
of the settings based upon values from the driver, but this is not
necessarily done to all members.  To assist with testing, include in
this change an update to TestPrintingContext::UpdatePrinterSettings()
to include logic which ensures that some of user-selected settings
persist unmodified by driver defaults.  Choose to keep the provided DPI
(applicable to all platforms) and advanced settings (Linux/ChromeOS
specific) as unmodified by the simulated driver settings for testing.

This update to a printing context is not retained by the service, but
is a one-time use and then discarded.  The process model does not
guarantee that the process used for this conversion will be the same
one used when printing of the job is performed.  The necessary print
settings will be provided to StartPrinting() and used in a
PrintingContext established at that time.

Bug: 809738
Change-Id: I7c4b2fe104da128a553c850d793f409d4f07f2a4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3146419
Commit-Queue: Alan Screen <awscreen@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/main@{#920496}
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
index c2ab56e..76d6128 100644
--- a/chrome/services/printing/print_backend_service_impl.cc
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -10,16 +10,19 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/notreached.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "components/crash/core/common/crash_keys.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "printing/backend/print_backend.h"
 #include "printing/mojom/print.mojom.h"
+#include "printing/printing_context.h"
 
 #if defined(OS_MAC)
 #include "base/threading/thread_restrictions.h"
@@ -263,6 +266,71 @@
           std::move(caps_and_info)));
 }
 
+void PrintBackendServiceImpl::UpdatePrintSettings(
+    base::flat_map<std::string, base::Value> job_settings,
+    mojom::PrintBackendService::UpdatePrintSettingsCallback callback) {
+  if (!print_backend_) {
+    DLOG(ERROR)
+        << "Print backend instance has not been initialized for locale.";
+    std::move(callback).Run(
+        mojom::PrintSettingsResult::NewResultCode(mojom::ResultCode::kFailed));
+    return;
+  }
+
+  auto item = job_settings.find(kSettingDeviceName);
+  if (item == job_settings.end()) {
+    DLOG(ERROR) << "Job settings are missing specification of printer name";
+    std::move(callback).Run(
+        mojom::PrintSettingsResult::NewResultCode(mojom::ResultCode::kFailed));
+    return;
+  }
+  const base::Value& device_name_value = item->second;
+  if (!device_name_value.is_string()) {
+    DLOG(ERROR) << "Invalid type for job settings device name entry, is type "
+                << device_name_value.type();
+    std::move(callback).Run(
+        mojom::PrintSettingsResult::NewResultCode(mojom::ResultCode::kFailed));
+    return;
+  }
+  const std::string& printer_name = device_name_value.GetString();
+
+  crash_keys_ = std::make_unique<crash_keys::ScopedPrinterInfo>(
+      print_backend_->GetPrinterDriverInfo(printer_name));
+
+#if defined(OS_LINUX) && defined(USE_CUPS)
+  // Try to fill in advanced settings based upon basic info options.
+  PrinterBasicInfo basic_info;
+  if (print_backend_->GetPrinterBasicInfo(printer_name, &basic_info) ==
+      mojom::ResultCode::kSuccess) {
+    base::Value advanced_settings(base::Value::Type::DICTIONARY);
+    for (const auto& pair : basic_info.options)
+      advanced_settings.SetStringKey(pair.first, pair.second);
+
+    job_settings[kSettingAdvancedSettings] = std::move(advanced_settings);
+  }
+#endif  // defined(OS_LINUX) && defined(USE_CUPS)
+
+  // Use a one-time `PrintingContext` to do the update to print settings.
+  // Intentionally do not cache this context here since the process model does
+  // not guarantee that we will return to this same process when
+  // `StartPrinting()` might be called.
+  std::unique_ptr<PrintingContext> context =
+      PrintingContext::Create(&context_delegate_);
+  PrintingContext::Result context_result =
+      context->UpdatePrintSettings(base::Value(std::move(job_settings)));
+
+  if (context_result != PrintingContext::OK) {
+    std::move(callback).Run(mojom::PrintSettingsResult::NewResultCode(
+        context_result == PrintingContext::CANCEL
+            ? mojom::ResultCode::kCanceled
+            : mojom::ResultCode::kFailed));
+    return;
+  }
+
+  std::move(callback).Run(mojom::PrintSettingsResult::NewSettings(
+      *context->TakeAndResetSettings()));
+}
+
 void PrintBackendServiceImpl::StartPrinting(
     int document_cookie,
     const std::u16string& document_name,