print_settings_conversion.cc 14 KB

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