| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "printing/print_settings_conversion.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "printing/print_job_constants.h" |
| #include "printing/print_settings.h" |
| #include "printing/units.h" |
| |
| namespace printing { |
| |
| namespace { |
| |
| void GetCustomMarginsFromJobSettings(const base::Value& settings, |
| PageMargins* page_size_margins) { |
| const base::Value* custom_margins = settings.FindKey(kSettingMarginsCustom); |
| if (!custom_margins) { |
| NOTREACHED(); |
| return; |
| } |
| page_size_margins->top = |
| custom_margins->FindIntKey(kSettingMarginTop).value_or(0); |
| page_size_margins->bottom = |
| custom_margins->FindIntKey(kSettingMarginBottom).value_or(0); |
| page_size_margins->left = |
| custom_margins->FindIntKey(kSettingMarginLeft).value_or(0); |
| page_size_margins->right = |
| custom_margins->FindIntKey(kSettingMarginRight).value_or(0); |
| } |
| |
| void SetMarginsToJobSettings(const std::string& json_path, |
| const PageMargins& margins, |
| base::DictionaryValue* job_settings) { |
| auto dict = std::make_unique<base::DictionaryValue>(); |
| dict->SetInteger(kSettingMarginTop, margins.top); |
| dict->SetInteger(kSettingMarginBottom, margins.bottom); |
| dict->SetInteger(kSettingMarginLeft, margins.left); |
| dict->SetInteger(kSettingMarginRight, margins.right); |
| job_settings->Set(json_path, std::move(dict)); |
| } |
| |
| void SetSizeToJobSettings(const std::string& json_path, |
| const gfx::Size& size, |
| base::DictionaryValue* job_settings) { |
| auto dict = std::make_unique<base::DictionaryValue>(); |
| dict->SetInteger("width", size.width()); |
| dict->SetInteger("height", size.height()); |
| job_settings->Set(json_path, std::move(dict)); |
| } |
| |
| void SetRectToJobSettings(const std::string& json_path, |
| const gfx::Rect& rect, |
| base::DictionaryValue* job_settings) { |
| auto dict = std::make_unique<base::DictionaryValue>(); |
| dict->SetInteger("x", rect.x()); |
| dict->SetInteger("y", rect.y()); |
| dict->SetInteger("width", rect.width()); |
| dict->SetInteger("height", rect.height()); |
| job_settings->Set(json_path, std::move(dict)); |
| } |
| |
| } // namespace |
| |
| bool PrintSettingsFromJobSettings(const base::Value& job_settings, |
| PrintSettings* settings) { |
| base::Optional<bool> display_header_footer = |
| job_settings.FindBoolKey(kSettingHeaderFooterEnabled); |
| if (!display_header_footer.has_value()) |
| return false; |
| |
| settings->set_display_header_footer(display_header_footer.value()); |
| if (settings->display_header_footer()) { |
| const std::string* title = |
| job_settings.FindStringKey(kSettingHeaderFooterTitle); |
| const std::string* url = |
| job_settings.FindStringKey(kSettingHeaderFooterURL); |
| if (!title || !url) |
| return false; |
| |
| settings->set_title(base::UTF8ToUTF16(*title)); |
| settings->set_url(base::UTF8ToUTF16(*url)); |
| } |
| |
| base::Optional<bool> backgrounds = |
| job_settings.FindBoolKey(kSettingShouldPrintBackgrounds); |
| base::Optional<bool> selection_only = |
| job_settings.FindBoolKey(kSettingShouldPrintSelectionOnly); |
| if (!backgrounds.has_value() || !selection_only.has_value()) |
| return false; |
| |
| settings->set_should_print_backgrounds(backgrounds.value()); |
| settings->set_selection_only(selection_only.value()); |
| |
| PrintSettings::RequestedMedia requested_media; |
| const base::Value* media_size_value = job_settings.FindKeyOfType( |
| kSettingMediaSize, base::Value::Type::DICTIONARY); |
| if (media_size_value) { |
| base::Optional<int> width_microns = |
| media_size_value->FindIntKey(kSettingMediaSizeWidthMicrons); |
| base::Optional<int> height_microns = |
| media_size_value->FindIntKey(kSettingMediaSizeHeightMicrons); |
| if (width_microns.has_value() && height_microns.has_value()) { |
| requested_media.size_microns = |
| gfx::Size(width_microns.value(), height_microns.value()); |
| } |
| |
| const std::string* vendor_id = |
| media_size_value->FindStringKey(kSettingMediaSizeVendorId); |
| if (vendor_id && !vendor_id->empty()) |
| requested_media.vendor_id = *vendor_id; |
| } |
| settings->set_requested_media(requested_media); |
| |
| int margin_type = |
| job_settings.FindIntKey(kSettingMarginsType).value_or(DEFAULT_MARGINS); |
| if (margin_type != DEFAULT_MARGINS && margin_type != NO_MARGINS && |
| margin_type != CUSTOM_MARGINS && margin_type != PRINTABLE_AREA_MARGINS) { |
| margin_type = DEFAULT_MARGINS; |
| } |
| settings->set_margin_type(static_cast<MarginType>(margin_type)); |
| |
| if (margin_type == CUSTOM_MARGINS) { |
| PageMargins margins_in_points; |
| margins_in_points.Clear(); |
| GetCustomMarginsFromJobSettings(job_settings, &margins_in_points); |
| settings->SetCustomMargins(margins_in_points); |
| } |
| |
| PageRanges new_ranges; |
| const base::Value* page_range_array = |
| job_settings.FindKeyOfType(kSettingPageRange, base::Value::Type::LIST); |
| if (page_range_array) { |
| for (const base::Value& value : page_range_array->GetList()) { |
| if (!value.is_dict()) |
| continue; |
| |
| base::Optional<int> from = value.FindIntKey(kSettingPageRangeFrom); |
| base::Optional<int> to = value.FindIntKey(kSettingPageRangeTo); |
| if (!from.has_value() || !to.has_value()) |
| continue; |
| |
| // Page numbers are 1-based in the dictionary. |
| // Page numbers are 0-based for the printing context. |
| new_ranges.push_back(PageRange{from.value() - 1, to.value() - 1}); |
| } |
| } |
| settings->set_ranges(new_ranges); |
| |
| base::Optional<bool> collate = job_settings.FindBoolKey(kSettingCollate); |
| base::Optional<int> copies = job_settings.FindIntKey(kSettingCopies); |
| base::Optional<int> color = job_settings.FindIntKey(kSettingColor); |
| base::Optional<int> duplex_mode = job_settings.FindIntKey(kSettingDuplexMode); |
| base::Optional<bool> landscape = job_settings.FindBoolKey(kSettingLandscape); |
| const std::string* device_name = |
| job_settings.FindStringKey(kSettingDeviceName); |
| base::Optional<int> scale_factor = |
| job_settings.FindIntKey(kSettingScaleFactor); |
| base::Optional<bool> rasterize_pdf = |
| job_settings.FindBoolKey(kSettingRasterizePdf); |
| base::Optional<int> pages_per_sheet = |
| job_settings.FindIntKey(kSettingPagesPerSheet); |
| |
| if (!collate.has_value() || !copies.has_value() || !color.has_value() || |
| !duplex_mode.has_value() || !landscape.has_value() || !device_name || |
| !scale_factor.has_value() || !rasterize_pdf.has_value() || |
| !pages_per_sheet.has_value()) { |
| return false; |
| } |
| #if defined(OS_WIN) |
| base::Optional<int> dpi_horizontal = |
| job_settings.FindIntKey(kSettingDpiHorizontal); |
| base::Optional<int> dpi_vertical = |
| job_settings.FindIntKey(kSettingDpiVertical); |
| if (!dpi_horizontal.has_value() || !dpi_vertical.has_value()) |
| return false; |
| |
| settings->set_dpi_xy(dpi_horizontal.value(), dpi_vertical.value()); |
| #endif |
| |
| settings->set_collate(collate.value()); |
| settings->set_copies(copies.value()); |
| settings->SetOrientation(landscape.value()); |
| settings->set_device_name(base::UTF8ToUTF16(*device_name)); |
| settings->set_duplex_mode(static_cast<DuplexMode>(duplex_mode.value())); |
| settings->set_color(static_cast<ColorModel>(color.value())); |
| settings->set_scale_factor(static_cast<double>(scale_factor.value()) / 100.0); |
| settings->set_rasterize_pdf(rasterize_pdf.value()); |
| settings->set_pages_per_sheet(pages_per_sheet.value()); |
| base::Optional<bool> is_modifiable = |
| job_settings.FindBoolKey(kSettingPreviewModifiable); |
| if (is_modifiable.has_value()) { |
| settings->set_is_modifiable(is_modifiable.value()); |
| #if defined(OS_WIN) |
| settings->set_print_text_with_gdi(is_modifiable.value()); |
| #endif |
| } |
| |
| #if defined(OS_CHROMEOS) |
| bool send_user_info = |
| job_settings.FindBoolKey(kSettingSendUserInfo).value_or(false); |
| settings->set_send_user_info(send_user_info); |
| if (send_user_info) { |
| const std::string* username = job_settings.FindStringKey(kSettingUsername); |
| if (username) |
| settings->set_username(*username); |
| |
| const std::string* job_title = job_settings.FindStringKey(kSettingJobTitle); |
| if (job_title) |
| settings->set_job_title(*job_title); |
| } |
| |
| const std::string* pin_value = job_settings.FindStringKey(kSettingPinValue); |
| if (pin_value) |
| settings->set_pin_value(*pin_value); |
| #endif |
| |
| return true; |
| } |
| |
| void PrintSettingsToJobSettingsDebug(const PrintSettings& settings, |
| base::DictionaryValue* job_settings) { |
| job_settings->SetBoolean(kSettingHeaderFooterEnabled, |
| settings.display_header_footer()); |
| job_settings->SetString(kSettingHeaderFooterTitle, settings.title()); |
| job_settings->SetString(kSettingHeaderFooterURL, settings.url()); |
| job_settings->SetBoolean(kSettingShouldPrintBackgrounds, |
| settings.should_print_backgrounds()); |
| job_settings->SetBoolean(kSettingShouldPrintSelectionOnly, |
| settings.selection_only()); |
| job_settings->SetInteger(kSettingMarginsType, settings.margin_type()); |
| if (!settings.ranges().empty()) { |
| auto page_range_array = std::make_unique<base::ListValue>(); |
| for (size_t i = 0; i < settings.ranges().size(); ++i) { |
| auto dict = std::make_unique<base::DictionaryValue>(); |
| dict->SetInteger(kSettingPageRangeFrom, settings.ranges()[i].from + 1); |
| dict->SetInteger(kSettingPageRangeTo, settings.ranges()[i].to + 1); |
| page_range_array->Append(std::move(dict)); |
| } |
| job_settings->Set(kSettingPageRange, std::move(page_range_array)); |
| } |
| |
| job_settings->SetBoolean(kSettingCollate, settings.collate()); |
| job_settings->SetInteger(kSettingCopies, settings.copies()); |
| job_settings->SetInteger(kSettingColor, settings.color()); |
| job_settings->SetInteger(kSettingDuplexMode, settings.duplex_mode()); |
| job_settings->SetBoolean(kSettingLandscape, settings.landscape()); |
| job_settings->SetString(kSettingDeviceName, settings.device_name()); |
| job_settings->SetInteger(kSettingPagesPerSheet, settings.pages_per_sheet()); |
| |
| // Following values are not read form JSON by InitSettings, so do not have |
| // common public constants. So just serialize in "debug" section. |
| auto debug = std::make_unique<base::DictionaryValue>(); |
| debug->SetInteger("dpi", settings.dpi()); |
| debug->SetInteger("deviceUnitsPerInch", settings.device_units_per_inch()); |
| debug->SetBoolean("support_alpha_blend", settings.should_print_backgrounds()); |
| debug->SetString("media_vendor_id", settings.requested_media().vendor_id); |
| SetSizeToJobSettings("media_size", settings.requested_media().size_microns, |
| debug.get()); |
| SetMarginsToJobSettings("requested_custom_margins_in_points", |
| settings.requested_custom_margins_in_points(), |
| debug.get()); |
| const PageSetup& page_setup = settings.page_setup_device_units(); |
| SetMarginsToJobSettings("effective_margins", page_setup.effective_margins(), |
| debug.get()); |
| SetSizeToJobSettings("physical_size", page_setup.physical_size(), |
| debug.get()); |
| SetRectToJobSettings("overlay_area", page_setup.overlay_area(), debug.get()); |
| SetRectToJobSettings("content_area", page_setup.content_area(), debug.get()); |
| SetRectToJobSettings("printable_area", page_setup.printable_area(), |
| debug.get()); |
| job_settings->Set("debug", std::move(debug)); |
| } |
| |
| } // namespace printing |