1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "printing/print_settings_conversion.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <cmath>
11 #include <memory>
12 #include <string>
13 #include <utility>
14
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "build/build_config.h"
20 #include "build/chromeos_buildflags.h"
21 #include "printing/mojom/print.mojom.h"
22 #include "printing/print_job_constants.h"
23 #include "printing/print_settings.h"
24 #include "printing/units.h"
25
26 namespace printing {
27
28 namespace {
29
30 // Note: If this code crashes, then the caller has passed in invalid |settings|.
31 // Fix the caller, instead of trying to avoid the crash here.
GetCustomMarginsFromJobSettings(const base::Value & settings)32 PageMargins GetCustomMarginsFromJobSettings(const base::Value& settings) {
33 PageMargins margins_in_points;
34 const base::Value* custom_margins = settings.FindKey(kSettingMarginsCustom);
35 margins_in_points.top = custom_margins->FindIntKey(kSettingMarginTop).value();
36 margins_in_points.bottom =
37 custom_margins->FindIntKey(kSettingMarginBottom).value();
38 margins_in_points.left =
39 custom_margins->FindIntKey(kSettingMarginLeft).value();
40 margins_in_points.right =
41 custom_margins->FindIntKey(kSettingMarginRight).value();
42 return margins_in_points;
43 }
44
SetMarginsToJobSettings(const std::string & json_path,const PageMargins & margins,base::DictionaryValue * job_settings)45 void SetMarginsToJobSettings(const std::string& json_path,
46 const PageMargins& margins,
47 base::DictionaryValue* job_settings) {
48 auto dict = std::make_unique<base::DictionaryValue>();
49 dict->SetInteger(kSettingMarginTop, margins.top);
50 dict->SetInteger(kSettingMarginBottom, margins.bottom);
51 dict->SetInteger(kSettingMarginLeft, margins.left);
52 dict->SetInteger(kSettingMarginRight, margins.right);
53 job_settings->Set(json_path, std::move(dict));
54 }
55
SetSizeToJobSettings(const std::string & json_path,const gfx::Size & size,base::DictionaryValue * job_settings)56 void SetSizeToJobSettings(const std::string& json_path,
57 const gfx::Size& size,
58 base::DictionaryValue* job_settings) {
59 auto dict = std::make_unique<base::DictionaryValue>();
60 dict->SetInteger("width", size.width());
61 dict->SetInteger("height", size.height());
62 job_settings->Set(json_path, std::move(dict));
63 }
64
SetRectToJobSettings(const std::string & json_path,const gfx::Rect & rect,base::DictionaryValue * job_settings)65 void SetRectToJobSettings(const std::string& json_path,
66 const gfx::Rect& rect,
67 base::DictionaryValue* job_settings) {
68 auto dict = std::make_unique<base::DictionaryValue>();
69 dict->SetInteger("x", rect.x());
70 dict->SetInteger("y", rect.y());
71 dict->SetInteger("width", rect.width());
72 dict->SetInteger("height", rect.height());
73 job_settings->Set(json_path, std::move(dict));
74 }
75
76 } // namespace
77
GetPageRangesFromJobSettings(const base::Value & job_settings)78 PageRanges GetPageRangesFromJobSettings(const base::Value& job_settings) {
79 PageRanges page_ranges;
80 const base::Value* page_range_array =
81 job_settings.FindListKey(kSettingPageRange);
82 if (page_range_array) {
83 for (const base::Value& page_range : page_range_array->GetList()) {
84 if (!page_range.is_dict())
85 continue;
86
87 base::Optional<int> from = page_range.FindIntKey(kSettingPageRangeFrom);
88 base::Optional<int> to = page_range.FindIntKey(kSettingPageRangeTo);
89 if (!from.has_value() || !to.has_value())
90 continue;
91
92 // Page numbers are 1-based in the dictionary.
93 // Page numbers are 0-based for the printing context.
94 page_ranges.push_back(PageRange{from.value() - 1, to.value() - 1});
95 }
96 }
97 return page_ranges;
98 }
99
PrintSettingsFromJobSettings(const base::Value & job_settings)100 std::unique_ptr<PrintSettings> PrintSettingsFromJobSettings(
101 const base::Value& job_settings) {
102 auto settings = std::make_unique<PrintSettings>();
103 base::Optional<bool> display_header_footer =
104 job_settings.FindBoolKey(kSettingHeaderFooterEnabled);
105 if (!display_header_footer.has_value())
106 return nullptr;
107
108 settings->set_display_header_footer(display_header_footer.value());
109 if (settings->display_header_footer()) {
110 const std::string* title =
111 job_settings.FindStringKey(kSettingHeaderFooterTitle);
112 const std::string* url =
113 job_settings.FindStringKey(kSettingHeaderFooterURL);
114 if (!title || !url)
115 return nullptr;
116
117 settings->set_title(base::UTF8ToUTF16(*title));
118 settings->set_url(base::UTF8ToUTF16(*url));
119 }
120
121 base::Optional<bool> backgrounds =
122 job_settings.FindBoolKey(kSettingShouldPrintBackgrounds);
123 base::Optional<bool> selection_only =
124 job_settings.FindBoolKey(kSettingShouldPrintSelectionOnly);
125 if (!backgrounds.has_value() || !selection_only.has_value())
126 return nullptr;
127
128 settings->set_should_print_backgrounds(backgrounds.value());
129 settings->set_selection_only(selection_only.value());
130
131 PrintSettings::RequestedMedia requested_media;
132 const base::Value* media_size_value = job_settings.FindKeyOfType(
133 kSettingMediaSize, base::Value::Type::DICTIONARY);
134 if (media_size_value) {
135 base::Optional<int> width_microns =
136 media_size_value->FindIntKey(kSettingMediaSizeWidthMicrons);
137 base::Optional<int> height_microns =
138 media_size_value->FindIntKey(kSettingMediaSizeHeightMicrons);
139 if (width_microns.has_value() && height_microns.has_value()) {
140 requested_media.size_microns =
141 gfx::Size(width_microns.value(), height_microns.value());
142 }
143
144 const std::string* vendor_id =
145 media_size_value->FindStringKey(kSettingMediaSizeVendorId);
146 if (vendor_id && !vendor_id->empty())
147 requested_media.vendor_id = *vendor_id;
148 }
149 settings->set_requested_media(requested_media);
150
151 mojom::MarginType margin_type = static_cast<mojom::MarginType>(
152 job_settings.FindIntKey(kSettingMarginsType)
153 .value_or(static_cast<int>(mojom::MarginType::kDefaultMargins)));
154 if (margin_type != mojom::MarginType::kDefaultMargins &&
155 margin_type != mojom::MarginType::kNoMargins &&
156 margin_type != mojom::MarginType::kCustomMargins &&
157 margin_type != mojom::MarginType::kPrintableAreaMargins) {
158 margin_type = mojom::MarginType::kDefaultMargins;
159 }
160 settings->set_margin_type(margin_type);
161
162 if (margin_type == mojom::MarginType::kCustomMargins)
163 settings->SetCustomMargins(GetCustomMarginsFromJobSettings(job_settings));
164
165 settings->set_ranges(GetPageRangesFromJobSettings(job_settings));
166
167 base::Optional<bool> collate = job_settings.FindBoolKey(kSettingCollate);
168 base::Optional<int> copies = job_settings.FindIntKey(kSettingCopies);
169 base::Optional<int> color = job_settings.FindIntKey(kSettingColor);
170 base::Optional<int> duplex_mode = job_settings.FindIntKey(kSettingDuplexMode);
171 base::Optional<bool> landscape = job_settings.FindBoolKey(kSettingLandscape);
172 base::Optional<int> scale_factor =
173 job_settings.FindIntKey(kSettingScaleFactor);
174 base::Optional<bool> rasterize_pdf =
175 job_settings.FindBoolKey(kSettingRasterizePdf);
176 base::Optional<int> pages_per_sheet =
177 job_settings.FindIntKey(kSettingPagesPerSheet);
178
179 if (!collate.has_value() || !copies.has_value() || !color.has_value() ||
180 !duplex_mode.has_value() || !landscape.has_value() ||
181 !scale_factor.has_value() || !rasterize_pdf.has_value() ||
182 !pages_per_sheet.has_value()) {
183 return nullptr;
184 }
185
186 base::Optional<int> dpi_horizontal =
187 job_settings.FindIntKey(kSettingDpiHorizontal);
188 base::Optional<int> dpi_vertical =
189 job_settings.FindIntKey(kSettingDpiVertical);
190 if (!dpi_horizontal.has_value() || !dpi_vertical.has_value())
191 return nullptr;
192 settings->set_dpi_xy(dpi_horizontal.value(), dpi_vertical.value());
193
194 settings->set_collate(collate.value());
195 settings->set_copies(copies.value());
196 settings->SetOrientation(landscape.value());
197 settings->set_device_name(
198 base::UTF8ToUTF16(*job_settings.FindStringKey(kSettingDeviceName)));
199 settings->set_duplex_mode(
200 static_cast<mojom::DuplexMode>(duplex_mode.value()));
201 settings->set_color(static_cast<mojom::ColorModel>(color.value()));
202 settings->set_scale_factor(static_cast<double>(scale_factor.value()) / 100.0);
203 settings->set_rasterize_pdf(rasterize_pdf.value());
204 settings->set_pages_per_sheet(pages_per_sheet.value());
205 base::Optional<bool> is_modifiable =
206 job_settings.FindBoolKey(kSettingPreviewModifiable);
207 if (is_modifiable.has_value()) {
208 settings->set_is_modifiable(is_modifiable.value());
209 #if defined(OS_WIN)
210 settings->set_print_text_with_gdi(is_modifiable.value());
211 #endif
212 }
213
214 #if defined(OS_CHROMEOS) || ((defined(OS_LINUX) || defined(OS_BSD)) && defined(USE_CUPS))
215 const base::Value* advanced_settings =
216 job_settings.FindDictKey(kSettingAdvancedSettings);
217 if (advanced_settings) {
218 for (const auto& item : advanced_settings->DictItems())
219 settings->advanced_settings().emplace(item.first, item.second.Clone());
220 }
221 #endif // defined(OS_CHROMEOS) || ((defined(OS_LINUX) || defined(OS_BSD)) && defined(USE_CUPS))
222
223 #if BUILDFLAG(IS_ASH)
224 bool send_user_info =
225 job_settings.FindBoolKey(kSettingSendUserInfo).value_or(false);
226 settings->set_send_user_info(send_user_info);
227 if (send_user_info) {
228 const std::string* username = job_settings.FindStringKey(kSettingUsername);
229 if (username)
230 settings->set_username(*username);
231 }
232
233 const std::string* pin_value = job_settings.FindStringKey(kSettingPinValue);
234 if (pin_value)
235 settings->set_pin_value(*pin_value);
236 #endif // BUILDFLAG(IS_ASH)
237
238 return settings;
239 }
240
PrintSettingsToJobSettingsDebug(const PrintSettings & settings,base::DictionaryValue * job_settings)241 void PrintSettingsToJobSettingsDebug(const PrintSettings& settings,
242 base::DictionaryValue* job_settings) {
243 job_settings->SetBoolean(kSettingHeaderFooterEnabled,
244 settings.display_header_footer());
245 job_settings->SetString(kSettingHeaderFooterTitle, settings.title());
246 job_settings->SetString(kSettingHeaderFooterURL, settings.url());
247 job_settings->SetBoolean(kSettingShouldPrintBackgrounds,
248 settings.should_print_backgrounds());
249 job_settings->SetBoolean(kSettingShouldPrintSelectionOnly,
250 settings.selection_only());
251 job_settings->SetInteger(kSettingMarginsType,
252 static_cast<int>(settings.margin_type()));
253 if (!settings.ranges().empty()) {
254 auto page_range_array = std::make_unique<base::ListValue>();
255 for (size_t i = 0; i < settings.ranges().size(); ++i) {
256 auto dict = std::make_unique<base::DictionaryValue>();
257 dict->SetInteger(kSettingPageRangeFrom, settings.ranges()[i].from + 1);
258 dict->SetInteger(kSettingPageRangeTo, settings.ranges()[i].to + 1);
259 page_range_array->Append(std::move(dict));
260 }
261 job_settings->Set(kSettingPageRange, std::move(page_range_array));
262 }
263
264 job_settings->SetBoolean(kSettingCollate, settings.collate());
265 job_settings->SetInteger(kSettingCopies, settings.copies());
266 job_settings->SetInteger(kSettingColor, static_cast<int>(settings.color()));
267 job_settings->SetInteger(kSettingDuplexMode,
268 static_cast<int>(settings.duplex_mode()));
269 job_settings->SetBoolean(kSettingLandscape, settings.landscape());
270 job_settings->SetString(kSettingDeviceName, settings.device_name());
271 job_settings->SetInteger(kSettingPagesPerSheet, settings.pages_per_sheet());
272
273 // Following values are not read form JSON by InitSettings, so do not have
274 // common public constants. So just serialize in "debug" section.
275 auto debug = std::make_unique<base::DictionaryValue>();
276 debug->SetInteger("dpi", settings.dpi());
277 debug->SetInteger("deviceUnitsPerInch", settings.device_units_per_inch());
278 debug->SetBoolean("support_alpha_blend", settings.should_print_backgrounds());
279 debug->SetString("media_vendor_id", settings.requested_media().vendor_id);
280 SetSizeToJobSettings("media_size", settings.requested_media().size_microns,
281 debug.get());
282 SetMarginsToJobSettings("requested_custom_margins_in_points",
283 settings.requested_custom_margins_in_points(),
284 debug.get());
285 const PageSetup& page_setup = settings.page_setup_device_units();
286 SetMarginsToJobSettings("effective_margins", page_setup.effective_margins(),
287 debug.get());
288 SetSizeToJobSettings("physical_size", page_setup.physical_size(),
289 debug.get());
290 SetRectToJobSettings("overlay_area", page_setup.overlay_area(), debug.get());
291 SetRectToJobSettings("content_area", page_setup.content_area(), debug.get());
292 SetRectToJobSettings("printable_area", page_setup.printable_area(),
293 debug.get());
294 job_settings->Set("debug", std::move(debug));
295 }
296
297 } // namespace printing
298