blob: 7fbf5f9dd5f743d0117f06531abbe5403cf1de82 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/printer_query_oop.h"
#include <memory>
#include <utility>
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_backend_service_manager.h"
#include "chrome/browser/printing/print_job_worker_oop.h"
#include "components/device_event_log/device_event_log.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents.h"
#include "printing/printing_features.h"
namespace printing {
namespace {
mojom::PrintTargetType DeterminePrintTargetType(
const base::Value::Dict& job_settings) {
#if BUILDFLAG(IS_MAC)
if (job_settings.contains(kSettingOpenPDFInPreview)) {
return mojom::PrintTargetType::kExternalPreview;
}
#endif
if (job_settings.FindBool(kSettingShowSystemDialog).value_or(false)) {
return mojom::PrintTargetType::kSystemDialog;
}
return mojom::PrintTargetType::kDirectToDevice;
}
} // namespace
PrinterQueryOop::PrinterQueryOop(content::GlobalRenderFrameHostId rfh_id)
: PrinterQuery(rfh_id) {}
PrinterQueryOop::~PrinterQueryOop() = default;
std::unique_ptr<PrintJobWorker> PrinterQueryOop::TransferContextToNewWorker(
PrintJob* print_job) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return std::make_unique<PrintJobWorkerOop>(
std::move(printing_context_delegate_), std::move(printing_context_),
print_job, print_target_type_);
}
void PrinterQueryOop::OnDidUseDefaultSettings(
SettingsCallback callback,
mojom::PrintSettingsResultPtr print_settings) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::ResultCode result;
if (print_settings->is_result_code()) {
result = print_settings->get_result_code();
DCHECK_NE(result, mojom::ResultCode::kSuccess);
PRINTER_LOG(ERROR) << "Error trying to use default settings via service: "
<< result;
// TODO(crbug.com/809738) Fill in support for handling of access-denied
// result code. Blocked on crbug.com/1243873 for Windows.
} else {
VLOG(1) << "Use default settings from service complete";
result = mojom::ResultCode::kSuccess;
printing_context()->ApplyPrintSettings(print_settings->get_settings());
}
InvokeSettingsCallback(std::move(callback), result);
}
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
void PrinterQueryOop::OnDidAskUserForSettings(
SettingsCallback callback,
mojom::PrintSettingsResultPtr print_settings) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::ResultCode result;
if (print_settings->is_result_code()) {
result = print_settings->get_result_code();
DCHECK_NE(result, mojom::ResultCode::kSuccess);
if (result != mojom::ResultCode::kCanceled) {
PRINTER_LOG(ERROR) << "Error getting settings from user via service: "
<< result;
}
// TODO(crbug.com/809738) Fill in support for handling of access-denied
// result code. Blocked on crbug.com/1243873 for Windows.
} else {
VLOG(1) << "Ask user for settings from service complete";
result = mojom::ResultCode::kSuccess;
printing_context()->ApplyPrintSettings(print_settings->get_settings());
}
InvokeSettingsCallback(std::move(callback), result);
}
#endif // BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
void PrinterQueryOop::UseDefaultSettings(SettingsCallback callback) {
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
SendUseDefaultSettings(std::move(callback));
#else
// `PrintingContextLinux::UseDefaultSettings()` is to be called prior to
// `AskUserForSettings()` to establish a base device context. If the system
// print dialog will be invoked from within the browser process, then that
// default setup needs to happen in browser as well.
PrinterQuery::UseDefaultSettings(std::move(callback));
#endif
}
void PrinterQueryOop::GetSettingsWithUI(uint32_t document_page_count,
bool has_selection,
bool is_scripted,
SettingsCallback callback) {
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
SendAskUserForSettings(document_page_count, has_selection, is_scripted,
std::move(callback));
#else
// Invoke the browser version of getting settings with the system UI:
// - macOS: It is impossible to invoke a system dialog UI from a service
// utility and have that dialog be application modal for a window that
// was launched by the browser process.
// - Linux: TODO(crbug.com/809738) Determine if Linux Wayland can be made
// to have a system dialog be modal against an application window in the
// browser process.
// - Other platforms don't have a system print UI or do not use OOP
// printing, so this does not matter.
PrinterQuery::GetSettingsWithUI(document_page_count, has_selection,
is_scripted, std::move(callback));
#endif
}
void PrinterQueryOop::UpdatePrintSettings(base::Value::Dict new_settings,
SettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Do not take a const reference, as `new_settings` will be modified below.
std::string device_name = *new_settings.FindString(kSettingDeviceName);
// Save the print target type from the settings, since this will be needed
// later when printing is started.
print_target_type_ = DeterminePrintTargetType(new_settings);
VLOG(1) << "Updating print settings via service for " << device_name;
PrintBackendServiceManager& service_mgr =
PrintBackendServiceManager::GetInstance();
service_mgr.UpdatePrintSettings(
device_name, std::move(new_settings),
base::BindOnce(&PrinterQueryOop::OnDidUpdatePrintSettings,
weak_factory_.GetWeakPtr(), device_name,
std::move(callback)));
}
void PrinterQueryOop::OnDidUpdatePrintSettings(
const std::string& device_name,
SettingsCallback callback,
mojom::PrintSettingsResultPtr print_settings) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
mojom::ResultCode result;
if (print_settings->is_result_code()) {
result = print_settings->get_result_code();
DCHECK_NE(result, mojom::ResultCode::kSuccess);
PRINTER_LOG(ERROR) << "Error updating print settings via service for `"
<< device_name << "`: " << result;
// TODO(crbug.com/809738) Fill in support for handling of access-denied
// result code.
} else {
VLOG(1) << "Update print settings via service complete for " << device_name;
result = mojom::ResultCode::kSuccess;
printing_context()->ApplyPrintSettings(print_settings->get_settings());
}
InvokeSettingsCallback(std::move(callback), result);
}
void PrinterQueryOop::SendUseDefaultSettings(SettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(features::kEnableOopPrintDriversJobPrint.Get());
PrintBackendServiceManager& service_mgr =
PrintBackendServiceManager::GetInstance();
service_mgr.UseDefaultSettings(
/*printer_name=*/std::string(),
base::BindOnce(&PrinterQueryOop::OnDidUseDefaultSettings,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
void PrinterQueryOop::SendAskUserForSettings(uint32_t document_page_count,
bool has_selection,
bool is_scripted,
SettingsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(features::kEnableOopPrintDriversJobPrint.Get());
if (document_page_count > kMaxPageCount) {
InvokeSettingsCallback(std::move(callback), mojom::ResultCode::kFailed);
return;
}
// Save the print target type from the settings, since this will be needed
// later when printing is started.
print_target_type_ = mojom::PrintTargetType::kDirectToDevice;
content::WebContents* web_contents = GetWebContents();
// Running a dialog causes an exit to webpage-initiated fullscreen.
// http://crbug.com/728276
if (web_contents && web_contents->IsFullscreen()) {
web_contents->ExitFullscreen(true);
}
gfx::NativeView parent_view =
web_contents ? web_contents->GetTopLevelNativeWindow() : nullptr;
PrintBackendServiceManager& service_mgr =
PrintBackendServiceManager::GetInstance();
service_mgr.AskUserForSettings(
/*printer_name=*/std::string(), parent_view, document_page_count,
has_selection, is_scripted,
base::BindOnce(&PrinterQueryOop::OnDidAskUserForSettings,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
#endif // BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
} // namespace printing