#include "printing/mojom/printing_context_mojom_traits.h"
#include <string>
#include "build/build_config.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "printing/mojom/print.mojom.h"
#include "printing/page_setup.h"
#include "printing/print_settings.h"
#include "ui/gfx/geometry/mojom/geometry.mojom-shared.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "ui/gfx/geometry/size.h"
#if BUILDFLAG(ENABLE_OOP_PRINTING_NO_OOP_BASIC_PRINT_DIALOG)
#include "base/numerics/safe_conversions.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "mojo/public/mojom/base/values.mojom.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "printing/printing_features.h"
#endif
namespace mojo {
namespace {
bool IsCustomOrPrecomputedMargins(printing::mojom::MarginType margin_type) {
if (margin_type == printing::mojom::MarginType::kCustomMargins) {
return true;
}
#if BUILDFLAG(IS_CHROMEOS)
if (margin_type ==
printing::mojom::MarginType::kPrecomputedMarginsForBackend &&
base::FeatureList::IsEnabled(
printing::features::kApiPrintingMarginsAndScale)) {
return true;
}
#endif
return false;
}
void SetMarginsToPrintSettings(printing::mojom::MarginType margin_type,
const printing::PageMargins& margins,
printing::PrintSettings* settings) {
#if BUILDFLAG(IS_CHROMEOS)
if (margin_type ==
printing::mojom::MarginType::kPrecomputedMarginsForBackend &&
base::FeatureList::IsEnabled(
printing::features::kApiPrintingMarginsAndScale)) {
settings->SetCustomMarginsForBackend(margins);
return;
}
#endif
CHECK_EQ(margin_type, printing::mojom::MarginType::kCustomMargins);
settings->SetCustomMargins(margins);
}
}
bool StructTraits<printing::mojom::PageMarginsDataView, printing::PageMargins>::
Read(printing::mojom::PageMarginsDataView data,
printing::PageMargins* out) {
out->header = data.header();
out->footer = data.footer();
out->left = data.left();
out->right = data.right();
out->top = data.top();
out->bottom = data.bottom();
return true;
}
bool StructTraits<printing::mojom::PageSetupDataView, printing::PageSetup>::
Read(printing::mojom::PageSetupDataView data, printing::PageSetup* out) {
gfx::Size physical_size;
gfx::Rect printable_area;
gfx::Rect overlay_area;
gfx::Rect content_area;
printing::PageMargins effective_margins;
printing::PageMargins requested_margins;
if (!data.ReadPhysicalSize(&physical_size) ||
!data.ReadPrintableArea(&printable_area) ||
!data.ReadOverlayArea(&overlay_area) ||
!data.ReadContentArea(&content_area) ||
!data.ReadEffectiveMargins(&effective_margins) ||
!data.ReadRequestedMargins(&requested_margins)) {
return false;
}
printing::PageSetup page_setup(physical_size, printable_area,
requested_margins, data.forced_margins(),
data.text_height());
if (page_setup.overlay_area() != overlay_area)
return false;
if (page_setup.content_area() != content_area)
return false;
if (page_setup.effective_margins() != effective_margins) {
return false;
}
*out = page_setup;
return true;
}
bool StructTraits<printing::mojom::RequestedMediaDataView,
printing::PrintSettings::RequestedMedia>::
Read(printing::mojom::RequestedMediaDataView data,
printing::PrintSettings::RequestedMedia* out) {
return data.ReadSizeMicrons(&out->size_microns) &&
data.ReadVendorId(&out->vendor_id);
}
bool StructTraits<
printing::mojom::PrintSettingsDataView,
printing::PrintSettings>::Read(printing::mojom::PrintSettingsDataView data,
printing::PrintSettings* out) {
printing::PageRanges ranges;
if (!data.ReadRanges(&ranges))
return false;
out->set_ranges(ranges);
out->set_selection_only(data.selection_only());
bool must_set_margin_type = true;
#if BUILDFLAG(IS_CHROMEOS)
must_set_margin_type =
!base::FeatureList::IsEnabled(
printing::features::kApiPrintingMarginsAndScale) ||
data.margin_type() !=
printing::mojom::MarginType::kPrecomputedMarginsForBackend;
#endif
if (must_set_margin_type) {
out->set_margin_type(data.margin_type());
}
std::u16string title;
if (!data.ReadTitle(&title))
return false;
out->set_title(title);
std::u16string url;
if (!data.ReadUrl(&url))
return false;
out->set_url(url);
out->set_display_header_footer(data.display_header_footer());
out->set_should_print_backgrounds(data.should_print_backgrounds());
out->set_collate(data.collate());
out->set_color(data.color());
out->set_copies(data.copies());
out->set_duplex_mode(data.duplex_mode());
std::u16string device_name;
if (!data.ReadDeviceName(&device_name))
return false;
out->set_device_name(device_name);
printing::PrintSettings::RequestedMedia requested_media;
if (!data.ReadRequestedMedia(&requested_media))
return false;
out->set_requested_media(requested_media);
out->SetOrientation(data.landscape());
printing::PageSetup page_setup;
if (!data.ReadPageSetupDeviceUnits(&page_setup))
return false;
out->set_page_setup_device_units(page_setup);
std::string media_type;
if (!data.ReadMediaType(&media_type)) {
return false;
}
out->set_media_type(media_type);
out->set_borderless(data.borderless());
gfx::Size dpi;
if (!data.ReadDpi(&dpi))
return false;
out->set_dpi_xy(dpi.width(), dpi.height());
out->set_scale_factor(data.scale_factor());
out->set_rasterize_pdf(data.rasterize_pdf());
#if BUILDFLAG(IS_WIN)
out->set_printer_language_type(data.printer_language_type());
#endif
out->set_is_modifiable(data.is_modifiable());
const bool is_custom_or_precomputed_margins =
IsCustomOrPrecomputedMargins(data.margin_type());
if (is_custom_or_precomputed_margins) {
printing::PageMargins requested_margins;
if (!data.ReadRequestedCustomMarginsInMicrons(&requested_margins)) {
return false;
}
SetMarginsToPrintSettings(data.margin_type(), requested_margins, out);
}
out->set_pages_per_sheet(data.pages_per_sheet());
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
DCHECK(out->advanced_settings().empty());
if (!data.ReadAdvancedSettings(&out->advanced_settings()))
return false;
#endif
#if BUILDFLAG(IS_CHROMEOS)
out->set_send_user_info(data.send_user_info());
std::string username;
if (!data.ReadUsername(&username))
return false;
out->set_username(username);
std::string pin_value;
if (!data.ReadPinValue(&pin_value))
return false;
out->set_pin_value(pin_value);
#endif
#if BUILDFLAG(ENABLE_OOP_PRINTING_NO_OOP_BASIC_PRINT_DIALOG)
base::Value::Dict system_print_dialog_data;
if (!data.ReadSystemPrintDialogData(&system_print_dialog_data)) {
return false;
}
if (!system_print_dialog_data.empty()) {
#if BUILDFLAG(IS_MAC)
std::optional<int> destination_type = system_print_dialog_data.FindInt(
printing::kMacSystemPrintDialogDataDestinationType);
if (!destination_type.has_value()) {
return false;
}
const base::Value::BlobStorage* page_format =
system_print_dialog_data.FindBlob(
printing::kMacSystemPrintDialogDataPageFormat);
if (!page_format || page_format->empty()) {
return false;
}
const base::Value::BlobStorage* print_settings =
system_print_dialog_data.FindBlob(
printing::kMacSystemPrintDialogDataPrintSettings);
if (!print_settings || print_settings->empty()) {
return false;
}
size_t dictionary_entries = 3;
if (!base::IsValueInRangeForNumericType<uint16_t>(*destination_type)) {
return false;
}
const base::Value* destination_format = system_print_dialog_data.Find(
printing::kMacSystemPrintDialogDataDestinationFormat);
if (destination_format) {
if (!destination_format->is_string()) {
return false;
}
++dictionary_entries;
}
const base::Value* destination_location = system_print_dialog_data.Find(
printing::kMacSystemPrintDialogDataDestinationLocation);
if (destination_location) {
if (!destination_location->is_string()) {
return false;
}
++dictionary_entries;
}
if (system_print_dialog_data.size() != dictionary_entries) {
return false;
}
#elif BUILDFLAG(IS_LINUX)
const base::Value* value = system_print_dialog_data.Find(
printing::kLinuxSystemPrintDialogDataPrinter);
if (!value || !value->is_string()) {
return false;
}
value = system_print_dialog_data.Find(
printing::kLinuxSystemPrintDialogDataPrintSettings);
if (!value || !value->is_string()) {
return false;
}
value = system_print_dialog_data.Find(
printing::kLinuxSystemPrintDialogDataPageSetup);
if (!value || !value->is_string()) {
return false;
}
if (system_print_dialog_data.size() != 3) {
return false;
}
#else
#error "System print dialog support not implemented for this platform."
#endif
}
out->set_system_print_dialog_data(std::move(system_print_dialog_data));
#endif
return true;
}
}