#include "printing/backend/mojom/print_backend_mojom_traits.h"
#include <set>
#include <utility>
#include "base/containers/contains.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/mojom/geometry.mojom-shared.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
namespace {
struct LessPaper {
bool operator()(
const ::printing::PrinterSemanticCapsAndDefaults::Paper& lhs,
const ::printing::PrinterSemanticCapsAndDefaults::Paper& rhs) const {
return std::tie(lhs.display_name(), lhs.vendor_id()) <
std::tie(rhs.display_name(), rhs.vendor_id());
}
};
#if BUILDFLAG(IS_CHROMEOS)
struct LessAdvancedCapability {
bool operator()(const ::printing::AdvancedCapability& lhs,
const ::printing::AdvancedCapability& rhs) const {
return std::tie(lhs.name, lhs.display_name) <
std::tie(rhs.name, rhs.display_name);
}
};
#endif
}
namespace mojo {
#if BUILDFLAG(IS_CHROMEOS)
bool StructTraits<
printing::mojom::PaperMarginsDataView,
printing::PaperMargins>::Read(printing::mojom::PaperMarginsDataView data,
printing::PaperMargins* out) {
if (data.top_margin_um() < 0 || data.right_margin_um() < 0 ||
data.bottom_margin_um() < 0 || data.left_margin_um() < 0) {
return false;
}
out->top_margin_um = data.top_margin_um();
out->right_margin_um = data.right_margin_um();
out->bottom_margin_um = data.bottom_margin_um();
out->left_margin_um = data.left_margin_um();
return true;
}
#endif
namespace {
template <class Key, class Less = std::less<Key>>
bool HasDuplicateItems(const std::vector<Key>& items, Less = {}) {
std::set<Key, Less> items_encountered;
for (const Key& item : items) {
bool inserted = items_encountered.insert(item).second;
if (!inserted) {
return true;
}
}
return false;
}
}
bool StructTraits<printing::mojom::PrinterBasicInfoDataView,
printing::PrinterBasicInfo>::
Read(printing::mojom::PrinterBasicInfoDataView data,
printing::PrinterBasicInfo* out) {
if (!data.ReadPrinterName(&out->printer_name) ||
!data.ReadDisplayName(&out->display_name) ||
!data.ReadPrinterDescription(&out->printer_description) ||
!data.ReadOptions(&out->options)) {
return false;
}
if (out->printer_name.empty()) {
DLOG(ERROR) << "The printer name must not be empty.";
return false;
}
if (out->display_name.empty()) {
DLOG(ERROR) << "The printer's display name must not be empty.";
return false;
}
return true;
}
bool StructTraits<printing::mojom::PaperDataView,
printing::PrinterSemanticCapsAndDefaults::Paper>::
Read(printing::mojom::PaperDataView data,
printing::PrinterSemanticCapsAndDefaults::Paper* out) {
std::string display_name;
if (!data.ReadDisplayName(&display_name)) {
return false;
}
std::string vendor_id;
if (!data.ReadVendorId(&vendor_id)) {
return false;
}
gfx::Size size_um;
if (!data.ReadSizeUm(&size_um)) {
return false;
}
gfx::Rect printable_area_um;
if (!data.ReadPrintableAreaUm(&printable_area_um)) {
return false;
}
#if BUILDFLAG(IS_CHROMEOS)
std::optional<printing::PaperMargins> supported_margins_um;
if (!data.ReadSupportedMarginsUm(&supported_margins_um)) {
return false;
}
#endif
int max_height_um = data.max_height_um();
bool has_borderless_variant = data.has_borderless_variant();
if (display_name.empty() && vendor_id.empty() && size_um.IsEmpty() &&
printable_area_um.IsEmpty() && max_height_um == 0) {
*out = printing::PrinterSemanticCapsAndDefaults::Paper();
return true;
}
if (max_height_um > 0 && max_height_um < size_um.height()) {
return false;
}
if (printable_area_um.IsEmpty()) {
return false;
}
if (!gfx::Rect(size_um).Contains(printable_area_um)) {
return false;
}
#if BUILDFLAG(IS_CHROMEOS)
*out = printing::PrinterSemanticCapsAndDefaults::Paper(
display_name, vendor_id, size_um, printable_area_um, max_height_um,
has_borderless_variant, supported_margins_um);
#else
*out = printing::PrinterSemanticCapsAndDefaults::Paper(
display_name, vendor_id, size_um, printable_area_um, max_height_um,
has_borderless_variant);
#endif
return true;
}
bool StructTraits<printing::mojom::MediaTypeDataView,
printing::PrinterSemanticCapsAndDefaults::MediaType>::
Read(printing::mojom::MediaTypeDataView data,
printing::PrinterSemanticCapsAndDefaults::MediaType* out) {
return data.ReadDisplayName(&out->display_name) &&
data.ReadVendorId(&out->vendor_id);
}
#if BUILDFLAG(IS_CHROMEOS)
printing::mojom::AdvancedCapabilityType
EnumTraits<printing::mojom::AdvancedCapabilityType,
::printing::AdvancedCapability::Type>::
ToMojom(::printing::AdvancedCapability::Type input) {
switch (input) {
case ::printing::AdvancedCapability::Type::kBoolean:
return printing::mojom::AdvancedCapabilityType::kBoolean;
case ::printing::AdvancedCapability::Type::kFloat:
return printing::mojom::AdvancedCapabilityType::kFloat;
case ::printing::AdvancedCapability::Type::kInteger:
return printing::mojom::AdvancedCapabilityType::kInteger;
case ::printing::AdvancedCapability::Type::kString:
return printing::mojom::AdvancedCapabilityType::kString;
}
NOTREACHED();
}
bool EnumTraits<printing::mojom::AdvancedCapabilityType,
::printing::AdvancedCapability::Type>::
FromMojom(printing::mojom::AdvancedCapabilityType input,
::printing::AdvancedCapability::Type* output) {
switch (input) {
case printing::mojom::AdvancedCapabilityType::kBoolean:
*output = ::printing::AdvancedCapability::Type::kBoolean;
return true;
case printing::mojom::AdvancedCapabilityType::kFloat:
*output = ::printing::AdvancedCapability::Type::kFloat;
return true;
case printing::mojom::AdvancedCapabilityType::kInteger:
*output = ::printing::AdvancedCapability::Type::kInteger;
return true;
case printing::mojom::AdvancedCapabilityType::kString:
*output = ::printing::AdvancedCapability::Type::kString;
return true;
}
NOTREACHED();
}
bool StructTraits<printing::mojom::AdvancedCapabilityValueDataView,
::printing::AdvancedCapabilityValue>::
Read(printing::mojom::AdvancedCapabilityValueDataView data,
::printing::AdvancedCapabilityValue* out) {
return data.ReadName(&out->name) && data.ReadDisplayName(&out->display_name);
}
bool StructTraits<printing::mojom::AdvancedCapabilityDataView,
::printing::AdvancedCapability>::
Read(printing::mojom::AdvancedCapabilityDataView data,
::printing::AdvancedCapability* out) {
return data.ReadName(&out->name) &&
data.ReadDisplayName(&out->display_name) &&
data.ReadType(&out->type) &&
data.ReadDefaultValue(&out->default_value) &&
data.ReadValues(&out->values);
}
#endif
#if BUILDFLAG(IS_WIN)
bool StructTraits<printing::mojom::PageOutputQualityAttributeDataView,
printing::PageOutputQualityAttribute>::
Read(printing::mojom::PageOutputQualityAttributeDataView data,
printing::PageOutputQualityAttribute* out) {
return data.ReadDisplayName(&out->display_name) && data.ReadName(&out->name);
}
bool StructTraits<printing::mojom::PageOutputQualityDataView,
printing::PageOutputQuality>::
Read(printing::mojom::PageOutputQualityDataView data,
printing::PageOutputQuality* out) {
return data.ReadQualities(&out->qualities) &&
data.ReadDefaultQuality(&out->default_quality);
}
#endif
bool StructTraits<printing::mojom::PrinterSemanticCapsAndDefaultsDataView,
printing::PrinterSemanticCapsAndDefaults>::
Read(printing::mojom::PrinterSemanticCapsAndDefaultsDataView data,
printing::PrinterSemanticCapsAndDefaults* out) {
std::optional<printing::PrinterSemanticCapsAndDefaults::MediaTypes>
media_types;
std::optional<printing::PrinterSemanticCapsAndDefaults::MediaType>
default_media_type;
out->collate_capable = data.collate_capable();
out->collate_default = data.collate_default();
out->copies_max = data.copies_max();
if (!data.ReadDuplexModes(&out->duplex_modes) ||
!data.ReadDuplexDefault(&out->duplex_default)) {
return false;
}
out->color_changeable = data.color_changeable();
out->color_default = data.color_default();
if (!data.ReadColorModel(&out->color_model) ||
!data.ReadBwModel(&out->bw_model) || !data.ReadPapers(&out->papers) ||
!data.ReadUserDefinedPapers(&out->user_defined_papers) ||
!data.ReadDefaultPaper(&out->default_paper) ||
!data.ReadDpis(&out->dpis) || !data.ReadDefaultDpi(&out->default_dpi)) {
return false;
}
#if BUILDFLAG(IS_CHROMEOS)
out->pin_supported = data.pin_supported();
if (!data.ReadAdvancedCapabilities(&out->advanced_capabilities) ||
!data.ReadPrintScalingTypes(&out->print_scaling_types) ||
!data.ReadPrintScalingTypeDefault(&out->print_scaling_type_default)) {
return false;
}
#endif
if (out->copies_max < 1) {
DLOG(ERROR) << "Must have copies_max greater than zero.";
return false;
}
if (HasDuplicateItems(out->duplex_modes)) {
DLOG(ERROR) << "Duplicate duplex_modes detected.";
return false;
}
if (HasDuplicateItems(out->user_defined_papers, LessPaper{})) {
DLOG(ERROR) << "Duplicate user_defined_papers detected.";
return false;
}
#if BUILDFLAG(IS_CHROMEOS)
if (HasDuplicateItems(out->advanced_capabilities, LessAdvancedCapability{})) {
DLOG(ERROR) << "Duplicate advanced_capabilities detected.";
return false;
}
if (HasDuplicateItems(out->print_scaling_types)) {
DLOG(ERROR) << "Duplicate print_scaling_types detected.";
return false;
}
#endif
#if BUILDFLAG(IS_WIN)
if (!data.ReadPageOutputQuality(&out->page_output_quality)) {
return false;
}
if (out->page_output_quality) {
printing::PageOutputQualityAttributes qualities =
out->page_output_quality->qualities;
std::optional<std::string> default_quality =
out->page_output_quality->default_quality;
if (default_quality) {
if (!base::Contains(qualities, *default_quality,
&printing::PageOutputQualityAttribute::name)) {
DLOG(ERROR) << "Non-null default quality, but page output qualities "
"does not contain default quality";
return false;
}
}
if (HasDuplicateItems(qualities)) {
DLOG(ERROR) << "Duplicate page output qualities detected.";
return false;
}
}
#endif
if (!data.ReadMediaTypes(&media_types) ||
!data.ReadDefaultMediaType(&default_media_type)) {
return false;
}
if (media_types.has_value()) {
out->media_types = media_types.value();
}
if (default_media_type.has_value()) {
out->default_media_type = default_media_type.value();
}
return true;
}
}