summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-04 01:01:52 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-04 01:01:52 +0000
commit89b80cce73826d7fc3b7b5eb692fbf89b0cba2dd (patch)
treea2d5e58424231ee2e01b8b59af93a312c97e51cc
parent15b44822b226721f14d9b494c00f8eeaee022bfe (diff)
downloadchromium_src-89b80cce73826d7fc3b7b5eb692fbf89b0cba2dd.zip
chromium_src-89b80cce73826d7fc3b7b5eb692fbf89b0cba2dd.tar.gz
chromium_src-89b80cce73826d7fc3b7b5eb692fbf89b0cba2dd.tar.bz2
Reading, writing of CDD and CJT JSON formats.
Printer description and print job ticket formats. BUG=317027 Review URL: https://codereview.chromium.org/150993002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@248644 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--components/cloud_devices.gypi10
-rw-r--r--components/cloud_devices/cloud_device_description.cc78
-rw-r--r--components/cloud_devices/cloud_device_description.h57
-rw-r--r--components/cloud_devices/cloud_device_description_consts.cc20
-rw-r--r--components/cloud_devices/cloud_device_description_consts.h25
-rw-r--r--components/cloud_devices/cloud_devices_json_consts.cc74
-rw-r--r--components/cloud_devices/cloud_devices_json_consts.h84
-rw-r--r--components/cloud_devices/description_items.h231
-rw-r--r--components/cloud_devices/description_items_inl.h211
-rw-r--r--components/cloud_devices/printer_description.cc729
-rw-r--r--components/cloud_devices/printer_description.h362
-rw-r--r--components/cloud_devices/printer_description_unittest.cc581
12 files changed, 2302 insertions, 160 deletions
diff --git a/components/cloud_devices.gypi b/components/cloud_devices.gypi
index d0ab6a8..27adfd1 100644
--- a/components/cloud_devices.gypi
+++ b/components/cloud_devices.gypi
@@ -14,8 +14,14 @@
'../base/base.gyp:base',
],
'sources': [
- 'cloud_devices/cloud_devices_json_consts.cc',
- 'cloud_devices/cloud_devices_json_consts.h',
+ 'cloud_devices/cloud_device_description.cc',
+ 'cloud_devices/cloud_device_description.h',
+ 'cloud_devices/cloud_device_description_consts.cc',
+ 'cloud_devices/cloud_device_description_consts.h',
+ 'cloud_devices/description_items.h',
+ 'cloud_devices/description_items_inl.h',
+ 'cloud_devices/printer_description.cc',
+ 'cloud_devices/printer_description.h',
],
},
],
diff --git a/components/cloud_devices/cloud_device_description.cc b/components/cloud_devices/cloud_device_description.cc
new file mode 100644
index 0000000..124bb49
--- /dev/null
+++ b/components/cloud_devices/cloud_device_description.cc
@@ -0,0 +1,78 @@
+// 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 "components/cloud_devices/cloud_device_description.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "components/cloud_devices/cloud_device_description_consts.h"
+
+namespace cloud_devices {
+
+CloudDeviceDescription::CloudDeviceDescription() {
+ Reset();
+}
+
+CloudDeviceDescription::~CloudDeviceDescription() {
+}
+
+void CloudDeviceDescription::Reset() {
+ root_.reset(new base::DictionaryValue);
+ root_->SetString(json::kVersion, json::kVersion10);
+}
+
+bool CloudDeviceDescription::InitFromString(const std::string& json) {
+ Reset();
+
+ scoped_ptr<base::Value> parsed(base::JSONReader::Read(json));
+ base::DictionaryValue* description = NULL;
+ if (!parsed || !parsed->GetAsDictionary(&description))
+ return false;
+ root_.reset(description);
+ ignore_result(parsed.release());
+
+ std::string version;
+ description->GetString(json::kVersion, &version);
+ return version == json::kVersion10;
+}
+
+std::string CloudDeviceDescription::ToString() const {
+ std::string json;
+ base::JSONWriter::WriteWithOptions(root_.get(),
+ base::JSONWriter::OPTIONS_PRETTY_PRINT,
+ &json);
+ return json;
+}
+
+const base::DictionaryValue* CloudDeviceDescription::GetItem(
+ const std::string& path) const {
+ const base::DictionaryValue* value = NULL;
+ root_->GetDictionary(path, &value);
+ return value;
+}
+
+base::DictionaryValue* CloudDeviceDescription::CreateItem(
+ const std::string& path) {
+ base::DictionaryValue* value = new base::DictionaryValue;
+ root_->Set(path, value);
+ return value;
+}
+
+const base::ListValue* CloudDeviceDescription::GetListItem(
+ const std::string& path) const {
+ const base::ListValue* value = NULL;
+ root_->GetList(path, &value);
+ return value;
+}
+
+base::ListValue* CloudDeviceDescription::CreateListItem(
+ const std::string& path) {
+ base::ListValue* value = new base::ListValue;
+ root_->Set(path, value);
+ return value;
+}
+
+} // namespace cloud_devices
diff --git a/components/cloud_devices/cloud_device_description.h b/components/cloud_devices/cloud_device_description.h
new file mode 100644
index 0000000..ec59c87
--- /dev/null
+++ b/components/cloud_devices/cloud_device_description.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICE_DESCRIPTION_H_
+#define COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICE_DESCRIPTION_H_
+
+#include <string>
+
+#include "base/callback.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace cloud_devices {
+
+// Provides parsing, serialization and validation Cloud Device Description or
+// Cloud Job Ticket.
+// https://developers.google.com/cloud-print/docs/cdd
+class CloudDeviceDescription {
+ public:
+ CloudDeviceDescription();
+ ~CloudDeviceDescription();
+
+ void Reset();
+
+ bool InitFromString(const std::string& json);
+
+ std::string ToString() const;
+
+ // Returns dictionary with capability/option.
+ // Returns NULL if missing.
+ const base::DictionaryValue* GetItem(const std::string& path) const;
+
+ // Create dictionary for capability/option.
+ // Never returns NULL.
+ base::DictionaryValue* CreateItem(const std::string& path);
+
+ // Returns list with capability/option.
+ // Returns NULL if missing.
+ const base::ListValue* GetListItem(const std::string& path) const;
+
+ // Create list for capability/option.
+ // Never returns NULL.
+ base::ListValue* CreateListItem(const std::string& path);
+
+ private:
+ scoped_ptr<base::DictionaryValue> root_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloudDeviceDescription);
+};
+
+} // namespace cloud_devices
+
+#endif // COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICE_DESCRIPTION_H_
diff --git a/components/cloud_devices/cloud_device_description_consts.cc b/components/cloud_devices/cloud_device_description_consts.cc
new file mode 100644
index 0000000..79d9d92
--- /dev/null
+++ b/components/cloud_devices/cloud_device_description_consts.cc
@@ -0,0 +1,20 @@
+// 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 "components/cloud_devices/cloud_device_description_consts.h"
+
+namespace cloud_devices {
+
+namespace json {
+
+const char kVersion[] = "version";
+const char kVersion10[] = "1.0";
+
+const char kKeyDefault[] = "default";
+const char kKeyIsDefault[] = "is_default";
+const char kKeyOption[] = "option";
+
+} // namespace json
+
+} // namespace cloud_devices
diff --git a/components/cloud_devices/cloud_device_description_consts.h b/components/cloud_devices/cloud_device_description_consts.h
new file mode 100644
index 0000000..77443c9
--- /dev/null
+++ b/components/cloud_devices/cloud_device_description_consts.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef COMPONENTS_CLOUD_DEVICESCLOUD_DEVICE_DESCRIPTION_CONSTS_H_
+#define COMPONENTS_CLOUD_DEVICESCLOUD_DEVICE_DESCRIPTION_CONSTS_H_
+
+// Constants for common parts of JSON representation of CDD/CJT.
+
+namespace cloud_devices {
+
+namespace json {
+
+extern const char kVersion[];
+extern const char kVersion10[];
+
+extern const char kKeyDefault[];
+extern const char kKeyIsDefault[];
+extern const char kKeyOption[];
+
+} // namespace json
+
+} // namespace cloud_devices
+
+#endif // COMPONENTS_CLOUD_DEVICESCLOUD_DEVICE_DESCRIPTION_CONSTS_H_
diff --git a/components/cloud_devices/cloud_devices_json_consts.cc b/components/cloud_devices/cloud_devices_json_consts.cc
deleted file mode 100644
index a94c060..0000000
--- a/components/cloud_devices/cloud_devices_json_consts.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 "components/cloud_devices/cloud_devices_json_consts.h"
-
-namespace cloud_devices {
-
-namespace cdd {
-
-const char kVersion[] = "version";
-const char kVersion10[] = "1.0";
-const char kSectionPrinter[] = "printer";
-
-const char kKeyContentType[] = "content_type";
-const char kKeyDefault[] = "default";
-const char kKeyIsDefault[] = "is_default";
-const char kKeyMax[] = "max";
-const char kKeyType[] = "type";
-const char kKeyOption[] = "option";
-const char kKeyVendorId[] = "vendor_id";
-const char kCustomName[] = "custom_display_name";
-
-const char kMargineBottomMicrons[] = "bottom_microns";
-const char kMargineLeftMicrons[] = "left_microns";
-const char kMargineRightMicrons[] = "right_microns";
-const char kMargineTopMicrons[] = "top_microns";
-
-const char kDpiHorizontal[] = "horizontal_dpi";
-const char kDpiVertical[] = "vertical_dpi";
-
-const char kOptionCollate[] = "collate";
-const char kOptionColor[] = "color";
-const char kOptionContentType[] = "supported_content_type";
-const char kOptionCopies[] = "copies";
-const char kOptionDpi[] = "dpi";
-const char kOptionDuplex[] = "duplex";
-const char kOptionFitToPage[] = "fit_to_page";
-const char kOptionMargins[] = "margins";
-const char kOptionMediaSize[] = "media_size";
-const char kOptionPageOrientation[] = "page_orientation";
-const char kOptionPageRange[] = "page_range";
-const char kOptionReverse[] = "reverse_order";
-
-const char kPageRangeEnd[] = "end";
-const char kPageRangeStart[] = "start";
-
-const char kTypeColorColor[] = "STANDARD_COLOR";
-const char kTypeColorMonochrome[] = "STANDARD_MONOCHROME";
-const char kTypeColorCustomColor[] = "CUSTOM_COLOR";
-const char kTypeColorCustomMonochrome[] = "CUSTOM_MONOCHROME";
-const char kTypeColorAuto[] = "AUTO";
-
-const char kTypeDuplexLongEdge[] = "LONG_EDGE";
-const char kTypeDuplexNoDuplex[] = "NO_DUPLEX";
-const char kTypeDuplexShortEdge[] = "SHORT_EDGE";
-
-const char kTypeFitToPageFillPage[] = "FILL_PAGE";
-const char kTypeFitToPageFitToPage[] = "FIT_TO_PAGE";
-const char kTypeFitToPageGrowToPage[] = "GROW_TO_PAGE";
-const char kTypeFitToPageNoFitting[] = "NO_FITTING";
-const char kTypeFitToPageShrinkToPage[] = "SHRINK_TO_PAGE";
-
-const char kTypeMarginsBorderless[] = "BORDERLESS";
-const char kTypeMarginsCustom[] = "CUSTOM";
-const char kTypeMarginsStandard[] = "STANDARD";
-const char kTypeOrientationAuto[] = "AUTO";
-
-const char kTypeOrientationLandscape[] = "LANDSCAPE";
-const char kTypeOrientationPortrait[] = "PORTRAIT";
-
-} // namespace cdd
-
-} // namespace cloud_devices
diff --git a/components/cloud_devices/cloud_devices_json_consts.h b/components/cloud_devices/cloud_devices_json_consts.h
deleted file mode 100644
index 5862a50..0000000
--- a/components/cloud_devices/cloud_devices_json_consts.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-// Defines strings constants for parsing Cloud Device Description.
-// https://developers.google.com/cloud-print/docs/cdd
-
-#ifndef COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICES_JSON_CONSTANTS_H_
-#define COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICES_JSON_CONSTANTS_H_
-
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace cloud_devices {
-
-namespace cdd {
-
-extern const char kVersion[];
-extern const char kVersion10[];
-extern const char kSectionPrinter[];
-
-extern const char kKeyContentType[];
-extern const char kKeyDefault[];
-extern const char kKeyIsDefault[];
-extern const char kKeyMax[];
-extern const char kKeyType[];
-extern const char kKeyOption[];
-extern const char kKeyVendorId[];
-extern const char kCustomName[];
-
-extern const char kMargineBottomMicrons[];
-extern const char kMargineLeftMicrons[];
-extern const char kMargineRightMicrons[];
-extern const char kMargineTopMicrons[];
-
-extern const char kDpiHorizontal[];
-extern const char kDpiVertical[];
-
-extern const char kOptionCollate[];
-extern const char kOptionColor[];
-extern const char kOptionContentType[];
-extern const char kOptionCopies[];
-extern const char kOptionDpi[];
-extern const char kOptionDuplex[];
-extern const char kOptionFitToPage[];
-extern const char kOptionMargins[];
-extern const char kOptionMediaSize[];
-extern const char kOptionPageOrientation[];
-extern const char kOptionPageRange[];
-extern const char kOptionReverse[];
-
-extern const char kPageRangeEnd[];
-extern const char kPageRangeStart[];
-
-extern const char kTypeColorColor[];
-extern const char kTypeColorMonochrome[];
-extern const char kTypeColorCustomColor[];
-extern const char kTypeColorCustomMonochrome[];
-extern const char kTypeColorAuto[];
-
-extern const char kTypeDuplexLongEdge[];
-extern const char kTypeDuplexNoDuplex[];
-extern const char kTypeDuplexShortEdge[];
-
-extern const char kTypeFitToPageFillPage[];
-extern const char kTypeFitToPageFitToPage[];
-extern const char kTypeFitToPageGrowToPage[];
-extern const char kTypeFitToPageNoFitting[];
-extern const char kTypeFitToPageShrinkToPage[];
-
-extern const char kTypeMarginsBorderless[];
-extern const char kTypeMarginsCustom[];
-extern const char kTypeMarginsStandard[];
-extern const char kTypeOrientationAuto[];
-
-extern const char kTypeOrientationLandscape[];
-extern const char kTypeOrientationPortrait[];
-
-} // namespace cdd
-
-} // namespace cloud_devices
-
-#endif // COMPONENTS_CLOUD_DEVICES_CLOUD_DEVICES_JSON_CONSTANTS_H_
diff --git a/components/cloud_devices/description_items.h b/components/cloud_devices/description_items.h
new file mode 100644
index 0000000..2dd404e
--- /dev/null
+++ b/components/cloud_devices/description_items.h
@@ -0,0 +1,231 @@
+// 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.
+
+#ifndef COMPONENTS_CLOUD_DEVICES_CAPABILITY_INTERFACES_H_
+#define COMPONENTS_CLOUD_DEVICES_CAPABILITY_INTERFACES_H_
+
+// Defines common templates that could be used to create device specific
+// capabilities and print tickets.
+
+#include <vector>
+
+#include "base/logging.h"
+
+#include "components/cloud_devices/cloud_device_description.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace cloud_devices {
+
+// All traits below specify how to serialize and validate capabilities and
+// ticket items.
+// Traits should have following methods:
+// // Returns true if capability semantically valid.
+// static bool IsValid(const Option&);
+//
+// // Returns json path relative to the root of CDD/CJT.
+// static std::string GetItemPath();
+//
+// // Loads ticket item. Returns false if failed.
+// static bool Load(const base::DictionaryValue& dict, ContentType* option);
+//
+// // Saves ticket item.
+// static void Save(ContentType option, base::DictionaryValue* dict);
+
+// Represents a CDD capability that is stored as a JSON list
+// Ex: "<CAPABILITY_NAME>": [ {<VALUE>}, {<VALUE>}, {<VALUE>} ]
+// Option specifies data type for <VALUE>.
+// Traits specifies how <VALUE> is stored in JSON and semantic validation.
+template <class Option, class Traits>
+class ListCapability {
+ public:
+ ListCapability();
+ ~ListCapability();
+
+ bool LoadFrom(const CloudDeviceDescription& description);
+ void SaveTo(CloudDeviceDescription* description) const;
+
+ void Reset() {
+ options_.clear();
+ }
+
+ bool IsValid() const;
+
+ bool empty() const {
+ return options_.empty();
+ }
+
+ size_t size() const {
+ return options_.size();
+ }
+
+ const Option& operator[](size_t i) const {
+ return options_[i];
+ }
+
+ bool Contains(const Option& option) const{
+ return std::find(options_.begin(), options_.end(), option) !=
+ options_.end();
+ }
+
+ void AddOption(const Option& option) {
+ options_.push_back(option);
+ }
+
+ private:
+ typedef std::vector<Option> OptionVector;
+ OptionVector options_;
+
+ DISALLOW_COPY_AND_ASSIGN(ListCapability);
+};
+
+// Represents CDD capability stored as JSON list with default_value value.
+// Ex: "<CAPABILITY_NAME>": { "option": [{ "is_default": true, <VALUE>},
+// {<VALUE>} ]}
+// Option specifies data type for <VALUE>.
+// Traits specifies how <VALUE> is stored in JSON and semantic validation.
+template <class Option, class Traits>
+class SelectionCapability {
+ public:
+ SelectionCapability();
+ ~SelectionCapability();
+
+ bool LoadFrom(const CloudDeviceDescription& description);
+ void SaveTo(CloudDeviceDescription* description) const;
+
+ void Reset() {
+ options_.clear();
+ default_idx_ = -1;
+ }
+
+ bool IsValid() const;
+
+ bool empty() const {
+ return options_.empty();
+ }
+
+ size_t size() const {
+ return options_.size();
+ }
+
+ const Option& operator[](size_t i) const {
+ return options_[i];
+ }
+
+ bool Contains(const Option& option) const{
+ return std::find(options_.begin(), options_.end(), option) !=
+ options_.end();
+ }
+
+ const Option& GetDefault() const {
+ CHECK_GE(default_idx_, 0);
+ return options_[default_idx_];
+ }
+
+ void AddOption(const Option& option) {
+ AddDefaultOption(option, false);
+ }
+
+ void AddDefaultOption(const Option& option, bool is_default) {
+ options_.push_back(option);
+ if (is_default) {
+ DCHECK_EQ(default_idx_, -1);
+ // Point to the last element.
+ default_idx_ = size() - 1;
+ }
+ }
+
+ private:
+ typedef std::vector<Option> OptionVector;
+
+ OptionVector options_;
+ int default_idx_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectionCapability);
+};
+
+// Represents CDD capability that can be true or false.
+// Ex: "<CAPABILITY_NAME>": { "default_value": true }
+// Traits specifies how <VALUE> is stored in JSON and semantic validation.
+template <class Traits>
+class BooleanCapability {
+ public:
+ BooleanCapability();
+ ~BooleanCapability();
+
+ bool LoadFrom(const CloudDeviceDescription& description);
+ void SaveTo(CloudDeviceDescription* description) const;
+
+ void Reset() {
+ default_value_ = false;
+ }
+
+ void set_default_value(bool value) {
+ default_value_ = value;
+ }
+
+ bool default_value() const {
+ return default_value_;
+ }
+
+ private:
+ bool default_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(BooleanCapability);
+};
+
+// Represents CDD capability for which existence is only important.
+// Ex: "<CAPABILITY_NAME>": { }
+// Traits specifies how <VALUE> is stored in JSON and semantic validation.
+template <class Traits>
+class EmptyCapability {
+ public:
+ EmptyCapability() {};
+ ~EmptyCapability() {};
+
+ bool LoadFrom(const CloudDeviceDescription& description);
+ void SaveTo(CloudDeviceDescription* description) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EmptyCapability);
+};
+
+// Represents CJT items.
+// Ex: "<CAPABILITY_NAME>": {<VALUE>}
+// Option specifies data type for <VALUE>.
+// Traits specifies how <VALUE> is stored in JSON and semantic validation.
+template <class Option, class Traits>
+class TicketItem {
+ public:
+ TicketItem();
+ ~TicketItem();
+
+ bool LoadFrom(const CloudDeviceDescription& description);
+ void SaveTo(CloudDeviceDescription* description) const;
+
+ void Reset() {
+ value_ = Option();
+ }
+
+ bool IsValid() const;
+
+ const Option& value() const {
+ return value_;
+ }
+
+ void set_value(const Option& value) {
+ value_ = value;
+ }
+
+ private:
+ Option value_;
+
+ DISALLOW_COPY_AND_ASSIGN(TicketItem);
+};
+
+} // namespace cloud_devices
+
+#endif // COMPONENTS_CLOUD_DEVICES_CAPABILITY_INTERFACES_H_
diff --git a/components/cloud_devices/description_items_inl.h b/components/cloud_devices/description_items_inl.h
new file mode 100644
index 0000000..a3e2df8
--- /dev/null
+++ b/components/cloud_devices/description_items_inl.h
@@ -0,0 +1,211 @@
+// 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.
+
+#ifndef COMPONENTS_CLOUD_DEVICES_DESCRIPTION_DESCRIPTION_ITEMS_INL_H_
+#define COMPONENTS_CLOUD_DEVICES_DESCRIPTION_DESCRIPTION_ITEMS_INL_H_
+
+#include <vector>
+
+#include "components/cloud_devices/description_items.h"
+
+// Implementation of templates defined in header file.
+// This file should be included from CC file with implementation of device
+// specific capabilities.
+
+namespace cloud_devices {
+
+template <class Option, class Traits>
+ListCapability<Option, Traits>::ListCapability() {
+ Reset();
+}
+
+template <class Option, class Traits>
+ListCapability<Option, Traits>::~ListCapability() { }
+
+template <class Option, class Traits>
+bool ListCapability<Option, Traits>::IsValid() const {
+ if (empty())
+ return false; // This type of capabilities can't be empty.
+ for (size_t i = 0; i < options_.size(); ++i) {
+ if (!Traits::IsValid(options_[i]))
+ return false;
+ }
+ return true;
+}
+
+template <class Option, class Traits>
+bool ListCapability<Option, Traits>::LoadFrom(
+ const CloudDeviceDescription& description) {
+ Reset();
+ const base::ListValue* options =
+ description.GetListItem(Traits::GetItemPath());
+ if (!options)
+ return false;
+ for (size_t i = 0; i < options->GetSize(); ++i) {
+ const base::DictionaryValue* option_value = NULL;
+ if (!options->GetDictionary(i, &option_value))
+ return false; // Every entry must be a dictionary.
+ Option option;
+ if (!Traits::Load(*option_value, &option))
+ return false;
+ AddOption(option);
+ }
+ return IsValid();
+}
+
+template <class Option, class Traits>
+void ListCapability<Option, Traits>::SaveTo(
+ CloudDeviceDescription* description) const {
+ DCHECK(IsValid());
+ base::ListValue* options_list =
+ description->CreateListItem(Traits::GetItemPath());
+ for (size_t i = 0; i < options_.size(); ++i) {
+ base::DictionaryValue* option_value = new base::DictionaryValue;
+ options_list->Append(option_value);
+ Traits::Save(options_[i], option_value);
+ }
+}
+
+template <class Option, class Traits>
+SelectionCapability<Option, Traits>::SelectionCapability() {
+ Reset();
+}
+
+template <class Option, class Traits>
+SelectionCapability<Option, Traits>::~SelectionCapability() { }
+
+template <class Option, class Traits>
+bool SelectionCapability<Option, Traits>::IsValid() const {
+ if (empty())
+ return false; // This type of capabilities can't be empty
+ for (size_t i = 0; i < options_.size(); ++i) {
+ if (!Traits::IsValid(options_[i]))
+ return false;
+ }
+ return default_idx_ >= 0 && default_idx_ < static_cast<int>(size());
+}
+
+template <class Option, class Traits>
+bool SelectionCapability<Option, Traits>::LoadFrom(
+ const CloudDeviceDescription& description) {
+ Reset();
+ const base::DictionaryValue* item =
+ description.GetItem(Traits::GetItemPath());
+ if (!item)
+ return false;
+ const base::ListValue* options = NULL;
+ if (!item->GetList(json::kKeyOption, &options))
+ return false;
+ for (size_t i = 0; i < options->GetSize(); ++i) {
+ const base::DictionaryValue* option_value = NULL;
+ if (!options->GetDictionary(i, &option_value))
+ return false; // Every entry must be a dictionary.
+ Option option;
+ if (!Traits::Load(*option_value, &option))
+ return false;
+ bool is_default = false;
+ option_value->GetBoolean(json::kKeyIsDefault, &is_default);
+ if (is_default && default_idx_ >= 0) {
+ return false; // Multiple defaults.
+ }
+ AddDefaultOption(option, is_default);
+ }
+ return IsValid();
+}
+
+template <class Option, class Traits>
+void SelectionCapability<Option, Traits>::SaveTo(
+ CloudDeviceDescription* description) const {
+ DCHECK(IsValid());
+ base::ListValue* options_list = new base::ListValue;
+ description->CreateItem(Traits::GetItemPath())->Set(json::kKeyOption,
+ options_list);
+ for (size_t i = 0; i < options_.size(); ++i) {
+ base::DictionaryValue* option_value = new base::DictionaryValue;
+ options_list->Append(option_value);
+ if (static_cast<int>(i) == default_idx_)
+ option_value->SetBoolean(json::kKeyIsDefault, true);
+ Traits::Save(options_[i], option_value);
+ }
+}
+
+template <class Traits>
+BooleanCapability<Traits>::BooleanCapability() {
+ Reset();
+}
+
+template <class Traits>
+BooleanCapability<Traits>::~BooleanCapability() { }
+
+template <class Traits>
+bool BooleanCapability<Traits>::LoadFrom(
+ const CloudDeviceDescription& description) {
+ Reset();
+ const base::DictionaryValue* dict =
+ description.GetItem(Traits::GetItemPath());
+ if (!dict)
+ return false;
+ default_value_ = Traits::kDefault;
+ dict->GetBoolean(json::kKeyDefault, &default_value_);
+ return true;
+}
+
+template <class Traits>
+void BooleanCapability<Traits>::SaveTo(
+ CloudDeviceDescription* description) const {
+ base::DictionaryValue* dict = description->CreateItem(Traits::GetItemPath());
+ if (default_value_ != Traits::kDefault)
+ dict->SetBoolean(json::kKeyDefault, default_value_);
+}
+
+template <class Traits>
+bool EmptyCapability<Traits>::LoadFrom(
+ const CloudDeviceDescription& description) {
+ return description.GetItem(Traits::GetItemPath()) != NULL;
+}
+
+template <class Traits>
+void EmptyCapability<Traits>::SaveTo(
+ CloudDeviceDescription* description) const {
+ description->CreateItem(Traits::GetItemPath());
+}
+
+template <class Option, class Traits>
+TicketItem<Option, Traits>::TicketItem() {
+ Reset();
+}
+
+template <class Option, class Traits>
+TicketItem<Option, Traits>::~TicketItem() { }
+
+template <class Option, class Traits>
+bool TicketItem<Option, Traits>::IsValid() const {
+ return Traits::IsValid(value());
+}
+
+template <class Option, class Traits>
+bool TicketItem<Option, Traits>::LoadFrom(
+ const CloudDeviceDescription& description) {
+ Reset();
+ const base::DictionaryValue* option_value =
+ description.GetItem(Traits::GetItemPath());
+ if (!option_value)
+ return false;
+ Option option;
+ if (!Traits::Load(*option_value, &option))
+ return false;
+ set_value(option);
+ return IsValid();
+}
+
+template <class Option, class Traits>
+void TicketItem<Option, Traits>::SaveTo(
+ CloudDeviceDescription* description) const {
+ DCHECK(IsValid());
+ Traits::Save(value(), description->CreateItem(Traits::GetItemPath()));
+}
+
+} // namespace cloud_devices
+
+#endif // COMPONENTS_CLOUD_DEVICES_DESCRIPTION_DESCRIPTION_ITEMS_INL_H_
diff --git a/components/cloud_devices/printer_description.cc b/components/cloud_devices/printer_description.cc
new file mode 100644
index 0000000..13f8710
--- /dev/null
+++ b/components/cloud_devices/printer_description.cc
@@ -0,0 +1,729 @@
+// 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 "components/cloud_devices/printer_description.h"
+
+#include <algorithm>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "components/cloud_devices/cloud_device_description_consts.h"
+#include "components/cloud_devices/description_items_inl.h"
+
+namespace cloud_devices {
+
+namespace printer {
+
+namespace {
+
+const int32 kMaxPageNumber = 1000000;
+
+const char kSectionPrinter[] = "printer";
+
+const char kCustomName[] = "custom_display_name";
+const char kKeyContentType[] = "content_type";
+const char kKeyName[] = "name";
+const char kKeyType[] = "type";
+const char kKeyVendorId[] = "vendor_id";
+
+// extern is required to be used in templates.
+extern const char kOptionCollate[] = "collate";
+extern const char kOptionColor[] = "color";
+extern const char kOptionContentType[] = "supported_content_type";
+extern const char kOptionCopies[] = "copies";
+extern const char kOptionDpi[] = "dpi";
+extern const char kOptionDuplex[] = "duplex";
+extern const char kOptionFitToPage[] = "fit_to_page";
+extern const char kOptionMargins[] = "margins";
+extern const char kOptionMediaSize[] = "media_size";
+extern const char kOptionPageOrientation[] = "page_orientation";
+extern const char kOptionPageRange[] = "page_range";
+extern const char kOptionReverse[] = "reverse_order";
+
+const char kMargineBottomMicrons[] = "bottom_microns";
+const char kMargineLeftMicrons[] = "left_microns";
+const char kMargineRightMicrons[] = "right_microns";
+const char kMargineTopMicrons[] = "top_microns";
+
+const char kDpiHorizontal[] = "horizontal_dpi";
+const char kDpiVertical[] = "vertical_dpi";
+
+const char kMediaWidth[] = "width_microns";
+const char kMediaHeight[] = "height_microns";
+const char kMediaIsContinuous[] = "is_continuous_feed";
+
+const char kPageRangeInterval[] = "interval";
+const char kPageRangeEnd[] = "end";
+const char kPageRangeStart[] = "start";
+
+const char kTypeColorColor[] = "STANDARD_COLOR";
+const char kTypeColorMonochrome[] = "STANDARD_MONOCHROME";
+const char kTypeColorCustomColor[] = "CUSTOM_COLOR";
+const char kTypeColorCustomMonochrome[] = "CUSTOM_MONOCHROME";
+const char kTypeColorAuto[] = "AUTO";
+
+const char kTypeDuplexLongEdge[] = "LONG_EDGE";
+const char kTypeDuplexNoDuplex[] = "NO_DUPLEX";
+const char kTypeDuplexShortEdge[] = "SHORT_EDGE";
+
+const char kTypeFitToPageFillPage[] = "FILL_PAGE";
+const char kTypeFitToPageFitToPage[] = "FIT_TO_PAGE";
+const char kTypeFitToPageGrowToPage[] = "GROW_TO_PAGE";
+const char kTypeFitToPageNoFitting[] = "NO_FITTING";
+const char kTypeFitToPageShrinkToPage[] = "SHRINK_TO_PAGE";
+
+const char kTypeMarginsBorderless[] = "BORDERLESS";
+const char kTypeMarginsCustom[] = "CUSTOM";
+const char kTypeMarginsStandard[] = "STANDARD";
+const char kTypeOrientationAuto[] = "AUTO";
+
+const char kTypeOrientationLandscape[] = "LANDSCAPE";
+const char kTypeOrientationPortrait[] = "PORTRAIT";
+
+template <class IdType>
+struct TypePair {
+ IdType id;
+ const char* const json_name;
+ static const TypePair kTypeMap[];
+};
+
+template<>
+const TypePair<ColorType> TypePair<ColorType>::kTypeMap[] = {
+ { STANDARD_COLOR, kTypeColorColor },
+ { STANDARD_MONOCHROME, kTypeColorMonochrome },
+ { CUSTOM_COLOR, kTypeColorCustomColor },
+ { CUSTOM_MONOCHROME, kTypeColorCustomMonochrome },
+ { AUTO_COLOR, kTypeColorAuto },
+};
+
+template<>
+const TypePair<DuplexType>
+ TypePair<DuplexType>::kTypeMap[] = {
+ { NO_DUPLEX, kTypeDuplexNoDuplex },
+ { LONG_EDGE, kTypeDuplexLongEdge },
+ { SHORT_EDGE, kTypeDuplexShortEdge },
+};
+
+template<>
+const TypePair<OrientationType>
+ TypePair<OrientationType>::kTypeMap[] = {
+ { PORTRAIT, kTypeOrientationPortrait },
+ { LANDSCAPE, kTypeOrientationLandscape },
+ { AUTO_ORIENTATION, kTypeOrientationAuto },
+};
+
+template<>
+const TypePair<MarginsType>
+ TypePair<MarginsType>::kTypeMap[] = {
+ { NO_MARGINS, kTypeMarginsBorderless },
+ { STANDARD_MARGINS, kTypeMarginsStandard },
+ { CUSTOM_MARGINS, kTypeMarginsCustom },
+};
+
+template<>
+const TypePair<FitToPageType>
+ TypePair<FitToPageType>::kTypeMap[] = {
+ { NO_FITTING, kTypeFitToPageNoFitting },
+ { FIT_TO_PAGE, kTypeFitToPageFitToPage },
+ { GROW_TO_PAGE, kTypeFitToPageGrowToPage },
+ { SHRINK_TO_PAGE, kTypeFitToPageShrinkToPage },
+ { FILL_PAGE, kTypeFitToPageFillPage },
+};
+
+
+template<>
+const TypePair<MediaType>
+ TypePair<MediaType>::kTypeMap[] = {
+#define MAP_CLOUD_PRINT_MEDIA_TYPE(type) { type, #type }
+ { CUSTOM_MEDIA, "CUSTOM" },
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_3X5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_PERSONAL),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_MONARCH),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_4X6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_A2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_11),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_12),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_5X7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_5X8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_14),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INVOICE),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_4X6_EXT),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_6X9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_C5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_7X9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EXECUTIVE),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_GOVT_LETTER),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_GOVT_LEGAL),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_QUARTO),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FANFOLD_EUR),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER_PLUS),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FOOLSCAP),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEGAL),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_SUPER_A),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_9X11),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_A),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEGAL_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X11),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X13),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X14),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X15),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_11X12),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EDP),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FANFOLD_US),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_11X15),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEDGER),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EUR_EDP),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_B),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_12X19),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_B_PLUS),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_SUPER_B),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_C),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_C),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_D),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_D),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ASME_F),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_WIDE_FORMAT),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_E),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_E),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(NA_F),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ROC_16K),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ROC_8K),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_32K),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_16K),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_JUURO_KU_KAI),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_PA_KAI),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_DAI_PA_KAI),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A5_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4_TAB),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1X3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1X4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_2A0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A0X3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B6C4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B5_EXTRA),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C7C6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C6C5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_DL),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B10),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B9),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B8),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B7),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B6),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B5),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B1),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B0),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_EXEC),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_HAGAKI),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_YOU4),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU3),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_OUFUKU),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_KAHU),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_KAKU2),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_SMALL_PHOTO),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_ITALIAN),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_POSTFIX),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_LARGE_PHOTO),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_FOLIO),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_FOLIO_SP),
+ MAP_CLOUD_PRINT_MEDIA_TYPE(OM_INVITE),
+#undef MAP_CLOUD_PRINT_MEDIA_TYPE
+};
+
+template<class IdType>
+std::string TypeToString(IdType id) {
+ for (size_t i = 0; i < arraysize(TypePair<IdType>::kTypeMap); ++i) {
+ if (id == TypePair<IdType>::kTypeMap[i].id)
+ return TypePair<IdType>::kTypeMap[i].json_name;
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+template<class IdType>
+bool TypeFromString(const std::string& type, IdType* id) {
+ for (size_t i = 0; i < arraysize(TypePair<IdType>::kTypeMap); ++i) {
+ if (type == TypePair<IdType>::kTypeMap[i].json_name) {
+ *id = TypePair<IdType>::kTypeMap[i].id;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+Color::Color() : type(AUTO_COLOR) {}
+
+Color::Color(ColorType type) : type(type) {}
+
+bool Color::operator==(const Color& other) const {
+ return type == other.type && vendor_id == other.vendor_id &&
+ custom_display_name == other.custom_display_name;
+}
+
+bool Color::IsValid() const {
+ if (type != CUSTOM_COLOR && type != CUSTOM_MONOCHROME)
+ return true;
+ return !vendor_id.empty() && !custom_display_name.empty();
+}
+
+Margins::Margins()
+ : type(STANDARD_MARGINS),
+ top_microns(0),
+ right_microns(0),
+ bottom_microns(0),
+ left_microns(0) {
+}
+
+Margins::Margins(MarginsType type,
+ int32 top_microns,
+ int32 right_microns,
+ int32 bottom_microns,
+ int32 left_microns)
+ : type(type),
+ top_microns(top_microns),
+ right_microns(right_microns),
+ bottom_microns(bottom_microns),
+ left_microns(left_microns) {
+}
+
+bool Margins::operator==(const Margins& other) const {
+ return type == other.type &&
+ top_microns == other.top_microns &&
+ right_microns == other.right_microns &&
+ bottom_microns == other.bottom_microns;
+}
+
+Dpi::Dpi() : horizontal(0), vertical(0) {}
+
+Dpi::Dpi(int32 horizontal, int32 vertical)
+ : horizontal(horizontal), vertical(vertical) {}
+
+bool Dpi::operator==(const Dpi& other) const {
+ return horizontal == other.horizontal && vertical == other.vertical;
+}
+
+Media::Media()
+ : type(CUSTOM_MEDIA),
+ width_microns(0),
+ height_microns(0),
+ is_continuous_feed(false) {
+
+}
+
+Media::Media(MediaType type, int32 width_microns, int32 height_microns)
+ : type(type),
+ width_microns(width_microns),
+ height_microns(height_microns),
+ is_continuous_feed(width_microns <= 0 || height_microns <= 0) {
+}
+
+Media::Media(const std::string& custom_display_name, int32 width_microns,
+ int32 height_microns)
+ : type(CUSTOM_MEDIA),
+ width_microns(width_microns),
+ height_microns(height_microns),
+ is_continuous_feed(width_microns <= 0 || height_microns <= 0),
+ custom_display_name(custom_display_name) {
+}
+
+bool Media::IsValid() const {
+ if (is_continuous_feed) {
+ if (width_microns <= 0 && height_microns <= 0)
+ return false;
+ } else {
+ if (width_microns <= 0 || height_microns <= 0)
+ return false;
+ }
+ return true;
+}
+
+bool Media::operator==(const Media& other) const {
+ return type == other.type &&
+ width_microns == other.width_microns &&
+ height_microns == other.height_microns &&
+ is_continuous_feed == other.is_continuous_feed;
+}
+
+Interval::Interval() : start(0), end(0) {}
+
+Interval::Interval(int32 start, int32 end)
+ : start(start), end(end) {}
+
+Interval::Interval(int32 start)
+ : start(start), end(kMaxPageNumber) {}
+
+bool Interval::operator==(const Interval& other) const {
+ return start == other.start && end == other.end;
+}
+
+template<const char* kName>
+class ItemsTraits {
+ public:
+ static std::string GetItemPath() {
+ std::string result = kSectionPrinter;
+ result += '.';
+ result += kName;
+ return result;
+ }
+};
+
+class NoValueValidation {
+ public:
+ template <class Option>
+ static bool IsValid(const Option&) {
+ return true;
+ }
+};
+
+class ContentTypeTraits : public NoValueValidation,
+ public ItemsTraits<kOptionContentType> {
+ public:
+ static bool Load(const base::DictionaryValue& dict, ContentType* option) {
+ return dict.GetString(kKeyContentType, option);
+ }
+
+ static void Save(ContentType option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyContentType, option);
+ }
+};
+
+class ColorTraits : public ItemsTraits<kOptionColor> {
+ public:
+ static bool IsValid(const Color& option) {
+ return option.IsValid();
+ }
+
+ static bool Load(const base::DictionaryValue& dict, Color* option) {
+ std::string type_str;
+ if (!dict.GetString(kKeyType, &type_str))
+ return false;
+ if (!TypeFromString(type_str, &option->type))
+ return false;
+ dict.GetString(kKeyVendorId, &option->vendor_id);
+ dict.GetString(kCustomName, &option->custom_display_name);
+ return true;
+ }
+
+ static void Save(const Color& option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyType, TypeToString(option.type));
+ if (!option.vendor_id.empty())
+ dict->SetString(kKeyVendorId, option.vendor_id);
+ if (!option.custom_display_name.empty())
+ dict->SetString(kCustomName, option.custom_display_name);
+ }
+};
+
+class DuplexTraits : public NoValueValidation,
+ public ItemsTraits<kOptionDuplex> {
+ public:
+ static bool Load(const base::DictionaryValue& dict, DuplexType* option) {
+ std::string type_str;
+ return dict.GetString(kKeyType, &type_str) &&
+ TypeFromString(type_str, option);
+ }
+
+ static void Save(DuplexType option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyType, TypeToString(option));
+ }
+};
+
+class OrientationTraits : public NoValueValidation,
+ public ItemsTraits<kOptionPageOrientation> {
+ public:
+ static bool Load(const base::DictionaryValue& dict, OrientationType* option) {
+ std::string type_str;
+ return dict.GetString(kKeyType, &type_str) &&
+ TypeFromString(type_str, option);
+ }
+
+ static void Save(OrientationType option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyType, TypeToString(option));
+ }
+};
+
+class CopiesTraits : public ItemsTraits<kOptionCopies> {
+ public:
+ static bool IsValid(int32 option) {
+ return option >= 1;
+ }
+
+ static bool Load(const base::DictionaryValue& dict, int32* option) {
+ return dict.GetInteger(kOptionCopies, option);
+ }
+
+ static void Save(int32 option, base::DictionaryValue* dict) {
+ dict->SetInteger(kOptionCopies, option);
+ }
+};
+
+class MarginsTraits : public NoValueValidation,
+ public ItemsTraits<kOptionMargins> {
+ public:
+ static bool Load(const base::DictionaryValue& dict, Margins* option) {
+ std::string type_str;
+ if (!dict.GetString(kKeyType, &type_str))
+ return false;
+ if (!TypeFromString(type_str, &option->type))
+ return false;
+ return
+ dict.GetInteger(kMargineTopMicrons, &option->top_microns) &&
+ dict.GetInteger(kMargineRightMicrons, &option->right_microns) &&
+ dict.GetInteger(kMargineBottomMicrons, &option->bottom_microns) &&
+ dict.GetInteger(kMargineLeftMicrons, &option->left_microns);
+ }
+
+ static void Save(const Margins& option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyType, TypeToString(option.type));
+ dict->SetInteger(kMargineTopMicrons, option.top_microns);
+ dict->SetInteger(kMargineRightMicrons, option.right_microns);
+ dict->SetInteger(kMargineBottomMicrons, option.bottom_microns);
+ dict->SetInteger(kMargineLeftMicrons, option.left_microns);
+ }
+};
+
+class DpiTraits : public ItemsTraits<kOptionDpi> {
+ public:
+ static bool IsValid(const Dpi& option) {
+ return option.horizontal && option.vertical > 0;
+ }
+
+ static bool Load(const base::DictionaryValue& dict, Dpi* option) {
+ if (!dict.GetInteger(kDpiHorizontal, &option->horizontal) ||
+ !dict.GetInteger(kDpiVertical, &option->vertical)) {
+ return false;
+ }
+ return true;
+ }
+
+ static void Save(const Dpi& option, base::DictionaryValue* dict) {
+ dict->SetInteger(kDpiHorizontal, option.horizontal);
+ dict->SetInteger(kDpiVertical, option.vertical);
+ }
+};
+
+class FitToPageTraits : public NoValueValidation,
+ public ItemsTraits<kOptionFitToPage> {
+ public:
+ static bool Load(const base::DictionaryValue& dict, FitToPageType* option) {
+ std::string type_str;
+ return dict.GetString(kKeyType, &type_str) &&
+ TypeFromString(type_str, option);
+ }
+
+ static void Save(FitToPageType option, base::DictionaryValue* dict) {
+ dict->SetString(kKeyType, TypeToString(option));
+ }
+};
+
+class PageRangeTraits : public ItemsTraits<kOptionPageRange> {
+ public:
+ static bool IsValid(const PageRange& option) {
+ for (size_t i = 0; i < option.size(); ++i) {
+ if (option[i].start < 1 || option[i].end < 1) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static bool Load(const base::DictionaryValue& dict, PageRange* option) {
+ const base::ListValue* list = NULL;
+ if (!dict.GetList(kPageRangeInterval, &list))
+ return false;
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ const base::DictionaryValue* interval = NULL;
+ if (!list->GetDictionary(i, &interval))
+ return false;
+ Interval new_interval(1, kMaxPageNumber);
+ interval->GetInteger(kPageRangeStart, &new_interval.start);
+ interval->GetInteger(kPageRangeEnd, &new_interval.end);
+ option->push_back(new_interval);
+ }
+ return true;
+ }
+
+ static void Save(const PageRange& option, base::DictionaryValue* dict) {
+ if (!option.empty()) {
+ base::ListValue* list = new base::ListValue;
+ dict->Set(kPageRangeInterval, list);
+ for (size_t i = 0; i < option.size(); ++i) {
+ base::DictionaryValue* interval = new base::DictionaryValue;
+ list->Append(interval);
+ interval->SetInteger(kPageRangeStart, option[i].start);
+ if (option[i].end < kMaxPageNumber)
+ interval->SetInteger(kPageRangeEnd, option[i].end);
+ }
+ }
+ }
+};
+
+class MediaTraits : public ItemsTraits<kOptionMediaSize> {
+ public:
+ static bool IsValid(const Media& option) {
+ return option.IsValid();
+ }
+
+ static bool Load(const base::DictionaryValue& dict, Media* option) {
+ std::string type_str;
+ if (dict.GetString(kKeyName, &type_str)) {
+ if (!TypeFromString(type_str, &option->type))
+ return false;
+ }
+
+ dict.GetInteger(kMediaWidth, &option->width_microns);
+ dict.GetInteger(kMediaHeight, &option->height_microns);
+ dict.GetBoolean(kMediaIsContinuous, &option->is_continuous_feed);
+ dict.GetString(kCustomName, &option->custom_display_name);
+ return true;
+ }
+
+ static void Save(const Media& option, base::DictionaryValue* dict) {
+ if (option.type != CUSTOM_MEDIA)
+ dict->SetString(kKeyName, TypeToString(option.type));
+ if (!option.custom_display_name.empty())
+ dict->SetString(kCustomName, option.custom_display_name);
+ if (option.width_microns > 0)
+ dict->SetInteger(kMediaWidth, option.width_microns);
+ if (option.height_microns > 0)
+ dict->SetInteger(kMediaHeight, option.height_microns);
+ if (option.is_continuous_feed)
+ dict->SetBoolean(kMediaIsContinuous, true);
+ }
+};
+
+class CollateTraits : public NoValueValidation,
+ public ItemsTraits<kOptionCollate> {
+ public:
+ static const bool kDefault = true;
+
+ static bool Load(const base::DictionaryValue& dict, bool* option) {
+ return dict.GetBoolean(kOptionCollate, option);
+ }
+
+ static void Save(bool option, base::DictionaryValue* dict) {
+ dict->SetBoolean(kOptionCollate, option);
+ }
+};
+
+class ReverseTraits : public NoValueValidation,
+ public ItemsTraits<kOptionReverse> {
+ public:
+ static const bool kDefault = false;
+
+ static bool Load(const base::DictionaryValue& dict, bool* option) {
+ return dict.GetBoolean(kOptionReverse, option);
+ }
+
+ static void Save(bool option, base::DictionaryValue* dict) {
+ dict->SetBoolean(kOptionReverse, option);
+ }
+};
+
+} // namespace printer
+
+using namespace printer;
+
+template class ListCapability<ContentType, ContentTypeTraits>;
+template class SelectionCapability<Color, ColorTraits>;
+template class SelectionCapability<DuplexType, DuplexTraits>;
+template class SelectionCapability<OrientationType, OrientationTraits>;
+template class SelectionCapability<Margins, MarginsTraits>;
+template class SelectionCapability<Dpi, DpiTraits>;
+template class SelectionCapability<FitToPageType, FitToPageTraits>;
+template class SelectionCapability<Media, MediaTraits>;
+template class EmptyCapability<class CopiesTraits>;
+template class EmptyCapability<class PageRangeTraits>;
+template class BooleanCapability<class CollateTraits>;
+template class BooleanCapability<class ReverseTraits>;
+
+template class TicketItem<Color, ColorTraits>;
+template class TicketItem<DuplexType, DuplexTraits>;
+template class TicketItem<OrientationType, OrientationTraits>;
+template class TicketItem<Margins, MarginsTraits>;
+template class TicketItem<Dpi, DpiTraits>;
+template class TicketItem<FitToPageType, FitToPageTraits>;
+template class TicketItem<Media, MediaTraits>;
+template class TicketItem<int32, CopiesTraits>;
+template class TicketItem<PageRange, PageRangeTraits>;
+template class TicketItem<bool, CollateTraits>;
+template class TicketItem<bool, ReverseTraits>;
+
+} // namespace cloud_devices
diff --git a/components/cloud_devices/printer_description.h b/components/cloud_devices/printer_description.h
new file mode 100644
index 0000000..cc9b654
--- /dev/null
+++ b/components/cloud_devices/printer_description.h
@@ -0,0 +1,362 @@
+// 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.
+
+#ifndef COMPONENTS_CLOUD_DEVICES_CLOUD_PRINTER_DESCRIPTION_H_
+#define COMPONENTS_CLOUD_DEVICES_CLOUD_PRINTER_DESCRIPTION_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "components/cloud_devices/description_items.h"
+
+// Defines printer options, CDD and CJT items.
+// https://developers.google.com/cloud-print/docs/cdd
+
+namespace cloud_devices {
+
+namespace printer {
+
+typedef std::string ContentType;
+
+enum ColorType {
+ STANDARD_COLOR,
+ STANDARD_MONOCHROME,
+ CUSTOM_COLOR,
+ CUSTOM_MONOCHROME,
+ AUTO_COLOR,
+};
+
+struct Color {
+ Color();
+ explicit Color(ColorType type);
+
+ bool IsValid() const;
+ bool operator==(const Color& other) const;
+ bool operator!=(const Color& other) const {
+ return !(*this == other);
+ }
+
+ ColorType type;
+ std::string vendor_id;
+ std::string custom_display_name;
+};
+
+enum DuplexType {
+ NO_DUPLEX,
+ LONG_EDGE,
+ SHORT_EDGE,
+};
+
+enum OrientationType {
+ PORTRAIT,
+ LANDSCAPE,
+ AUTO_ORIENTATION,
+};
+
+enum MarginsType {
+ NO_MARGINS,
+ STANDARD_MARGINS,
+ CUSTOM_MARGINS,
+};
+
+struct Margins {
+ Margins();
+ Margins(MarginsType type,
+ int32 top_microns,
+ int32 right_microns,
+ int32 bottom_microns,
+ int32 left_microns);
+
+ bool operator==(const Margins& other) const;
+ bool operator!=(const Margins& other) const {
+ return !(*this == other);
+ }
+
+ MarginsType type;
+ int32 top_microns;
+ int32 right_microns;
+ int32 bottom_microns;
+ int32 left_microns;
+};
+
+struct Dpi {
+ Dpi();
+ Dpi(int32 horizontal, int32 vertical);
+
+ bool operator==(const Dpi& other) const;
+ bool operator!=(const Dpi& other) const {
+ return !(*this == other);
+ }
+
+ int32 horizontal;
+ int32 vertical;
+};
+
+enum FitToPageType {
+ NO_FITTING,
+ FIT_TO_PAGE,
+ GROW_TO_PAGE,
+ SHRINK_TO_PAGE,
+ FILL_PAGE,
+};
+
+enum MediaType {
+ CUSTOM_MEDIA,
+
+ // North American standard sheet media names.
+ NA_INDEX_3X5,
+ NA_PERSONAL,
+ NA_MONARCH,
+ NA_NUMBER_9,
+ NA_INDEX_4X6,
+ NA_NUMBER_10,
+ NA_A2,
+ NA_NUMBER_11,
+ NA_NUMBER_12,
+ NA_5X7,
+ NA_INDEX_5X8,
+ NA_NUMBER_14,
+ NA_INVOICE,
+ NA_INDEX_4X6_EXT,
+ NA_6X9,
+ NA_C5,
+ NA_7X9,
+ NA_EXECUTIVE,
+ NA_GOVT_LETTER,
+ NA_GOVT_LEGAL,
+ NA_QUARTO,
+ NA_LETTER,
+ NA_FANFOLD_EUR,
+ NA_LETTER_PLUS,
+ NA_FOOLSCAP,
+ NA_LEGAL,
+ NA_SUPER_A,
+ NA_9X11,
+ NA_ARCH_A,
+ NA_LETTER_EXTRA,
+ NA_LEGAL_EXTRA,
+ NA_10X11,
+ NA_10X13,
+ NA_10X14,
+ NA_10X15,
+ NA_11X12,
+ NA_EDP,
+ NA_FANFOLD_US,
+ NA_11X15,
+ NA_LEDGER,
+ NA_EUR_EDP,
+ NA_ARCH_B,
+ NA_12X19,
+ NA_B_PLUS,
+ NA_SUPER_B,
+ NA_C,
+ NA_ARCH_C,
+ NA_D,
+ NA_ARCH_D,
+ NA_ASME_F,
+ NA_WIDE_FORMAT,
+ NA_E,
+ NA_ARCH_E,
+ NA_F,
+
+ // Chinese standard sheet media size names.
+ ROC_16K,
+ ROC_8K,
+ PRC_32K,
+ PRC_1,
+ PRC_2,
+ PRC_4,
+ PRC_5,
+ PRC_8,
+ PRC_6,
+ PRC_3,
+ PRC_16K,
+ PRC_7,
+ OM_JUURO_KU_KAI,
+ OM_PA_KAI,
+ OM_DAI_PA_KAI,
+ PRC_10,
+
+ // ISO standard sheet media size names.
+ ISO_A10,
+ ISO_A9,
+ ISO_A8,
+ ISO_A7,
+ ISO_A6,
+ ISO_A5,
+ ISO_A5_EXTRA,
+ ISO_A4,
+ ISO_A4_TAB,
+ ISO_A4_EXTRA,
+ ISO_A3,
+ ISO_A4X3,
+ ISO_A4X4,
+ ISO_A4X5,
+ ISO_A4X6,
+ ISO_A4X7,
+ ISO_A4X8,
+ ISO_A4X9,
+ ISO_A3_EXTRA,
+ ISO_A2,
+ ISO_A3X3,
+ ISO_A3X4,
+ ISO_A3X5,
+ ISO_A3X6,
+ ISO_A3X7,
+ ISO_A1,
+ ISO_A2X3,
+ ISO_A2X4,
+ ISO_A2X5,
+ ISO_A0,
+ ISO_A1X3,
+ ISO_A1X4,
+ ISO_2A0,
+ ISO_A0X3,
+ ISO_B10,
+ ISO_B9,
+ ISO_B8,
+ ISO_B7,
+ ISO_B6,
+ ISO_B6C4,
+ ISO_B5,
+ ISO_B5_EXTRA,
+ ISO_B4,
+ ISO_B3,
+ ISO_B2,
+ ISO_B1,
+ ISO_B0,
+ ISO_C10,
+ ISO_C9,
+ ISO_C8,
+ ISO_C7,
+ ISO_C7C6,
+ ISO_C6,
+ ISO_C6C5,
+ ISO_C5,
+ ISO_C4,
+ ISO_C3,
+ ISO_C2,
+ ISO_C1,
+ ISO_C0,
+ ISO_DL,
+ ISO_RA2,
+ ISO_SRA2,
+ ISO_RA1,
+ ISO_SRA1,
+ ISO_RA0,
+ ISO_SRA0,
+
+ // Japanese standard sheet media size names.
+ JIS_B10,
+ JIS_B9,
+ JIS_B8,
+ JIS_B7,
+ JIS_B6,
+ JIS_B5,
+ JIS_B4,
+ JIS_B3,
+ JIS_B2,
+ JIS_B1,
+ JIS_B0,
+ JIS_EXEC,
+ JPN_CHOU4,
+ JPN_HAGAKI,
+ JPN_YOU4,
+ JPN_CHOU2,
+ JPN_CHOU3,
+ JPN_OUFUKU,
+ JPN_KAHU,
+ JPN_KAKU2,
+
+ // Other metric standard sheet media size names.
+ OM_SMALL_PHOTO,
+ OM_ITALIAN,
+ OM_POSTFIX,
+ OM_LARGE_PHOTO,
+ OM_FOLIO,
+ OM_FOLIO_SP,
+ OM_INVITE,
+};
+
+struct Media {
+ Media();
+
+ Media(MediaType type, int32 width_microns, int32 height_microns);
+
+ Media(const std::string& custom_display_name,
+ int32 width_microns, int32 height_microns);
+
+ bool IsValid() const;
+ bool operator==(const Media& other) const;
+ bool operator!=(const Media& other) const {
+ return !(*this == other);
+ }
+
+ MediaType type;
+ int32 width_microns;
+ int32 height_microns;
+ bool is_continuous_feed;
+ std::string custom_display_name;
+};
+
+struct Interval {
+ Interval();
+ Interval(int32 start, int32 end);
+ Interval(int32 start);
+
+ bool operator==(const Interval& other) const;
+ bool operator!=(const Interval& other) const {
+ return !(*this == other);
+ }
+
+ int32 start;
+ int32 end;
+};
+
+typedef std::vector<Interval> PageRange;
+
+class ContentTypeTraits;
+class ColorTraits;
+class DuplexTraits;
+class OrientationTraits;
+class MarginsTraits;
+class DpiTraits;
+class FitToPageTraits;
+class MediaTraits;
+class CopiesTraits;
+class PageRangeTraits;
+class CollateTraits;
+class ReverseTraits;
+
+typedef ListCapability<ContentType, ContentTypeTraits> ContentTypesCapability;
+typedef SelectionCapability<Color, ColorTraits> ColorCapability;
+typedef SelectionCapability<DuplexType, DuplexTraits> DuplexCapability;
+typedef SelectionCapability<OrientationType,
+ OrientationTraits> OrientationCapability;
+typedef SelectionCapability<Margins, MarginsTraits> MarginsCapability;
+typedef SelectionCapability<Dpi, DpiTraits> DpiCapability;
+typedef SelectionCapability<FitToPageType, FitToPageTraits> FitToPageCapability;
+typedef SelectionCapability<Media, MediaTraits> MediaCapability;
+typedef EmptyCapability<class CopiesTraits> CopiesCapability;
+typedef EmptyCapability<class PageRangeTraits> PageRangeCapability;
+typedef BooleanCapability<class CollateTraits> CollateCapability;
+typedef BooleanCapability<class ReverseTraits> ReverseCapability;
+
+typedef TicketItem<Color, ColorTraits> ColorTicketItem;
+typedef TicketItem<DuplexType, DuplexTraits> DuplexTicketItem;
+typedef TicketItem<OrientationType, OrientationTraits> OrientationTicketItem;
+typedef TicketItem<Margins, MarginsTraits> MarginsTicketItem;
+typedef TicketItem<Dpi, DpiTraits> DpiTicketItem;
+typedef TicketItem<FitToPageType, FitToPageTraits> FitToPageTicketItem;
+typedef TicketItem<Media, MediaTraits> MediaTicketItem;
+typedef TicketItem<int32, CopiesTraits> CopiesTicketItem;
+typedef TicketItem<PageRange, PageRangeTraits> PageRangeTicketItem;
+typedef TicketItem<bool, CollateTraits> CollateTicketItem;
+typedef TicketItem<bool, ReverseTraits> ReverseTicketItem;
+
+} // namespace printer
+
+} // namespace cloud_devices
+
+#endif // COMPONENTS_CLOUD_DEVICES_CLOUD_PRINTER_DESCRIPTION_H_
diff --git a/components/cloud_devices/printer_description_unittest.cc b/components/cloud_devices/printer_description_unittest.cc
new file mode 100644
index 0000000..d6a68f0
--- /dev/null
+++ b/components/cloud_devices/printer_description_unittest.cc
@@ -0,0 +1,581 @@
+// 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 "components/cloud_devices/printer_description.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cloud_devices {
+
+namespace printer {
+
+// Replaces ' with " to allow readable json constants in tests.
+// Makes sure that same json value represented by same strings to simplify
+// comparison.
+std::string NormalizeJson(const std::string& json) {
+ std::string result = json;
+ base::ReplaceChars(result, "'", "\"", &result);
+ scoped_ptr<base::Value> value(base::JSONReader::Read(result));
+ DCHECK(value);
+ base::JSONWriter::Write(value.get(), &result);
+ return result;
+}
+
+const char kCdd[] =
+"{"
+" 'version': '1.0',"
+" 'printer': {"
+" 'supported_content_type': [ {"
+" 'content_type': 'image/pwg-raster'"
+" }, {"
+" 'content_type': 'image/jpeg'"
+" } ],"
+" 'color': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'type': 'STANDARD_COLOR'"
+" }, {"
+" 'type': 'STANDARD_MONOCHROME'"
+" }, {"
+" 'type': 'CUSTOM_MONOCHROME',"
+" 'vendor_id': '123',"
+" 'custom_display_name': 'monochrome'"
+" } ]"
+" },"
+" 'duplex': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'type': 'LONG_EDGE'"
+" }, {"
+" 'type': 'SHORT_EDGE'"
+" }, {"
+" 'type': 'NO_DUPLEX'"
+" } ]"
+" },"
+" 'page_orientation': {"
+" 'option': [ {"
+" 'type': 'PORTRAIT'"
+" }, {"
+" 'type': 'LANDSCAPE'"
+" }, {"
+" 'is_default': true,"
+" 'type': 'AUTO'"
+" } ]"
+" },"
+" 'copies': {"
+" },"
+" 'margins': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'type': 'BORDERLESS',"
+" 'top_microns': 0,"
+" 'right_microns': 0,"
+" 'bottom_microns': 0,"
+" 'left_microns': 0"
+" }, {"
+" 'type': 'STANDARD',"
+" 'top_microns': 100,"
+" 'right_microns': 200,"
+" 'bottom_microns': 300,"
+" 'left_microns': 400"
+" }, {"
+" 'type': 'CUSTOM',"
+" 'top_microns': 1,"
+" 'right_microns': 2,"
+" 'bottom_microns': 3,"
+" 'left_microns': 4"
+" } ]"
+" },"
+" 'dpi': {"
+" 'option': [ {"
+" 'horizontal_dpi': 150,"
+" 'vertical_dpi': 250"
+" }, {"
+" 'is_default': true,"
+" 'horizontal_dpi': 600,"
+" 'vertical_dpi': 1600"
+" } ]"
+" },"
+" 'fit_to_page': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'type': 'NO_FITTING'"
+" }, {"
+" 'type': 'FIT_TO_PAGE'"
+" }, {"
+" 'type': 'GROW_TO_PAGE'"
+" }, {"
+" 'type': 'SHRINK_TO_PAGE'"
+" }, {"
+" 'type': 'FILL_PAGE'"
+" } ]"
+" },"
+" 'page_range': {"
+" },"
+" 'media_size': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'name': 'NA_LETTER',"
+" 'width_microns': 2222,"
+" 'height_microns': 3333"
+" }, {"
+" 'name': 'ISO_A6',"
+" 'width_microns': 4444,"
+" 'height_microns': 5555"
+" }, {"
+" 'name': 'JPN_YOU4',"
+" 'width_microns': 6666,"
+" 'height_microns': 7777"
+" }, {"
+" 'width_microns': 1111,"
+" 'is_continuous_feed': true,"
+" 'custom_display_name': 'FEED'"
+" } ]"
+" },"
+" 'collate': {"
+" 'default': false"
+" },"
+" 'reverse_order': {"
+" 'default': true"
+" }"
+" }"
+"}";
+
+
+const char kDefaultCdd[] =
+"{"
+" 'version': '1.0'"
+"}";
+
+const char kBadVersionCdd[] =
+"{"
+" 'version': '1.1',"
+" 'printer': {"
+" }"
+"}";
+
+const char kNoDefaultCdd[] =
+"{"
+" 'version': '1.0',"
+" 'printer': {"
+" 'color': {"
+" 'option': [ {"
+" 'type': 'STANDARD_COLOR'"
+" }, {"
+" 'type': 'STANDARD_MONOCHROME'"
+" } ]"
+" }"
+" }"
+"}";
+
+const char kMultyDefaultCdd[] =
+"{"
+" 'version': '1.0',"
+" 'printer': {"
+" 'color': {"
+" 'option': [ {"
+" 'is_default': true,"
+" 'type': 'STANDARD_COLOR'"
+" }, {"
+" 'is_default': true,"
+" 'type': 'STANDARD_MONOCHROME'"
+" } ]"
+" }"
+" }"
+"}";
+
+const char kCjt[] =
+"{"
+" 'version': '1.0',"
+" 'printer': {"
+" 'color': {"
+" 'type': 'STANDARD_MONOCHROME'"
+" },"
+" 'duplex': {"
+" 'type': 'NO_DUPLEX'"
+" },"
+" 'page_orientation': {"
+" 'type': 'LANDSCAPE'"
+" },"
+" 'copies': {"
+" 'copies': 123"
+" },"
+" 'margins': {"
+" 'type': 'CUSTOM',"
+" 'top_microns': 7,"
+" 'right_microns': 6,"
+" 'bottom_microns': 3,"
+" 'left_microns': 1"
+" },"
+" 'dpi': {"
+" 'horizontal_dpi': 562,"
+" 'vertical_dpi': 125"
+" },"
+" 'fit_to_page': {"
+" 'type': 'SHRINK_TO_PAGE'"
+" },"
+" 'page_range': {"
+" 'interval': [ {"
+" 'start': 1,"
+" 'end': 99"
+" }, {"
+" 'start': 150"
+" } ]"
+" },"
+" 'media_size': {"
+" 'name': 'ISO_C7C6',"
+" 'width_microns': 4261,"
+" 'height_microns': 334"
+" },"
+" 'collate': {"
+" 'collate': false"
+" },"
+" 'reverse_order': {"
+" 'reverse_order': true"
+" }"
+" }"
+"}";
+
+const char kDefaultCjt[] =
+"{"
+" 'version': '1.0'"
+"}";
+
+const char kBadVersionCjt[] =
+"{"
+" 'version': '1.1',"
+" 'printer': {"
+" }"
+"}";
+
+TEST(PrinterDescriptionTest, CddInit) {
+ CloudDeviceDescription description;
+ EXPECT_EQ(NormalizeJson(kDefaultCdd), NormalizeJson(description.ToString()));
+
+ ContentTypesCapability content_types;
+ ColorCapability color;
+ DuplexCapability duplex;
+ OrientationCapability orientation;
+ MarginsCapability margins;
+ DpiCapability dpi;
+ FitToPageCapability fit_to_page;
+ MediaCapability media;
+ CopiesCapability copies;
+ PageRangeCapability page_range;
+ CollateCapability collate;
+ ReverseCapability reverse;
+
+ EXPECT_FALSE(content_types.LoadFrom(description));
+ EXPECT_FALSE(color.LoadFrom(description));
+ EXPECT_FALSE(duplex.LoadFrom(description));
+ EXPECT_FALSE(orientation.LoadFrom(description));
+ EXPECT_FALSE(copies.LoadFrom(description));
+ EXPECT_FALSE(margins.LoadFrom(description));
+ EXPECT_FALSE(dpi.LoadFrom(description));
+ EXPECT_FALSE(fit_to_page.LoadFrom(description));
+ EXPECT_FALSE(page_range.LoadFrom(description));
+ EXPECT_FALSE(media.LoadFrom(description));
+ EXPECT_FALSE(collate.LoadFrom(description));
+ EXPECT_FALSE(reverse.LoadFrom(description));
+ EXPECT_FALSE(media.LoadFrom(description));
+}
+
+TEST(PrinterDescriptionTest, CddInvalid) {
+ CloudDeviceDescription description;
+ ColorCapability color;
+
+ EXPECT_FALSE(description.InitFromString(NormalizeJson(kBadVersionCdd)));
+
+ EXPECT_TRUE(description.InitFromString(NormalizeJson(kNoDefaultCdd)));
+ EXPECT_FALSE(color.LoadFrom(description));
+
+ EXPECT_TRUE(description.InitFromString(NormalizeJson(kMultyDefaultCdd)));
+ EXPECT_FALSE(color.LoadFrom(description));
+}
+
+TEST(PrinterDescriptionTest, CddSetAll) {
+ CloudDeviceDescription description;
+
+ ContentTypesCapability content_types;
+ ColorCapability color;
+ DuplexCapability duplex;
+ OrientationCapability orientation;
+ MarginsCapability margins;
+ DpiCapability dpi;
+ FitToPageCapability fit_to_page;
+ MediaCapability media;
+ CopiesCapability copies;
+ PageRangeCapability page_range;
+ CollateCapability collate;
+ ReverseCapability reverse;
+
+ content_types.AddOption("image/pwg-raster");
+ content_types.AddOption("image/jpeg");
+
+ color.AddDefaultOption(Color(STANDARD_COLOR), true);
+ color.AddOption(Color(STANDARD_MONOCHROME));
+ Color custom(CUSTOM_MONOCHROME);
+ custom.vendor_id = "123";
+ custom.custom_display_name = "monochrome";
+ color.AddOption(custom);
+
+ duplex.AddDefaultOption(LONG_EDGE, true);
+ duplex.AddOption(SHORT_EDGE);
+ duplex.AddOption(NO_DUPLEX);
+
+ orientation.AddOption(PORTRAIT);
+ orientation.AddOption(LANDSCAPE);
+ orientation.AddDefaultOption(AUTO_ORIENTATION, true);
+
+ margins.AddDefaultOption(Margins(NO_MARGINS, 0, 0, 0, 0), true);
+ margins.AddOption(Margins(STANDARD_MARGINS, 100, 200, 300, 400));
+ margins.AddOption(Margins(CUSTOM_MARGINS, 1, 2, 3, 4));
+
+ dpi.AddOption(Dpi(150, 250));
+ dpi.AddDefaultOption(Dpi(600, 1600), true);
+
+ fit_to_page.AddDefaultOption(NO_FITTING, true);
+ fit_to_page.AddOption(FIT_TO_PAGE);
+ fit_to_page.AddOption(GROW_TO_PAGE);
+ fit_to_page.AddOption(SHRINK_TO_PAGE);
+ fit_to_page.AddOption(FILL_PAGE);
+
+ media.AddDefaultOption(Media(NA_LETTER, 2222, 3333), true);
+ media.AddOption(Media(ISO_A6, 4444, 5555));
+ media.AddOption(Media(JPN_YOU4, 6666, 7777));
+ media.AddOption(Media("FEED", 1111, 0));
+
+ collate.set_default_value(false);
+ reverse.set_default_value(true);
+
+ content_types.SaveTo(&description);
+ color.SaveTo(&description);
+ duplex.SaveTo(&description);
+ orientation.SaveTo(&description);
+ copies.SaveTo(&description);
+ margins.SaveTo(&description);
+ dpi.SaveTo(&description);
+ fit_to_page.SaveTo(&description);
+ page_range.SaveTo(&description);
+ media.SaveTo(&description);
+ collate.SaveTo(&description);
+ reverse.SaveTo(&description);
+
+ EXPECT_EQ(NormalizeJson(kCdd), NormalizeJson(description.ToString()));
+}
+
+TEST(PrinterDescriptionTest, CddGetAll) {
+ CloudDeviceDescription description;
+ ASSERT_TRUE(description.InitFromString(NormalizeJson(kCdd)));
+
+ ContentTypesCapability content_types;
+ ColorCapability color;
+ DuplexCapability duplex;
+ OrientationCapability orientation;
+ MarginsCapability margins;
+ DpiCapability dpi;
+ FitToPageCapability fit_to_page;
+ MediaCapability media;
+ CopiesCapability copies;
+ PageRangeCapability page_range;
+ CollateCapability collate;
+ ReverseCapability reverse;
+
+ EXPECT_TRUE(content_types.LoadFrom(description));
+ EXPECT_TRUE(color.LoadFrom(description));
+ EXPECT_TRUE(duplex.LoadFrom(description));
+ EXPECT_TRUE(orientation.LoadFrom(description));
+ EXPECT_TRUE(copies.LoadFrom(description));
+ EXPECT_TRUE(margins.LoadFrom(description));
+ EXPECT_TRUE(dpi.LoadFrom(description));
+ EXPECT_TRUE(fit_to_page.LoadFrom(description));
+ EXPECT_TRUE(page_range.LoadFrom(description));
+ EXPECT_TRUE(media.LoadFrom(description));
+ EXPECT_TRUE(collate.LoadFrom(description));
+ EXPECT_TRUE(reverse.LoadFrom(description));
+ EXPECT_TRUE(media.LoadFrom(description));
+
+ EXPECT_TRUE(content_types.Contains("image/pwg-raster"));
+ EXPECT_TRUE(content_types.Contains("image/jpeg"));
+
+ EXPECT_TRUE(color.Contains(Color(STANDARD_COLOR)));
+ EXPECT_TRUE(color.Contains(Color(STANDARD_MONOCHROME)));
+ Color custom(CUSTOM_MONOCHROME);
+ custom.vendor_id = "123";
+ custom.custom_display_name = "monochrome";
+ EXPECT_TRUE(color.Contains(custom));
+ EXPECT_EQ(Color(STANDARD_COLOR), color.GetDefault());
+
+ EXPECT_TRUE(duplex.Contains(LONG_EDGE));
+ EXPECT_TRUE(duplex.Contains(SHORT_EDGE));
+ EXPECT_TRUE(duplex.Contains(NO_DUPLEX));
+ EXPECT_EQ(LONG_EDGE, duplex.GetDefault());
+
+ EXPECT_TRUE(orientation.Contains(PORTRAIT));
+ EXPECT_TRUE(orientation.Contains(LANDSCAPE));
+ EXPECT_TRUE(orientation.Contains(AUTO_ORIENTATION));
+ EXPECT_EQ(AUTO_ORIENTATION, orientation.GetDefault());
+
+ EXPECT_TRUE(margins.Contains(Margins(NO_MARGINS, 0, 0, 0, 0)));
+ EXPECT_TRUE(margins.Contains(Margins(STANDARD_MARGINS, 100, 200, 300, 400)));
+ EXPECT_TRUE(margins.Contains(Margins(CUSTOM_MARGINS, 1, 2, 3, 4)));
+ EXPECT_EQ(Margins(NO_MARGINS, 0, 0, 0, 0), margins.GetDefault());
+
+ EXPECT_TRUE(dpi.Contains(Dpi(150, 250)));
+ EXPECT_TRUE(dpi.Contains(Dpi(600, 1600)));
+ EXPECT_EQ(Dpi(600, 1600), dpi.GetDefault());
+
+ EXPECT_TRUE(fit_to_page.Contains(NO_FITTING));
+ EXPECT_TRUE(fit_to_page.Contains(FIT_TO_PAGE));
+ EXPECT_TRUE(fit_to_page.Contains(GROW_TO_PAGE));
+ EXPECT_TRUE(fit_to_page.Contains(SHRINK_TO_PAGE));
+ EXPECT_TRUE(fit_to_page.Contains(FILL_PAGE));
+ EXPECT_EQ(NO_FITTING, fit_to_page.GetDefault());
+
+ EXPECT_TRUE(media.Contains(Media(NA_LETTER, 2222, 3333)));
+ EXPECT_TRUE(media.Contains(Media(ISO_A6, 4444, 5555)));
+ EXPECT_TRUE(media.Contains(Media(JPN_YOU4, 6666, 7777)));
+ EXPECT_TRUE(media.Contains(Media("FEED", 1111, 0)));
+ EXPECT_EQ(Media(NA_LETTER, 2222, 3333), media.GetDefault());
+
+ EXPECT_FALSE(collate.default_value());
+ EXPECT_TRUE(reverse.default_value());
+
+ EXPECT_EQ(NormalizeJson(kCdd), NormalizeJson(description.ToString()));
+}
+
+TEST(PrinterDescriptionTest, CjtInit) {
+ CloudDeviceDescription description;
+ EXPECT_EQ(NormalizeJson(kDefaultCjt), NormalizeJson(description.ToString()));
+
+ ColorTicketItem color;
+ DuplexTicketItem duplex;
+ OrientationTicketItem orientation;
+ MarginsTicketItem margins;
+ DpiTicketItem dpi;
+ FitToPageTicketItem fit_to_page;
+ MediaTicketItem media;
+ CopiesTicketItem copies;
+ PageRangeTicketItem page_range;
+ CollateTicketItem collate;
+ ReverseTicketItem reverse;
+
+ EXPECT_FALSE(color.LoadFrom(description));
+ EXPECT_FALSE(duplex.LoadFrom(description));
+ EXPECT_FALSE(orientation.LoadFrom(description));
+ EXPECT_FALSE(copies.LoadFrom(description));
+ EXPECT_FALSE(margins.LoadFrom(description));
+ EXPECT_FALSE(dpi.LoadFrom(description));
+ EXPECT_FALSE(fit_to_page.LoadFrom(description));
+ EXPECT_FALSE(page_range.LoadFrom(description));
+ EXPECT_FALSE(media.LoadFrom(description));
+ EXPECT_FALSE(collate.LoadFrom(description));
+ EXPECT_FALSE(reverse.LoadFrom(description));
+ EXPECT_FALSE(media.LoadFrom(description));
+}
+
+TEST(PrinterDescriptionTest, CjtInvalid) {
+ CloudDeviceDescription ticket;
+ EXPECT_FALSE(ticket.InitFromString(NormalizeJson(kBadVersionCjt)));
+}
+
+TEST(PrinterDescriptionTest, GjtSetAll) {
+ CloudDeviceDescription description;
+
+ ColorTicketItem color;
+ DuplexTicketItem duplex;
+ OrientationTicketItem orientation;
+ MarginsTicketItem margins;
+ DpiTicketItem dpi;
+ FitToPageTicketItem fit_to_page;
+ MediaTicketItem media;
+ CopiesTicketItem copies;
+ PageRangeTicketItem page_range;
+ CollateTicketItem collate;
+ ReverseTicketItem reverse;
+
+ color.set_value(Color(STANDARD_MONOCHROME));
+ duplex.set_value(NO_DUPLEX);
+ orientation.set_value(LANDSCAPE);
+ copies.set_value(123);
+ margins.set_value(Margins(CUSTOM_MARGINS, 7, 6, 3, 1));
+ dpi.set_value(Dpi(562, 125));
+ fit_to_page.set_value(SHRINK_TO_PAGE);
+ PageRange page_ranges;
+ page_ranges.push_back(Interval(1, 99));
+ page_ranges.push_back(Interval(150));
+ page_range.set_value(page_ranges);
+ media.set_value(Media(ISO_C7C6, 4261, 334));
+ collate.set_value(false);
+ reverse.set_value(true);
+
+ color.SaveTo(&description);
+ duplex.SaveTo(&description);
+ orientation.SaveTo(&description);
+ copies.SaveTo(&description);
+ margins.SaveTo(&description);
+ dpi.SaveTo(&description);
+ fit_to_page.SaveTo(&description);
+ page_range.SaveTo(&description);
+ media.SaveTo(&description);
+ collate.SaveTo(&description);
+ reverse.SaveTo(&description);
+
+ EXPECT_EQ(NormalizeJson(kCjt), NormalizeJson(description.ToString()));
+}
+
+TEST(PrinterDescriptionTest, CjtGetAll) {
+ CloudDeviceDescription description;
+ ASSERT_TRUE(description.InitFromString(NormalizeJson(kCjt)));
+
+ ColorTicketItem color;
+ DuplexTicketItem duplex;
+ OrientationTicketItem orientation;
+ MarginsTicketItem margins;
+ DpiTicketItem dpi;
+ FitToPageTicketItem fit_to_page;
+ MediaTicketItem media;
+ CopiesTicketItem copies;
+ PageRangeTicketItem page_range;
+ CollateTicketItem collate;
+ ReverseTicketItem reverse;
+
+ EXPECT_TRUE(color.LoadFrom(description));
+ EXPECT_TRUE(duplex.LoadFrom(description));
+ EXPECT_TRUE(orientation.LoadFrom(description));
+ EXPECT_TRUE(copies.LoadFrom(description));
+ EXPECT_TRUE(margins.LoadFrom(description));
+ EXPECT_TRUE(dpi.LoadFrom(description));
+ EXPECT_TRUE(fit_to_page.LoadFrom(description));
+ EXPECT_TRUE(page_range.LoadFrom(description));
+ EXPECT_TRUE(media.LoadFrom(description));
+ EXPECT_TRUE(collate.LoadFrom(description));
+ EXPECT_TRUE(reverse.LoadFrom(description));
+ EXPECT_TRUE(media.LoadFrom(description));
+
+ EXPECT_EQ(color.value(), Color(STANDARD_MONOCHROME));
+ EXPECT_EQ(duplex.value(), NO_DUPLEX);
+ EXPECT_EQ(orientation.value(), LANDSCAPE);
+ EXPECT_EQ(copies.value(), 123);
+ EXPECT_EQ(margins.value(), Margins(CUSTOM_MARGINS, 7, 6, 3, 1));
+ EXPECT_EQ(dpi.value(), Dpi(562, 125));
+ EXPECT_EQ(fit_to_page.value(), SHRINK_TO_PAGE);
+ PageRange page_ranges;
+ page_ranges.push_back(Interval(1, 99));
+ page_ranges.push_back(Interval(150));
+ EXPECT_EQ(page_range.value(), page_ranges);
+ EXPECT_EQ(media.value(), Media(ISO_C7C6, 4261, 334));
+ EXPECT_FALSE(collate.value());
+ EXPECT_TRUE(reverse.value());
+
+ EXPECT_EQ(NormalizeJson(kCjt), NormalizeJson(description.ToString()));
+}
+
+} // namespace printer
+
+} // namespace cloud_devices