1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "printing/print_settings.h"
9 #include "base/atomic_sequence_num.h"
10 #include "base/notreached.h"
11 #include "build/build_config.h"
12 #include "printing/buildflags/buildflags.h"
13 #include "printing/units.h"
15 #if BUILDFLAG(USE_CUPS)
16 #include "printing/print_job_constants_cups.h"
17 #endif // BUILDFLAG(USE_CUPS)
19 #if BUILDFLAG(USE_CUPS_IPP)
20 #include <cups/cups.h>
21 #endif // BUILDFLAG(USE_CUPS_IPP)
24 #include "printing/mojom/print.mojom.h"
25 #endif // BUILDFLAG(IS_WIN)
29 mojom::ColorModel ColorModeToColorModel(int color_mode) {
30 if (color_mode < static_cast<int>(mojom::ColorModel::kUnknownColorModel) ||
31 color_mode > static_cast<int>(mojom::ColorModel::kMaxValue)) {
32 return mojom::ColorModel::kUnknownColorModel;
34 return static_cast<mojom::ColorModel>(color_mode);
37 #if BUILDFLAG(USE_CUPS)
38 void GetColorModelForModel(mojom::ColorModel color_model,
39 std::string* color_setting_name,
40 std::string* color_value) {
41 *color_setting_name = kCUPSColorModel;
43 switch (color_model) {
44 case mojom::ColorModel::kUnknownColorModel:
45 *color_value = kGrayscale;
47 case mojom::ColorModel::kGray:
50 case mojom::ColorModel::kColor:
51 *color_value = kColor;
53 case mojom::ColorModel::kCMYK:
56 case mojom::ColorModel::kCMY:
59 case mojom::ColorModel::kKCMY:
62 case mojom::ColorModel::kCMYPlusK:
63 *color_value = kCMY_K;
65 case mojom::ColorModel::kBlack:
66 *color_value = kBlack;
68 case mojom::ColorModel::kGrayscale:
69 *color_value = kGrayscale;
71 case mojom::ColorModel::kRGB:
74 case mojom::ColorModel::kRGB16:
75 *color_value = kRGB16;
77 case mojom::ColorModel::kRGBA:
80 case mojom::ColorModel::kColorModeColor:
81 *color_setting_name = kCUPSColorMode;
82 *color_value = kColor;
84 case mojom::ColorModel::kColorModeMonochrome:
85 *color_setting_name = kCUPSColorMode;
86 *color_value = kMonochrome;
88 case mojom::ColorModel::kHPColorColor:
89 *color_setting_name = kColor;
90 *color_value = kColor;
92 case mojom::ColorModel::kHPColorBlack:
93 *color_setting_name = kColor;
94 *color_value = kBlack;
96 case mojom::ColorModel::kHpPjlColorAsGrayNo:
97 *color_setting_name = kCUPSHpPjlColorAsGray;
98 *color_value = kHpPjlColorAsGrayNo;
100 case mojom::ColorModel::kHpPjlColorAsGrayYes:
101 *color_setting_name = kCUPSHpPjlColorAsGray;
102 *color_value = kHpPjlColorAsGrayYes;
104 case mojom::ColorModel::kPrintoutModeNormal:
105 *color_setting_name = kCUPSPrintoutMode;
106 *color_value = kNormal;
108 case mojom::ColorModel::kPrintoutModeNormalGray:
109 *color_setting_name = kCUPSPrintoutMode;
110 *color_value = kNormalGray;
112 case mojom::ColorModel::kProcessColorModelCMYK:
113 *color_setting_name = kCUPSProcessColorModel;
114 *color_value = kCMYK;
116 case mojom::ColorModel::kProcessColorModelGreyscale:
117 *color_setting_name = kCUPSProcessColorModel;
118 *color_value = kGreyscale;
120 case mojom::ColorModel::kProcessColorModelRGB:
121 *color_setting_name = kCUPSProcessColorModel;
124 case mojom::ColorModel::kBrotherCUPSColor:
125 *color_setting_name = kCUPSBrotherMonoColor;
126 *color_value = kFullColor;
128 case mojom::ColorModel::kBrotherCUPSMono:
129 *color_setting_name = kCUPSBrotherMonoColor;
130 *color_value = kMono;
132 case mojom::ColorModel::kBrotherBRScript3Color:
133 *color_setting_name = kCUPSBrotherPrintQuality;
134 *color_value = kColor;
136 case mojom::ColorModel::kBrotherBRScript3Black:
137 *color_setting_name = kCUPSBrotherPrintQuality;
138 *color_value = kBlack;
140 case mojom::ColorModel::kCanonCNColorModeColor:
141 *color_setting_name = kCUPSCanonCNColorMode;
142 *color_value = kColor;
144 case mojom::ColorModel::kCanonCNColorModeMono:
145 *color_setting_name = kCUPSCanonCNColorMode;
146 *color_value = kMono;
148 case mojom::ColorModel::kCanonCNIJGrayScaleOne:
149 *color_setting_name = kCUPSCanonCNIJGrayScale;
152 case mojom::ColorModel::kCanonCNIJGrayScaleZero:
153 *color_setting_name = kCUPSCanonCNIJGrayScale;
154 *color_value = kZero;
156 case mojom::ColorModel::kEpsonInkColor:
157 *color_setting_name = kCUPSEpsonInk;
158 *color_value = kEpsonColor;
160 case mojom::ColorModel::kEpsonInkMono:
161 *color_setting_name = kCUPSEpsonInk;
162 *color_value = kEpsonMono;
164 case mojom::ColorModel::kKonicaMinoltaSelectColorColor:
165 *color_setting_name = kCUPSKonicaMinoltaSelectColor;
166 *color_value = kColor;
168 case mojom::ColorModel::kKonicaMinoltaSelectColorGrayscale:
169 *color_setting_name = kCUPSKonicaMinoltaSelectColor;
170 *color_value = kGrayscale;
172 case mojom::ColorModel::kOkiOKControlColor:
173 *color_setting_name = kCUPSOkiControl;
174 *color_value = kAuto;
176 case mojom::ColorModel::kOkiOKControlGray:
177 *color_setting_name = kCUPSOkiControl;
178 *color_value = kGray;
180 case mojom::ColorModel::kSharpARCModeCMColor:
181 *color_setting_name = kCUPSSharpARCMode;
182 *color_value = kSharpCMColor;
184 case mojom::ColorModel::kSharpARCModeCMBW:
185 *color_setting_name = kCUPSSharpARCMode;
186 *color_value = kSharpCMBW;
188 case mojom::ColorModel::kXeroxXRXColorAutomatic:
189 *color_setting_name = kCUPSXeroxXRXColor;
190 *color_value = kXeroxAutomatic;
192 case mojom::ColorModel::kXeroxXRXColorBW:
193 *color_setting_name = kCUPSXeroxXRXColor;
194 *color_value = kXeroxBW;
196 case mojom::ColorModel::kXeroxXROutputColorPrintAsColor:
197 *color_setting_name = kCUPSXeroxXROutputColor;
198 *color_value = kPrintAsColor;
200 case mojom::ColorModel::kXeroxXROutputColorPrintAsGrayscale:
201 *color_setting_name = kCUPSXeroxXROutputColor;
202 *color_value = kPrintAsGrayscale;
205 // The default case is excluded from the above switch statement to ensure that
206 // all ColorModel values are determinantly handled.
208 #endif // BUILDFLAG(USE_CUPS)
210 #if BUILDFLAG(USE_CUPS_IPP)
211 std::string GetIppColorModelForModel(mojom::ColorModel color_model) {
212 // Accept `kUnknownColorModel` for consistency with GetColorModelForModel().
213 if (color_model == mojom::ColorModel::kUnknownColorModel)
214 return CUPS_PRINT_COLOR_MODE_MONOCHROME;
216 return IsColorModelSelected(color_model).value()
217 ? CUPS_PRINT_COLOR_MODE_COLOR
218 : CUPS_PRINT_COLOR_MODE_MONOCHROME;
220 #endif // BUILDFLAG(USE_CUPS_IPP)
222 absl::optional<bool> IsColorModelSelected(mojom::ColorModel color_model) {
223 switch (color_model) {
224 case mojom::ColorModel::kColor:
225 case mojom::ColorModel::kCMYK:
226 case mojom::ColorModel::kCMY:
227 case mojom::ColorModel::kKCMY:
228 case mojom::ColorModel::kCMYPlusK:
229 case mojom::ColorModel::kRGB:
230 case mojom::ColorModel::kRGB16:
231 case mojom::ColorModel::kRGBA:
232 case mojom::ColorModel::kColorModeColor:
233 case mojom::ColorModel::kHPColorColor:
234 case mojom::ColorModel::kHpPjlColorAsGrayNo:
235 case mojom::ColorModel::kPrintoutModeNormal:
236 case mojom::ColorModel::kProcessColorModelCMYK:
237 case mojom::ColorModel::kProcessColorModelRGB:
238 case mojom::ColorModel::kBrotherCUPSColor:
239 case mojom::ColorModel::kBrotherBRScript3Color:
240 case mojom::ColorModel::kCanonCNColorModeColor:
241 case mojom::ColorModel::kCanonCNIJGrayScaleZero:
242 case mojom::ColorModel::kEpsonInkColor:
243 case mojom::ColorModel::kKonicaMinoltaSelectColorColor:
244 case mojom::ColorModel::kOkiOKControlColor:
245 case mojom::ColorModel::kSharpARCModeCMColor:
246 case mojom::ColorModel::kXeroxXRXColorAutomatic:
247 case mojom::ColorModel::kXeroxXROutputColorPrintAsColor:
249 case mojom::ColorModel::kGray:
250 case mojom::ColorModel::kBlack:
251 case mojom::ColorModel::kGrayscale:
252 case mojom::ColorModel::kColorModeMonochrome:
253 case mojom::ColorModel::kHPColorBlack:
254 case mojom::ColorModel::kHpPjlColorAsGrayYes:
255 case mojom::ColorModel::kPrintoutModeNormalGray:
256 case mojom::ColorModel::kProcessColorModelGreyscale:
257 case mojom::ColorModel::kBrotherCUPSMono:
258 case mojom::ColorModel::kBrotherBRScript3Black:
259 case mojom::ColorModel::kCanonCNColorModeMono:
260 case mojom::ColorModel::kCanonCNIJGrayScaleOne:
261 case mojom::ColorModel::kEpsonInkMono:
262 case mojom::ColorModel::kKonicaMinoltaSelectColorGrayscale:
263 case mojom::ColorModel::kOkiOKControlGray:
264 case mojom::ColorModel::kSharpARCModeCMBW:
265 case mojom::ColorModel::kXeroxXRXColorBW:
266 case mojom::ColorModel::kXeroxXROutputColorPrintAsGrayscale:
268 case mojom::ColorModel::kUnknownColorModel:
270 return absl::nullopt;
272 // The default case is excluded from the above switch statement to ensure that
273 // all ColorModel values are determinantly handled.
276 bool PrintSettings::RequestedMedia::operator==(
277 const PrintSettings::RequestedMedia& other) const {
278 return std::tie(size_microns, vendor_id) ==
279 std::tie(other.size_microns, other.vendor_id);
282 // Global SequenceNumber used for generating unique cookie values.
283 static base::AtomicSequenceNumber cookie_seq;
285 PrintSettings::PrintSettings() {
289 PrintSettings::PrintSettings(const PrintSettings& settings) {
293 PrintSettings& PrintSettings::operator=(const PrintSettings& settings) {
294 if (this == &settings)
297 ranges_ = settings.ranges_;
298 selection_only_ = settings.selection_only_;
299 margin_type_ = settings.margin_type_;
300 title_ = settings.title_;
301 url_ = settings.url_;
302 display_header_footer_ = settings.display_header_footer_;
303 should_print_backgrounds_ = settings.should_print_backgrounds_;
304 collate_ = settings.collate_;
305 color_ = settings.color_;
306 copies_ = settings.copies_;
307 duplex_mode_ = settings.duplex_mode_;
308 device_name_ = settings.device_name_;
309 requested_media_ = settings.requested_media_;
310 page_setup_device_units_ = settings.page_setup_device_units_;
311 borderless_ = settings.borderless_;
312 media_type_ = settings.media_type_;
313 dpi_ = settings.dpi_;
314 scale_factor_ = settings.scale_factor_;
315 rasterize_pdf_ = settings.rasterize_pdf_;
316 rasterize_pdf_dpi_ = settings.rasterize_pdf_dpi_;
317 landscape_ = settings.landscape_;
318 #if BUILDFLAG(IS_WIN)
319 printer_language_type_ = settings.printer_language_type_;
321 is_modifiable_ = settings.is_modifiable_;
322 pages_per_sheet_ = settings.pages_per_sheet_;
323 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
324 for (const auto& item : settings.advanced_settings_)
325 advanced_settings_.emplace(item.first, item.second.Clone());
326 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
327 #if BUILDFLAG(IS_CHROMEOS)
328 send_user_info_ = settings.send_user_info_;
329 username_ = settings.username_;
330 oauth_token_ = settings.oauth_token_;
331 pin_value_ = settings.pin_value_;
332 client_infos_ = settings.client_infos_;
333 #endif // BUILDFLAG(IS_CHROMEOS)
334 #if BUILDFLAG(ENABLE_OOP_PRINTING_NO_OOP_BASIC_PRINT_DIALOG)
335 system_print_dialog_data_ = settings.system_print_dialog_data_.Clone();
340 PrintSettings::~PrintSettings() = default;
342 bool PrintSettings::operator==(const PrintSettings& other) const {
343 return std::tie(ranges_, selection_only_, margin_type_, title_, url_,
344 display_header_footer_, should_print_backgrounds_, collate_,
345 color_, copies_, duplex_mode_, device_name_, requested_media_,
346 page_setup_device_units_, dpi_, scale_factor_, rasterize_pdf_,
347 rasterize_pdf_dpi_, landscape_,
348 #if BUILDFLAG(IS_WIN)
349 printer_language_type_,
351 is_modifiable_, requested_custom_margins_in_points_,
353 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
357 #if BUILDFLAG(IS_CHROMEOS)
359 send_user_info_, username_, oauth_token_, pin_value_,
360 client_infos_, printer_manually_selected_,
361 printer_status_reason_
364 std::tie(other.ranges_, other.selection_only_, other.margin_type_,
365 other.title_, other.url_, other.display_header_footer_,
366 other.should_print_backgrounds_, other.collate_, other.color_,
367 other.copies_, other.duplex_mode_, other.device_name_,
368 other.requested_media_, other.page_setup_device_units_,
369 other.dpi_, other.scale_factor_, other.rasterize_pdf_,
370 other.rasterize_pdf_dpi_, other.landscape_,
371 #if BUILDFLAG(IS_WIN)
372 other.printer_language_type_,
374 other.is_modifiable_,
375 other.requested_custom_margins_in_points_,
376 other.pages_per_sheet_
377 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
379 other.advanced_settings_
381 #if BUILDFLAG(IS_CHROMEOS)
383 other.send_user_info_, other.username_, other.oauth_token_,
384 other.pin_value_, other.client_infos_,
385 other.printer_manually_selected_, other.printer_status_reason_
390 void PrintSettings::Clear() {
392 selection_only_ = false;
393 margin_type_ = mojom::MarginType::kDefaultMargins;
396 display_header_footer_ = false;
397 should_print_backgrounds_ = false;
399 color_ = mojom::ColorModel::kUnknownColorModel;
401 duplex_mode_ = mojom::DuplexMode::kUnknownDuplexMode;
402 device_name_.clear();
403 requested_media_ = RequestedMedia();
404 page_setup_device_units_.Clear();
408 scale_factor_ = 1.0f;
409 rasterize_pdf_ = false;
410 rasterize_pdf_dpi_ = 0;
412 #if BUILDFLAG(IS_WIN)
413 printer_language_type_ = mojom::PrinterLanguageType::kNone;
415 is_modifiable_ = true;
416 pages_per_sheet_ = 1;
417 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
418 advanced_settings_.clear();
419 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
420 #if BUILDFLAG(IS_CHROMEOS)
421 send_user_info_ = false;
423 oauth_token_.clear();
425 client_infos_.clear();
426 #endif // BUILDFLAG(IS_CHROMEOS)
427 #if BUILDFLAG(ENABLE_OOP_PRINTING_NO_OOP_BASIC_PRINT_DIALOG)
428 system_print_dialog_data_.clear();
432 void PrintSettings::SetPrinterPrintableArea(
433 const gfx::Size& physical_size_device_units,
434 const gfx::Rect& printable_area_device_units,
435 bool landscape_needs_flip) {
436 int units_per_inch = device_units_per_inch();
437 int header_footer_text_height = 0;
438 if (display_header_footer_) {
439 // Hard-code text_height = 0.5cm = ~1/5 of inch.
440 header_footer_text_height = ConvertUnit(kSettingHeaderFooterInterstice,
441 kPointsPerInch, units_per_inch);
445 bool small_paper_size = false;
446 switch (margin_type_) {
447 case mojom::MarginType::kDefaultMargins: {
448 // Default margins 1.0cm = ~2/5 of an inch, unless a page dimension is
449 // less than 2.54 cm = ~1 inch, in which case set the margins in that
451 static constexpr double kCmInMicrons = 10000;
452 int margin_printer_units =
453 ConvertUnit(kCmInMicrons, kMicronsPerInch, units_per_inch);
454 int min_size_printer_units = units_per_inch;
455 margins.header = header_footer_text_height;
456 margins.footer = header_footer_text_height;
457 if (physical_size_device_units.height() > min_size_printer_units) {
458 margins.top = margin_printer_units;
459 margins.bottom = margin_printer_units;
463 small_paper_size = true;
465 if (physical_size_device_units.width() > min_size_printer_units) {
466 margins.left = margin_printer_units;
467 margins.right = margin_printer_units;
471 small_paper_size = true;
475 case mojom::MarginType::kNoMargins:
476 case mojom::MarginType::kPrintableAreaMargins: {
485 case mojom::MarginType::kCustomMargins: {
488 margins.top = ConvertUnit(requested_custom_margins_in_points_.top,
489 kPointsPerInch, units_per_inch);
490 margins.bottom = ConvertUnit(requested_custom_margins_in_points_.bottom,
491 kPointsPerInch, units_per_inch);
492 margins.left = ConvertUnit(requested_custom_margins_in_points_.left,
493 kPointsPerInch, units_per_inch);
494 margins.right = ConvertUnit(requested_custom_margins_in_points_.right,
495 kPointsPerInch, units_per_inch);
503 if ((margin_type_ == mojom::MarginType::kDefaultMargins ||
504 margin_type_ == mojom::MarginType::kPrintableAreaMargins) &&
506 page_setup_device_units_.SetRequestedMargins(margins);
508 page_setup_device_units_.ForceRequestedMargins(margins);
510 page_setup_device_units_.Init(physical_size_device_units,
511 printable_area_device_units,
512 header_footer_text_height);
513 if (landscape_ && landscape_needs_flip)
514 page_setup_device_units_.FlipOrientation();
517 #if BUILDFLAG(IS_WIN)
518 void PrintSettings::UpdatePrinterPrintableArea(
519 const gfx::Rect& printable_area_um) {
520 // Scale the page size and printable area to device units.
521 // Blink doesn't support different dpi settings in X and Y axis. Because of
522 // this, printers with non-square pixels still scale page size and printable
523 // area using device_units_per_inch() instead of their respective dimensions
524 // in device_units_per_inch_size().
525 float scale = static_cast<float>(device_units_per_inch()) / kMicronsPerInch;
526 gfx::Rect printable_area_device_units =
527 gfx::ScaleToRoundedRect(printable_area_um, scale);
529 // Protect against misbehaving drivers. We have observed some drivers return
530 // incorrect values compared to page size. E.g., HP Business Inkjet 2300 PS.
531 gfx::Rect physical_size_rect(page_setup_device_units_.physical_size());
532 if (printable_area_device_units.IsEmpty() ||
533 !physical_size_rect.Contains(printable_area_device_units)) {
534 // Invalid printable area! Default to paper size.
535 printable_area_device_units = physical_size_rect;
538 page_setup_device_units_.Init(page_setup_device_units_.physical_size(),
539 printable_area_device_units,
540 page_setup_device_units_.text_height());
544 void PrintSettings::SetCustomMargins(
545 const PageMargins& requested_margins_in_points) {
546 requested_custom_margins_in_points_ = requested_margins_in_points;
547 margin_type_ = mojom::MarginType::kCustomMargins;
551 int PrintSettings::NewCookie() {
552 // A cookie of 0 is used to mark a document as unassigned, count from 1.
553 return cookie_seq.GetNext() + 1;
557 int PrintSettings::NewInvalidCookie() {
561 void PrintSettings::SetOrientation(bool landscape) {
562 if (landscape_ != landscape) {
563 landscape_ = landscape;
564 page_setup_device_units_.FlipOrientation();
568 } // namespace printing