| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "printing/print_settings.h" |
| |
| #include <tuple> |
| |
| #include "base/atomic_sequence_num.h" |
| #include "base/notreached.h" |
| #include "build/build_config.h" |
| #include "printing/buildflags/buildflags.h" |
| #include "printing/units.h" |
| |
| #if BUILDFLAG(USE_CUPS) |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) |
| #include <cups/cups.h> |
| #endif |
| |
| #include "printing/print_job_constants_cups.h" |
| #endif // BUILDFLAG(USE_CUPS) |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "printing/mojom/print.mojom.h" |
| #endif |
| |
| namespace printing { |
| |
| mojom::ColorModel ColorModeToColorModel(int color_mode) { |
| if (color_mode < static_cast<int>(mojom::ColorModel::kUnknownColorModel) || |
| color_mode > static_cast<int>(mojom::ColorModel::kMaxValue)) { |
| return mojom::ColorModel::kUnknownColorModel; |
| } |
| return static_cast<mojom::ColorModel>(color_mode); |
| } |
| |
| #if BUILDFLAG(USE_CUPS) |
| void GetColorModelForModel(mojom::ColorModel color_model, |
| std::string* color_setting_name, |
| std::string* color_value) { |
| *color_setting_name = kCUPSColorModel; |
| |
| switch (color_model) { |
| case mojom::ColorModel::kUnknownColorModel: |
| *color_value = kGrayscale; |
| break; |
| case mojom::ColorModel::kGray: |
| *color_value = kGray; |
| break; |
| case mojom::ColorModel::kColor: |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kCMYK: |
| *color_value = kCMYK; |
| break; |
| case mojom::ColorModel::kCMY: |
| *color_value = kCMY; |
| break; |
| case mojom::ColorModel::kKCMY: |
| *color_value = kKCMY; |
| break; |
| case mojom::ColorModel::kCMYPlusK: |
| *color_value = kCMY_K; |
| break; |
| case mojom::ColorModel::kBlack: |
| *color_value = kBlack; |
| break; |
| case mojom::ColorModel::kGrayscale: |
| *color_value = kGrayscale; |
| break; |
| case mojom::ColorModel::kRGB: |
| *color_value = kRGB; |
| break; |
| case mojom::ColorModel::kRGB16: |
| *color_value = kRGB16; |
| break; |
| case mojom::ColorModel::kRGBA: |
| *color_value = kRGBA; |
| break; |
| case mojom::ColorModel::kColorModeColor: |
| *color_setting_name = kCUPSColorMode; |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kColorModeMonochrome: |
| *color_setting_name = kCUPSColorMode; |
| *color_value = kMonochrome; |
| break; |
| case mojom::ColorModel::kHPColorColor: |
| *color_setting_name = kColor; |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kHPColorBlack: |
| *color_setting_name = kColor; |
| *color_value = kBlack; |
| break; |
| case mojom::ColorModel::kPrintoutModeNormal: |
| *color_setting_name = kCUPSPrintoutMode; |
| *color_value = kNormal; |
| break; |
| case mojom::ColorModel::kPrintoutModeNormalGray: |
| *color_setting_name = kCUPSPrintoutMode; |
| *color_value = kNormalGray; |
| break; |
| case mojom::ColorModel::kProcessColorModelCMYK: |
| *color_setting_name = kCUPSProcessColorModel; |
| *color_value = kCMYK; |
| break; |
| case mojom::ColorModel::kProcessColorModelGreyscale: |
| *color_setting_name = kCUPSProcessColorModel; |
| *color_value = kGreyscale; |
| break; |
| case mojom::ColorModel::kProcessColorModelRGB: |
| *color_setting_name = kCUPSProcessColorModel; |
| *color_value = kRGB; |
| break; |
| case mojom::ColorModel::kBrotherCUPSColor: |
| *color_setting_name = kCUPSBrotherMonoColor; |
| *color_value = kFullColor; |
| break; |
| case mojom::ColorModel::kBrotherCUPSMono: |
| *color_setting_name = kCUPSBrotherMonoColor; |
| *color_value = kMono; |
| break; |
| case mojom::ColorModel::kBrotherBRScript3Color: |
| *color_setting_name = kCUPSBrotherPrintQuality; |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kBrotherBRScript3Black: |
| *color_setting_name = kCUPSBrotherPrintQuality; |
| *color_value = kBlack; |
| break; |
| case mojom::ColorModel::kCanonCNColorModeColor: |
| *color_setting_name = kCUPSCanonCNColorMode; |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kCanonCNColorModeMono: |
| *color_setting_name = kCUPSCanonCNColorMode; |
| *color_value = kMono; |
| break; |
| case mojom::ColorModel::kCanonCNIJGrayScaleOne: |
| *color_setting_name = kCUPSCanonCNIJGrayScale; |
| *color_value = kOne; |
| break; |
| case mojom::ColorModel::kCanonCNIJGrayScaleZero: |
| *color_setting_name = kCUPSCanonCNIJGrayScale; |
| *color_value = kZero; |
| break; |
| case mojom::ColorModel::kEpsonInkColor: |
| *color_setting_name = kCUPSEpsonInk; |
| *color_value = kEpsonColor; |
| break; |
| case mojom::ColorModel::kEpsonInkMono: |
| *color_setting_name = kCUPSEpsonInk; |
| *color_value = kEpsonMono; |
| break; |
| case mojom::ColorModel::kKonicaMinoltaSelectColorColor: |
| *color_setting_name = kCUPSKonicaMinoltaSelectColor; |
| *color_value = kColor; |
| break; |
| case mojom::ColorModel::kKonicaMinoltaSelectColorGrayscale: |
| *color_setting_name = kCUPSKonicaMinoltaSelectColor; |
| *color_value = kGrayscale; |
| break; |
| case mojom::ColorModel::kOkiOKControlColor: |
| *color_setting_name = kCUPSOkiControl; |
| *color_value = kAuto; |
| break; |
| case mojom::ColorModel::kOkiOKControlGray: |
| *color_setting_name = kCUPSOkiControl; |
| *color_value = kGray; |
| break; |
| case mojom::ColorModel::kSharpARCModeCMColor: |
| *color_setting_name = kCUPSSharpARCMode; |
| *color_value = kSharpCMColor; |
| break; |
| case mojom::ColorModel::kSharpARCModeCMBW: |
| *color_setting_name = kCUPSSharpARCMode; |
| *color_value = kSharpCMBW; |
| break; |
| case mojom::ColorModel::kXeroxXRXColorAutomatic: |
| *color_setting_name = kCUPSXeroxXRXColor; |
| *color_value = kXeroxAutomatic; |
| break; |
| case mojom::ColorModel::kXeroxXRXColorBW: |
| *color_setting_name = kCUPSXeroxXRXColor; |
| *color_value = kXeroxBW; |
| break; |
| case mojom::ColorModel::kXeroxXROutputColorPrintAsColor: |
| *color_setting_name = kCUPSXeroxXROutputColor; |
| *color_value = kPrintAsColor; |
| break; |
| case mojom::ColorModel::kXeroxXROutputColorPrintAsGrayscale: |
| *color_setting_name = kCUPSXeroxXROutputColor; |
| *color_value = kPrintAsGrayscale; |
| break; |
| } |
| // The default case is excluded from the above switch statement to ensure that |
| // all ColorModel values are determinantly handled. |
| } |
| |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) |
| std::string GetIppColorModelForModel(mojom::ColorModel color_model) { |
| // Accept `kUnknownColorModel` for consistency with GetColorModelForModel(). |
| if (color_model == mojom::ColorModel::kUnknownColorModel) |
| return CUPS_PRINT_COLOR_MODE_MONOCHROME; |
| |
| absl::optional<bool> is_color = IsColorModelSelected(color_model); |
| if (!is_color.has_value()) { |
| NOTREACHED(); |
| return std::string(); |
| } |
| |
| return is_color.value() ? CUPS_PRINT_COLOR_MODE_COLOR |
| : CUPS_PRINT_COLOR_MODE_MONOCHROME; |
| } |
| #endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) |
| #endif // BUILDFLAG(USE_CUPS) |
| |
| absl::optional<bool> IsColorModelSelected(mojom::ColorModel color_model) { |
| switch (color_model) { |
| case mojom::ColorModel::kColor: |
| case mojom::ColorModel::kCMYK: |
| case mojom::ColorModel::kCMY: |
| case mojom::ColorModel::kKCMY: |
| case mojom::ColorModel::kCMYPlusK: |
| case mojom::ColorModel::kRGB: |
| case mojom::ColorModel::kRGB16: |
| case mojom::ColorModel::kRGBA: |
| case mojom::ColorModel::kColorModeColor: |
| case mojom::ColorModel::kHPColorColor: |
| case mojom::ColorModel::kPrintoutModeNormal: |
| case mojom::ColorModel::kProcessColorModelCMYK: |
| case mojom::ColorModel::kProcessColorModelRGB: |
| case mojom::ColorModel::kBrotherCUPSColor: |
| case mojom::ColorModel::kBrotherBRScript3Color: |
| case mojom::ColorModel::kCanonCNColorModeColor: |
| case mojom::ColorModel::kCanonCNIJGrayScaleZero: |
| case mojom::ColorModel::kEpsonInkColor: |
| case mojom::ColorModel::kKonicaMinoltaSelectColorColor: |
| case mojom::ColorModel::kOkiOKControlColor: |
| case mojom::ColorModel::kSharpARCModeCMColor: |
| case mojom::ColorModel::kXeroxXRXColorAutomatic: |
| case mojom::ColorModel::kXeroxXROutputColorPrintAsColor: |
| return true; |
| case mojom::ColorModel::kGray: |
| case mojom::ColorModel::kBlack: |
| case mojom::ColorModel::kGrayscale: |
| case mojom::ColorModel::kColorModeMonochrome: |
| case mojom::ColorModel::kHPColorBlack: |
| case mojom::ColorModel::kPrintoutModeNormalGray: |
| case mojom::ColorModel::kProcessColorModelGreyscale: |
| case mojom::ColorModel::kBrotherCUPSMono: |
| case mojom::ColorModel::kBrotherBRScript3Black: |
| case mojom::ColorModel::kCanonCNColorModeMono: |
| case mojom::ColorModel::kCanonCNIJGrayScaleOne: |
| case mojom::ColorModel::kEpsonInkMono: |
| case mojom::ColorModel::kKonicaMinoltaSelectColorGrayscale: |
| case mojom::ColorModel::kOkiOKControlGray: |
| case mojom::ColorModel::kSharpARCModeCMBW: |
| case mojom::ColorModel::kXeroxXRXColorBW: |
| case mojom::ColorModel::kXeroxXROutputColorPrintAsGrayscale: |
| return false; |
| case mojom::ColorModel::kUnknownColorModel: |
| NOTREACHED(); |
| return absl::nullopt; |
| } |
| // The default case is excluded from the above switch statement to ensure that |
| // all ColorModel values are determinantly handled. |
| } |
| |
| bool PrintSettings::RequestedMedia::operator==( |
| const PrintSettings::RequestedMedia& other) const { |
| return std::tie(size_microns, vendor_id) == |
| std::tie(other.size_microns, other.vendor_id); |
| } |
| |
| // Global SequenceNumber used for generating unique cookie values. |
| static base::AtomicSequenceNumber cookie_seq; |
| |
| PrintSettings::PrintSettings() { |
| Clear(); |
| } |
| |
| PrintSettings::PrintSettings(const PrintSettings& settings) { |
| *this = settings; |
| } |
| |
| PrintSettings& PrintSettings::operator=(const PrintSettings& settings) { |
| if (this == &settings) |
| return *this; |
| |
| ranges_ = settings.ranges_; |
| selection_only_ = settings.selection_only_; |
| margin_type_ = settings.margin_type_; |
| title_ = settings.title_; |
| url_ = settings.url_; |
| display_header_footer_ = settings.display_header_footer_; |
| should_print_backgrounds_ = settings.should_print_backgrounds_; |
| collate_ = settings.collate_; |
| color_ = settings.color_; |
| copies_ = settings.copies_; |
| duplex_mode_ = settings.duplex_mode_; |
| device_name_ = settings.device_name_; |
| requested_media_ = settings.requested_media_; |
| page_setup_device_units_ = settings.page_setup_device_units_; |
| dpi_ = settings.dpi_; |
| scale_factor_ = settings.scale_factor_; |
| rasterize_pdf_ = settings.rasterize_pdf_; |
| rasterize_pdf_dpi_ = settings.rasterize_pdf_dpi_; |
| landscape_ = settings.landscape_; |
| supports_alpha_blend_ = settings.supports_alpha_blend_; |
| #if BUILDFLAG(IS_WIN) |
| printer_language_type_ = settings.printer_language_type_; |
| #endif |
| is_modifiable_ = settings.is_modifiable_; |
| pages_per_sheet_ = settings.pages_per_sheet_; |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| for (const auto& item : settings.advanced_settings_) |
| advanced_settings_.emplace(item.first, item.second.Clone()); |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| #if BUILDFLAG(IS_CHROMEOS) |
| send_user_info_ = settings.send_user_info_; |
| username_ = settings.username_; |
| oauth_token_ = settings.oauth_token_; |
| pin_value_ = settings.pin_value_; |
| client_infos_ = settings.client_infos_; |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| return *this; |
| } |
| |
| PrintSettings::~PrintSettings() = default; |
| |
| bool PrintSettings::operator==(const PrintSettings& other) const { |
| return std::tie(ranges_, selection_only_, margin_type_, title_, url_, |
| display_header_footer_, should_print_backgrounds_, collate_, |
| color_, copies_, duplex_mode_, device_name_, requested_media_, |
| page_setup_device_units_, dpi_, scale_factor_, rasterize_pdf_, |
| rasterize_pdf_dpi_, landscape_, supports_alpha_blend_, |
| #if BUILDFLAG(IS_WIN) |
| printer_language_type_, |
| #endif |
| is_modifiable_, requested_custom_margins_in_points_, |
| pages_per_sheet_ |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| , |
| advanced_settings_ |
| #endif |
| #if BUILDFLAG(IS_CHROMEOS) |
| , |
| send_user_info_, username_, oauth_token_, pin_value_, |
| client_infos_, printer_manually_selected_, |
| printer_status_reason_ |
| #endif |
| ) == |
| std::tie(other.ranges_, other.selection_only_, other.margin_type_, |
| other.title_, other.url_, other.display_header_footer_, |
| other.should_print_backgrounds_, other.collate_, other.color_, |
| other.copies_, other.duplex_mode_, other.device_name_, |
| other.requested_media_, other.page_setup_device_units_, |
| other.dpi_, other.scale_factor_, other.rasterize_pdf_, |
| other.rasterize_pdf_dpi_, other.landscape_, |
| other.supports_alpha_blend_, |
| #if BUILDFLAG(IS_WIN) |
| other.printer_language_type_, |
| #endif |
| other.is_modifiable_, |
| other.requested_custom_margins_in_points_, |
| other.pages_per_sheet_ |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| , |
| other.advanced_settings_ |
| #endif |
| #if BUILDFLAG(IS_CHROMEOS) |
| , |
| other.send_user_info_, other.username_, other.oauth_token_, |
| other.pin_value_, other.client_infos_, |
| other.printer_manually_selected_, other.printer_status_reason_ |
| #endif |
| ); |
| } |
| |
| void PrintSettings::Clear() { |
| ranges_.clear(); |
| selection_only_ = false; |
| margin_type_ = mojom::MarginType::kDefaultMargins; |
| title_.clear(); |
| url_.clear(); |
| display_header_footer_ = false; |
| should_print_backgrounds_ = false; |
| collate_ = false; |
| color_ = mojom::ColorModel::kUnknownColorModel; |
| copies_ = 0; |
| duplex_mode_ = mojom::DuplexMode::kUnknownDuplexMode; |
| device_name_.clear(); |
| requested_media_ = RequestedMedia(); |
| page_setup_device_units_.Clear(); |
| dpi_ = gfx::Size(); |
| scale_factor_ = 1.0f; |
| rasterize_pdf_ = false; |
| rasterize_pdf_dpi_ = 0; |
| landscape_ = false; |
| supports_alpha_blend_ = true; |
| #if BUILDFLAG(IS_WIN) |
| printer_language_type_ = mojom::PrinterLanguageType::kNone; |
| #endif |
| is_modifiable_ = true; |
| pages_per_sheet_ = 1; |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| advanced_settings_.clear(); |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| #if BUILDFLAG(IS_CHROMEOS) |
| send_user_info_ = false; |
| username_.clear(); |
| oauth_token_.clear(); |
| pin_value_.clear(); |
| client_infos_.clear(); |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| } |
| |
| void PrintSettings::SetPrinterPrintableArea( |
| const gfx::Size& physical_size_device_units, |
| const gfx::Rect& printable_area_device_units, |
| bool landscape_needs_flip) { |
| int units_per_inch = device_units_per_inch(); |
| int header_footer_text_height = 0; |
| if (display_header_footer_) { |
| // Hard-code text_height = 0.5cm = ~1/5 of inch. |
| header_footer_text_height = ConvertUnit(kSettingHeaderFooterInterstice, |
| kPointsPerInch, units_per_inch); |
| } |
| |
| PageMargins margins; |
| bool small_paper_size = false; |
| switch (margin_type_) { |
| case mojom::MarginType::kDefaultMargins: { |
| // Default margins 1.0cm = ~2/5 of an inch, unless a page dimension is |
| // less than 2.54 cm = ~1 inch, in which case set the margins in that |
| // dimension to 0. |
| static constexpr double kCmInMicrons = 10000; |
| int margin_printer_units = |
| ConvertUnit(kCmInMicrons, kMicronsPerInch, units_per_inch); |
| int min_size_printer_units = units_per_inch; |
| margins.header = header_footer_text_height; |
| margins.footer = header_footer_text_height; |
| if (physical_size_device_units.height() > min_size_printer_units) { |
| margins.top = margin_printer_units; |
| margins.bottom = margin_printer_units; |
| } else { |
| margins.top = 0; |
| margins.bottom = 0; |
| small_paper_size = true; |
| } |
| if (physical_size_device_units.width() > min_size_printer_units) { |
| margins.left = margin_printer_units; |
| margins.right = margin_printer_units; |
| } else { |
| margins.left = 0; |
| margins.right = 0; |
| small_paper_size = true; |
| } |
| break; |
| } |
| case mojom::MarginType::kNoMargins: |
| case mojom::MarginType::kPrintableAreaMargins: { |
| margins.header = 0; |
| margins.footer = 0; |
| margins.top = 0; |
| margins.bottom = 0; |
| margins.left = 0; |
| margins.right = 0; |
| break; |
| } |
| case mojom::MarginType::kCustomMargins: { |
| margins.header = 0; |
| margins.footer = 0; |
| margins.top = ConvertUnit(requested_custom_margins_in_points_.top, |
| kPointsPerInch, units_per_inch); |
| margins.bottom = ConvertUnit(requested_custom_margins_in_points_.bottom, |
| kPointsPerInch, units_per_inch); |
| margins.left = ConvertUnit(requested_custom_margins_in_points_.left, |
| kPointsPerInch, units_per_inch); |
| margins.right = ConvertUnit(requested_custom_margins_in_points_.right, |
| kPointsPerInch, units_per_inch); |
| break; |
| } |
| default: { |
| NOTREACHED(); |
| } |
| } |
| |
| if ((margin_type_ == mojom::MarginType::kDefaultMargins || |
| margin_type_ == mojom::MarginType::kPrintableAreaMargins) && |
| !small_paper_size) { |
| page_setup_device_units_.SetRequestedMargins(margins); |
| } else { |
| page_setup_device_units_.ForceRequestedMargins(margins); |
| } |
| page_setup_device_units_.Init(physical_size_device_units, |
| printable_area_device_units, |
| header_footer_text_height); |
| if (landscape_ && landscape_needs_flip) |
| page_setup_device_units_.FlipOrientation(); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| void PrintSettings::UpdatePrinterPrintableArea( |
| const gfx::Rect& printable_area_um) { |
| // Scale the page size and printable area to device units. |
| // Blink doesn't support different dpi settings in X and Y axis. Because of |
| // this, printers with non-square DPIs still scale page size and printable |
| // area using device_units_per_inch() instead of their respective dimensions |
| // in device_units_per_inch_size(). |
| float scale = static_cast<float>(device_units_per_inch()) / kMicronsPerInch; |
| gfx::Rect printable_area_device_units = |
| gfx::ScaleToRoundedRect(printable_area_um, scale); |
| |
| // Protect against misbehaving drivers. We have observed some drivers return |
| // incorrect values compared to page size. E.g., HP Business Inkjet 2300 PS. |
| gfx::Rect physical_size_rect(page_setup_device_units_.physical_size()); |
| if (printable_area_device_units.IsEmpty() || |
| !physical_size_rect.Contains(printable_area_device_units)) { |
| // Invalid printable area! Default to paper size. |
| printable_area_device_units = physical_size_rect; |
| } |
| |
| page_setup_device_units_.Init(page_setup_device_units_.physical_size(), |
| printable_area_device_units, |
| page_setup_device_units_.text_height()); |
| } |
| #endif |
| |
| void PrintSettings::SetCustomMargins( |
| const PageMargins& requested_margins_in_points) { |
| requested_custom_margins_in_points_ = requested_margins_in_points; |
| margin_type_ = mojom::MarginType::kCustomMargins; |
| } |
| |
| int PrintSettings::NewCookie() { |
| // A cookie of 0 is used to mark a document as unassigned, count from 1. |
| return cookie_seq.GetNext() + 1; |
| } |
| |
| void PrintSettings::SetOrientation(bool landscape) { |
| if (landscape_ != landscape) { |
| landscape_ = landscape; |
| page_setup_device_units_.FlipOrientation(); |
| } |
| } |
| |
| } // namespace printing |