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 <algorithm>
8#include <cmath>
9#include <string>
10
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/time/time.h"
14#include "base/values.h"
15#include "printing/page_size_margins.h"
16#include "printing/print_job_constants.h"
17#include "printing/print_settings.h"
18#include "printing/units.h"
19
20namespace printing {
21
22namespace {
23
24void GetCustomMarginsFromJobSettings(const base::DictionaryValue& settings,
25                                     PageSizeMargins* page_size_margins) {
26  const base::DictionaryValue* custom_margins;
27  if (!settings.GetDictionary(kSettingMarginsCustom, &custom_margins) ||
28      !custom_margins->GetDouble(kSettingMarginTop,
29                                 &page_size_margins->margin_top) ||
30      !custom_margins->GetDouble(kSettingMarginBottom,
31                                 &page_size_margins->margin_bottom) ||
32      !custom_margins->GetDouble(kSettingMarginLeft,
33                                 &page_size_margins->margin_left) ||
34      !custom_margins->GetDouble(kSettingMarginRight,
35                                 &page_size_margins->margin_right)) {
36    NOTREACHED();
37  }
38}
39
40void SetMarginsToJobSettings(const std::string& json_path,
41                             const PageMargins& margins,
42                             base::DictionaryValue* job_settings) {
43  base::DictionaryValue* dict = new base::DictionaryValue;
44  job_settings->Set(json_path, dict);
45  dict->SetInteger(kSettingMarginTop, margins.top);
46  dict->SetInteger(kSettingMarginBottom, margins.bottom);
47  dict->SetInteger(kSettingMarginLeft, margins.left);
48  dict->SetInteger(kSettingMarginRight, margins.right);
49}
50
51void SetSizeToJobSettings(const std::string& json_path,
52                          const gfx::Size& size,
53                          base::DictionaryValue* job_settings) {
54  base::DictionaryValue* dict = new base::DictionaryValue;
55  job_settings->Set(json_path, dict);
56  dict->SetInteger("width", size.width());
57  dict->SetInteger("height", size.height());
58}
59
60void SetRectToJobSettings(const std::string& json_path,
61                          const gfx::Rect& rect,
62                          base::DictionaryValue* job_settings) {
63  base::DictionaryValue* dict = new base::DictionaryValue;
64  job_settings->Set(json_path, dict);
65  dict->SetInteger("x", rect.x());
66  dict->SetInteger("y", rect.y());
67  dict->SetInteger("width", rect.width());
68  dict->SetInteger("height", rect.height());
69}
70
71}  // namespace
72
73bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings,
74                                  PrintSettings* settings) {
75  bool display_header_footer = false;
76  if (!job_settings.GetBoolean(kSettingHeaderFooterEnabled,
77                               &display_header_footer)) {
78    return false;
79  }
80  settings->set_display_header_footer(display_header_footer);
81
82  if (settings->display_header_footer()) {
83    base::string16 title;
84    base::string16 url;
85    if (!job_settings.GetString(kSettingHeaderFooterTitle, &title) ||
86        !job_settings.GetString(kSettingHeaderFooterURL, &url)) {
87      return false;
88    }
89    settings->set_title(title);
90    settings->set_url(url);
91  }
92
93  bool backgrounds = false;
94  bool selection_only = false;
95  if (!job_settings.GetBoolean(kSettingShouldPrintBackgrounds, &backgrounds) ||
96      !job_settings.GetBoolean(kSettingShouldPrintSelectionOnly,
97                               &selection_only)) {
98    return false;
99  }
100  settings->set_should_print_backgrounds(backgrounds);
101  settings->set_selection_only(selection_only);
102
103  PrintSettings::RequestedMedia requested_media;
104  const base::DictionaryValue* media_size_value = NULL;
105  if (job_settings.GetDictionary(kSettingMediaSize, &media_size_value)) {
106    int width_microns = 0;
107    int height_microns = 0;
108    if (media_size_value->GetInteger(kSettingMediaSizeWidthMicrons,
109                                     &width_microns) &&
110        media_size_value->GetInteger(kSettingMediaSizeHeightMicrons,
111                                     &height_microns)) {
112      requested_media.size_microns = gfx::Size(width_microns, height_microns);
113    }
114    std::string vendor_id;
115    if (media_size_value->GetString(kSettingMediaSizeVendorId, &vendor_id) &&
116        !vendor_id.empty()) {
117      requested_media.vendor_id = vendor_id;
118    }
119  }
120  settings->set_requested_media(requested_media);
121
122  int margin_type = DEFAULT_MARGINS;
123  if (!job_settings.GetInteger(kSettingMarginsType, &margin_type) ||
124      (margin_type != DEFAULT_MARGINS &&
125       margin_type != NO_MARGINS &&
126       margin_type != CUSTOM_MARGINS &&
127       margin_type != PRINTABLE_AREA_MARGINS)) {
128    margin_type = DEFAULT_MARGINS;
129  }
130  settings->set_margin_type(static_cast<MarginType>(margin_type));
131
132  if (margin_type == CUSTOM_MARGINS) {
133    PageSizeMargins page_size_margins;
134    GetCustomMarginsFromJobSettings(job_settings, &page_size_margins);
135
136    PageMargins margins_in_points;
137    margins_in_points.Clear();
138    margins_in_points.top = page_size_margins.margin_top;
139    margins_in_points.bottom = page_size_margins.margin_bottom;
140    margins_in_points.left = page_size_margins.margin_left;
141    margins_in_points.right = page_size_margins.margin_right;
142
143    settings->SetCustomMargins(margins_in_points);
144  }
145
146  PageRanges new_ranges;
147  const base::ListValue* page_range_array = NULL;
148  if (job_settings.GetList(kSettingPageRange, &page_range_array)) {
149    for (size_t index = 0; index < page_range_array->GetSize(); ++index) {
150      const base::DictionaryValue* dict;
151      if (!page_range_array->GetDictionary(index, &dict))
152        continue;
153
154      PageRange range;
155      if (!dict->GetInteger(kSettingPageRangeFrom, &range.from) ||
156          !dict->GetInteger(kSettingPageRangeTo, &range.to)) {
157        continue;
158      }
159
160      // Page numbers are 1-based in the dictionary.
161      // Page numbers are 0-based for the printing context.
162      range.from--;
163      range.to--;
164      new_ranges.push_back(range);
165    }
166  }
167  settings->set_ranges(new_ranges);
168
169  int color = 0;
170  bool landscape = false;
171  int duplex_mode = 0;
172  base::string16 device_name;
173  bool collate = false;
174  int copies = 1;
175
176  if (!job_settings.GetBoolean(kSettingCollate, &collate) ||
177      !job_settings.GetInteger(kSettingCopies, &copies) ||
178      !job_settings.GetInteger(kSettingColor, &color) ||
179      !job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
180      !job_settings.GetBoolean(kSettingLandscape, &landscape) ||
181      !job_settings.GetString(kSettingDeviceName, &device_name)) {
182    return false;
183  }
184
185  settings->set_collate(collate);
186  settings->set_copies(copies);
187  settings->SetOrientation(landscape);
188  settings->set_device_name(device_name);
189  settings->set_duplex_mode(static_cast<DuplexMode>(duplex_mode));
190  settings->set_color(static_cast<ColorModel>(color));
191
192  return true;
193}
194
195void PrintSettingsToJobSettingsDebug(const PrintSettings& settings,
196                                     base::DictionaryValue* job_settings) {
197  job_settings->SetBoolean(kSettingHeaderFooterEnabled,
198                           settings.display_header_footer());
199  job_settings->SetString(kSettingHeaderFooterTitle, settings.title());
200  job_settings->SetString(kSettingHeaderFooterURL, settings.url());
201  job_settings->SetBoolean(kSettingShouldPrintBackgrounds,
202                           settings.should_print_backgrounds());
203  job_settings->SetBoolean(kSettingShouldPrintSelectionOnly,
204                           settings.selection_only());
205  job_settings->SetInteger(kSettingMarginsType, settings.margin_type());
206  if (!settings.ranges().empty()) {
207    base::ListValue* page_range_array = new base::ListValue;
208    job_settings->Set(kSettingPageRange, page_range_array);
209    for (size_t i = 0; i < settings.ranges().size(); ++i) {
210      base::DictionaryValue* dict = new base::DictionaryValue;
211      page_range_array->Append(dict);
212      dict->SetInteger(kSettingPageRangeFrom, settings.ranges()[i].from + 1);
213      dict->SetInteger(kSettingPageRangeTo, settings.ranges()[i].to + 1);
214    }
215  }
216
217  job_settings->SetBoolean(kSettingCollate, settings.collate());
218  job_settings->SetInteger(kSettingCopies, settings.copies());
219  job_settings->SetInteger(kSettingColor, settings.color());
220  job_settings->SetInteger(kSettingDuplexMode, settings.duplex_mode());
221  job_settings->SetBoolean(kSettingLandscape, settings.landscape());
222  job_settings->SetString(kSettingDeviceName, settings.device_name());
223
224  // Following values are not read form JSON by InitSettings, so do not have
225  // common public constants. So just serialize in "debug" section.
226  base::DictionaryValue* debug = new base::DictionaryValue;
227  job_settings->Set("debug", debug);
228  debug->SetDouble("minShrink", settings.min_shrink());
229  debug->SetDouble("maxShrink", settings.max_shrink());
230  debug->SetInteger("desiredDpi", settings.desired_dpi());
231  debug->SetInteger("dpi", settings.dpi());
232  debug->SetInteger("deviceUnitsPerInch", settings.device_units_per_inch());
233  debug->SetBoolean("support_alpha_blend", settings.should_print_backgrounds());
234  debug->SetString("media_vendor_od", settings.requested_media().vendor_id);
235  SetSizeToJobSettings(
236      "media_size", settings.requested_media().size_microns, debug);
237  SetMarginsToJobSettings("requested_custom_margins_in_points",
238                          settings.requested_custom_margins_in_points(),
239                          debug);
240  const PageSetup& page_setup = settings.page_setup_device_units();
241  SetMarginsToJobSettings(
242      "effective_margins", page_setup.effective_margins(), debug);
243  SetSizeToJobSettings("physical_size", page_setup.physical_size(), debug);
244  SetRectToJobSettings("overlay_area", page_setup.overlay_area(), debug);
245  SetRectToJobSettings("content_area", page_setup.content_area(), debug);
246  SetRectToJobSettings("printable_area", page_setup.printable_area(), debug);
247}
248
249}  // namespace printing
250