[go: nahoru, domu]

blob: 00bebb81d33b59c7f277165f358d593c09e5a3ba [file] [log] [blame]
// Copyright 2018 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/common/printing/printer_capabilities.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/types/optional_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "build/chromeos_buildflags.h"
#include "chrome/common/printing/printing_buildflags.h"
#include "components/crash/core/common/crash_keys.h"
#include "components/device_event_log/device_event_log.h"
#include "components/printing/common/cloud_print_cdd_conversion.h"
#include "components/strings/grit/components_strings.h"
#include "printing/backend/print_backend.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_job_constants.h"
#include "ui/base/l10n/l10n_util.h"
#if BUILDFLAG(IS_WIN)
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/common/printing/ipp_l10n.h"
#endif // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
#include "chrome/common/printing/print_media_l10n.h"
#if BUILDFLAG(IS_MAC)
#include "printing/printing_features.h"
#endif // BUILDFLAG(IS_MAC)
#endif // BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
namespace printing {
const char kPrinter[] = "printer";
namespace {
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
// Iterate on the `Papers` of a given printer `info` and set the
// `display_name` members, localizing where possible, as well as the `vendor_id`
// members. The `Papers` will be sorted in place when this function returns.
void PopulateAndSortAllPaperNames(PrinterSemanticCapsAndDefaults& info) {
MediaSizeInfo default_paper =
LocalizePaperDisplayName(info.default_paper.size_um());
info.default_paper.set_display_name(
base::UTF16ToUTF8(default_paper.display_name));
info.default_paper.set_vendor_id(default_paper.vendor_id);
// Pair the paper entries with their sort info so they can be sorted.
std::vector<PaperWithSizeInfo> size_list;
for (PrinterSemanticCapsAndDefaults::Paper& paper : info.papers) {
// Copy `paper.size_um` to avoid potentially using `paper` after calling
// std::move(paper).
gfx::Size size_um = paper.size_um();
size_list.emplace_back(LocalizePaperDisplayName(size_um), std::move(paper));
}
// Sort and recreate the list with localizations inserted.
SortPaperDisplayNames(size_list);
info.papers.clear();
for (auto& pair : size_list) {
auto& paper = info.papers.emplace_back(std::move(pair.paper));
paper.set_display_name(base::UTF16ToUTF8(pair.size_info.display_name));
paper.set_vendor_id(pair.size_info.vendor_id);
}
}
#endif // BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
#if BUILDFLAG(IS_CHROMEOS)
void PopulateMediaTypeLocalization(
PrinterSemanticCapsAndDefaults::MediaTypes& media_types) {
auto& l10n_map = CapabilityLocalizationMap();
for (auto& value : media_types) {
auto value_it =
l10n_map.find(base::StrCat({"media-type/", value.vendor_id}));
if (value_it != l10n_map.end()) {
value.display_name = l10n_util::GetStringUTF8(value_it->second);
}
}
}
void PopulateAdvancedCapsLocalization(
std::vector<AdvancedCapability>* advanced_capabilities) {
auto& l10n_map = CapabilityLocalizationMap();
for (AdvancedCapability& capability : *advanced_capabilities) {
auto capability_it = l10n_map.find(capability.name);
if (capability_it != l10n_map.end())
capability.display_name = l10n_util::GetStringUTF8(capability_it->second);
for (AdvancedCapabilityValue& value : capability.values) {
auto value_it =
l10n_map.find(base::StrCat({capability.name, "/", value.name}));
if (value_it != l10n_map.end())
value.display_name = l10n_util::GetStringUTF8(value_it->second);
}
}
}
#endif // BUILDFLAG(IS_CHROMEOS)
// Returns a dictionary representing printer capabilities as CDD, or
// a Value of type NONE if no capabilities are provided.
base::Value AssemblePrinterCapabilities(const std::string& device_name,
bool has_secure_protocol,
PrinterSemanticCapsAndDefaults* caps) {
DCHECK(!device_name.empty());
if (!caps)
return base::Value();
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
bool populate_paper_names = true;
#if BUILDFLAG(IS_MAC)
// Paper display name localization and vendor ID assignment is intended for
// use with the CUPS IPP backend. If the CUPS IPP backend is not enabled,
// localization will not properly occur.
populate_paper_names =
base::FeatureList::IsEnabled(features::kCupsIppPrintingBackend);
#endif
if (populate_paper_names) {
PopulateAndSortAllPaperNames(*caps);
}
#endif // BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
#if BUILDFLAG(IS_CHROMEOS)
PopulateMediaTypeLocalization(caps->media_types);
if (!has_secure_protocol)
caps->pin_supported = false;
PopulateAdvancedCapsLocalization(&caps->advanced_capabilities);
#endif // BUILDFLAG(IS_CHROMEOS)
return cloud_print::PrinterSemanticCapsAndDefaultsToCdd(*caps);
}
} // namespace
#if BUILDFLAG(IS_WIN)
std::string GetUserFriendlyName(const std::string& printer_name) {
// `printer_name` may be a UNC path like \\printserver\printername.
if (!base::StartsWith(printer_name, "\\\\",
base::CompareCase::INSENSITIVE_ASCII)) {
return printer_name;
}
// If it is a UNC path, split the "printserver\printername" portion and
// generate a friendly name, like Windows does.
std::string printer_name_trimmed = printer_name.substr(2);
std::vector<std::string> tokens = base::SplitString(
printer_name_trimmed, "\\", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
if (tokens.size() != 2 || tokens[0].empty() || tokens[1].empty())
return printer_name;
return l10n_util::GetStringFUTF8(
IDS_PRINT_PREVIEW_FRIENDLY_WIN_NETWORK_PRINTER_NAME,
base::UTF8ToUTF16(tokens[1]), base::UTF8ToUTF16(tokens[0]));
}
#endif
base::Value::Dict AssemblePrinterSettings(
const std::string& device_name,
const PrinterBasicInfo& basic_info,
bool has_secure_protocol,
PrinterSemanticCapsAndDefaults* caps) {
base::Value::Dict printer_info;
printer_info.Set(kSettingDeviceName, device_name);
printer_info.Set(kSettingPrinterName, basic_info.display_name);
printer_info.Set(kSettingPrinterDescription, basic_info.printer_description);
base::Value::Dict options;
#if BUILDFLAG(IS_CHROMEOS)
printer_info.Set(
kCUPSEnterprisePrinter,
base::Contains(basic_info.options, kCUPSEnterprisePrinter) &&
basic_info.options.at(kCUPSEnterprisePrinter) == kValueTrue);
#endif // BUILDFLAG(IS_CHROMEOS)
printer_info.Set(kSettingPrinterOptions, std::move(options));
base::Value::Dict printer_info_capabilities;
printer_info_capabilities.Set(kPrinter, std::move(printer_info));
base::Value capabilities =
AssemblePrinterCapabilities(device_name, has_secure_protocol, caps);
if (capabilities.is_dict()) {
printer_info_capabilities.Set(kSettingCapabilities,
std::move(capabilities));
}
return printer_info_capabilities;
}
base::Value::Dict GetSettingsOnBlockingTaskRunner(
const std::string& device_name,
const PrinterBasicInfo& basic_info,
PrinterSemanticCapsAndDefaults::Papers user_defined_papers,
scoped_refptr<PrintBackend> print_backend) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
PRINTER_LOG(EVENT) << "Get printer capabilities start for " << device_name;
const std::vector<std::string> driver_info =
print_backend->GetPrinterDriverInfo(device_name);
PRINTER_LOG(EVENT) << "Driver info: " << base::JoinString(driver_info, ";");
crash_keys::ScopedPrinterInfo crash_key(device_name, driver_info);
auto caps = std::make_optional<PrinterSemanticCapsAndDefaults>();
mojom::ResultCode result =
print_backend->GetPrinterSemanticCapsAndDefaults(device_name, &*caps);
if (result == mojom::ResultCode::kSuccess) {
PRINTER_LOG(EVENT) << "Got printer capabilities for " << device_name;
caps->user_defined_papers = std::move(user_defined_papers);
} else {
// Failed to get capabilities, but proceed to assemble the settings to
// return what information we do have.
PRINTER_LOG(ERROR) << "Failed to get capabilities for " << device_name
<< ", result: " << result;
caps = std::nullopt;
}
return AssemblePrinterSettings(device_name, basic_info,
/*has_secure_protocol=*/false,
base::OptionalToPtr(caps));
}
} // namespace printing