Home | History | Annotate | Download | only in common
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/cloud_devices/common/printer_description.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/json/json_reader.h"
     10 #include "base/json/json_writer.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/values.h"
     13 #include "components/cloud_devices/common/cloud_device_description_consts.h"
     14 #include "components/cloud_devices/common/description_items_inl.h"
     15 
     16 namespace cloud_devices {
     17 
     18 namespace printer {
     19 
     20 namespace {
     21 
     22 const int32 kMaxPageNumber = 1000000;
     23 
     24 const char kSectionPrint[] = "print";
     25 const char kSectionPrinter[] = "printer";
     26 
     27 const char kCustomName[] = "custom_display_name";
     28 const char kKeyContentType[] = "content_type";
     29 const char kKeyName[] = "name";
     30 const char kKeyType[] = "type";
     31 const char kKeyVendorId[] = "vendor_id";
     32 
     33 // extern is required to be used in templates.
     34 extern const char kOptionCollate[] = "collate";
     35 extern const char kOptionColor[] = "color";
     36 extern const char kOptionContentType[] = "supported_content_type";
     37 extern const char kOptionCopies[] = "copies";
     38 extern const char kOptionDpi[] = "dpi";
     39 extern const char kOptionDuplex[] = "duplex";
     40 extern const char kOptionFitToPage[] = "fit_to_page";
     41 extern const char kOptionMargins[] = "margins";
     42 extern const char kOptionMediaSize[] = "media_size";
     43 extern const char kOptionPageOrientation[] = "page_orientation";
     44 extern const char kOptionPageRange[] = "page_range";
     45 extern const char kOptionReverse[] = "reverse_order";
     46 extern const char kOptionPwgRasterConfig[] = "pwg_raster_config";
     47 
     48 const char kMargineBottom[] = "bottom_microns";
     49 const char kMargineLeft[] = "left_microns";
     50 const char kMargineRight[] = "right_microns";
     51 const char kMargineTop[] = "top_microns";
     52 
     53 const char kDpiHorizontal[] = "horizontal_dpi";
     54 const char kDpiVertical[] = "vertical_dpi";
     55 
     56 const char kMediaWidth[] = "width_microns";
     57 const char kMediaHeight[] = "height_microns";
     58 const char kMediaIsContinuous[] = "is_continuous_feed";
     59 
     60 const char kPageRangeInterval[] = "interval";
     61 const char kPageRangeEnd[] = "end";
     62 const char kPageRangeStart[] = "start";
     63 
     64 const char kPwgRasterDocumentSheetBack[] = "document_sheet_back";
     65 const char kPwgRasterReverseOrderStreaming[] = "reverse_order_streaming";
     66 const char kPwgRasterRotateAllPages[] = "rotate_all_pages";
     67 
     68 const char kTypeColorColor[] = "STANDARD_COLOR";
     69 const char kTypeColorMonochrome[] = "STANDARD_MONOCHROME";
     70 const char kTypeColorCustomColor[] = "CUSTOM_COLOR";
     71 const char kTypeColorCustomMonochrome[] = "CUSTOM_MONOCHROME";
     72 const char kTypeColorAuto[] = "AUTO";
     73 
     74 const char kTypeDuplexLongEdge[] = "LONG_EDGE";
     75 const char kTypeDuplexNoDuplex[] = "NO_DUPLEX";
     76 const char kTypeDuplexShortEdge[] = "SHORT_EDGE";
     77 
     78 const char kTypeFitToPageFillPage[] = "FILL_PAGE";
     79 const char kTypeFitToPageFitToPage[] = "FIT_TO_PAGE";
     80 const char kTypeFitToPageGrowToPage[] = "GROW_TO_PAGE";
     81 const char kTypeFitToPageNoFitting[] = "NO_FITTING";
     82 const char kTypeFitToPageShrinkToPage[] = "SHRINK_TO_PAGE";
     83 
     84 const char kTypeMarginsBorderless[] = "BORDERLESS";
     85 const char kTypeMarginsCustom[] = "CUSTOM";
     86 const char kTypeMarginsStandard[] = "STANDARD";
     87 const char kTypeOrientationAuto[] = "AUTO";
     88 
     89 const char kTypeOrientationLandscape[] = "LANDSCAPE";
     90 const char kTypeOrientationPortrait[] = "PORTRAIT";
     91 
     92 const char kTypeDocumentSheetBackNormal[] = "NORMAL";
     93 const char kTypeDocumentSheetBackRotated[] = "ROTATED";
     94 const char kTypeDocumentSheetBackManualTumble[] = "MANUAL_TUMBLE";
     95 const char kTypeDocumentSheetBackFlipped[] = "FLIPPED";
     96 
     97 const struct ColorNames {
     98   ColorType id;
     99   const char* const json_name;
    100 } kColorNames[] = {
    101       {STANDARD_COLOR, kTypeColorColor},
    102       {STANDARD_MONOCHROME, kTypeColorMonochrome},
    103       {CUSTOM_COLOR, kTypeColorCustomColor},
    104       {CUSTOM_MONOCHROME, kTypeColorCustomMonochrome},
    105       {AUTO_COLOR, kTypeColorAuto},
    106 };
    107 
    108 const struct DuplexNames {
    109   DuplexType id;
    110   const char* const json_name;
    111 } kDuplexNames[] = {
    112       {NO_DUPLEX, kTypeDuplexNoDuplex},
    113       {LONG_EDGE, kTypeDuplexLongEdge},
    114       {SHORT_EDGE, kTypeDuplexShortEdge},
    115 };
    116 
    117 const struct OrientationNames {
    118   OrientationType id;
    119   const char* const json_name;
    120 } kOrientationNames[] = {
    121       {PORTRAIT, kTypeOrientationPortrait},
    122       {LANDSCAPE, kTypeOrientationLandscape},
    123       {AUTO_ORIENTATION, kTypeOrientationAuto},
    124 };
    125 
    126 const struct MarginsNames {
    127   MarginsType id;
    128   const char* const json_name;
    129 } kMarginsNames[] = {
    130       {NO_MARGINS, kTypeMarginsBorderless},
    131       {STANDARD_MARGINS, kTypeMarginsStandard},
    132       {CUSTOM_MARGINS, kTypeMarginsCustom},
    133 };
    134 
    135 const struct FitToPageNames {
    136   FitToPageType id;
    137   const char* const json_name;
    138 } kFitToPageNames[] = {
    139       {NO_FITTING, kTypeFitToPageNoFitting},
    140       {FIT_TO_PAGE, kTypeFitToPageFitToPage},
    141       {GROW_TO_PAGE, kTypeFitToPageGrowToPage},
    142       {SHRINK_TO_PAGE, kTypeFitToPageShrinkToPage},
    143       {FILL_PAGE, kTypeFitToPageFillPage},
    144 };
    145 
    146 const struct DocumentSheetBackNames {
    147   DocumentSheetBack id;
    148   const char* const json_name;
    149 } kDocumentSheetBackNames[] = {
    150       {NORMAL, kTypeDocumentSheetBackNormal},
    151       {ROTATED, kTypeDocumentSheetBackRotated},
    152       {MANUAL_TUMBLE, kTypeDocumentSheetBackManualTumble},
    153       {FLIPPED, kTypeDocumentSheetBackFlipped}};
    154 
    155 const int32 kInchToUm = 25400;
    156 const int32 kMmToUm = 1000;
    157 const int32 kSizeTrasholdUm = 1000;
    158 
    159 #define MAP_CLOUD_PRINT_MEDIA_TYPE(type, width, height, unit_um) \
    160   {                                                              \
    161     type, #type, static_cast<int>(width* unit_um + 0.5),         \
    162         static_cast<int>(height* unit_um + 0.5)                  \
    163   }
    164 
    165 const struct MediaDefinition {
    166   MediaType id;
    167   const char* const json_name;
    168   int width_um;
    169   int height_um;
    170 } kMediaDefinitions[] = {
    171       {CUSTOM_MEDIA, "CUSTOM", 0, 0},
    172       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_3X5, 3, 5, kInchToUm),
    173       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_PERSONAL, 3.625f, 6.5f, kInchToUm),
    174       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_MONARCH, 3.875f, 7.5f, kInchToUm),
    175       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_9, 3.875f, 8.875f, kInchToUm),
    176       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_4X6, 4, 6, kInchToUm),
    177       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_10, 4.125f, 9.5f, kInchToUm),
    178       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_A2, 4.375f, 5.75f, kInchToUm),
    179       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_11, 4.5f, 10.375f, kInchToUm),
    180       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_12, 4.75f, 11, kInchToUm),
    181       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_5X7, 5, 7, kInchToUm),
    182       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_5X8, 5, 8, kInchToUm),
    183       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_NUMBER_14, 5, 11.5f, kInchToUm),
    184       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INVOICE, 5.5f, 8.5f, kInchToUm),
    185       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_INDEX_4X6_EXT, 6, 8, kInchToUm),
    186       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_6X9, 6, 9, kInchToUm),
    187       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_C5, 6.5f, 9.5f, kInchToUm),
    188       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_7X9, 7, 9, kInchToUm),
    189       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EXECUTIVE, 7.25f, 10.5f, kInchToUm),
    190       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_GOVT_LETTER, 8, 10, kInchToUm),
    191       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_GOVT_LEGAL, 8, 13, kInchToUm),
    192       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_QUARTO, 8.5f, 10.83f, kInchToUm),
    193       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER, 8.5f, 11, kInchToUm),
    194       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FANFOLD_EUR, 8.5f, 12, kInchToUm),
    195       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER_PLUS, 8.5f, 12.69f, kInchToUm),
    196       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FOOLSCAP, 8.5f, 13, kInchToUm),
    197       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEGAL, 8.5f, 14, kInchToUm),
    198       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_SUPER_A, 8.94f, 14, kInchToUm),
    199       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_9X11, 9, 11, kInchToUm),
    200       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_A, 9, 12, kInchToUm),
    201       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LETTER_EXTRA, 9.5f, 12, kInchToUm),
    202       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEGAL_EXTRA, 9.5f, 15, kInchToUm),
    203       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X11, 10, 11, kInchToUm),
    204       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X13, 10, 13, kInchToUm),
    205       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X14, 10, 14, kInchToUm),
    206       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_10X15, 10, 15, kInchToUm),
    207       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_11X12, 11, 12, kInchToUm),
    208       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EDP, 11, 14, kInchToUm),
    209       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_FANFOLD_US, 11, 14.875f, kInchToUm),
    210       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_11X15, 11, 15, kInchToUm),
    211       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_LEDGER, 11, 17, kInchToUm),
    212       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_EUR_EDP, 12, 14, kInchToUm),
    213       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_B, 12, 18, kInchToUm),
    214       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_12X19, 12, 19, kInchToUm),
    215       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_B_PLUS, 12, 19.17f, kInchToUm),
    216       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_SUPER_B, 13, 19, kInchToUm),
    217       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_C, 17, 22, kInchToUm),
    218       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_C, 18, 24, kInchToUm),
    219       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_D, 22, 34, kInchToUm),
    220       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_D, 24, 36, kInchToUm),
    221       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ASME_F, 28, 40, kInchToUm),
    222       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_WIDE_FORMAT, 30, 42, kInchToUm),
    223       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_E, 34, 44, kInchToUm),
    224       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_ARCH_E, 36, 48, kInchToUm),
    225       MAP_CLOUD_PRINT_MEDIA_TYPE(NA_F, 44, 68, kInchToUm),
    226       MAP_CLOUD_PRINT_MEDIA_TYPE(ROC_16K, 7.75f, 10.75f, kInchToUm),
    227       MAP_CLOUD_PRINT_MEDIA_TYPE(ROC_8K, 10.75f, 15.5f, kInchToUm),
    228       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_32K, 97, 151, kMmToUm),
    229       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_1, 102, 165, kMmToUm),
    230       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_2, 102, 176, kMmToUm),
    231       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_4, 110, 208, kMmToUm),
    232       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_5, 110, 220, kMmToUm),
    233       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_8, 120, 309, kMmToUm),
    234       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_6, 120, 230, kMmToUm),
    235       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_3, 125, 176, kMmToUm),
    236       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_16K, 146, 215, kMmToUm),
    237       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_7, 160, 230, kMmToUm),
    238       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_JUURO_KU_KAI, 198, 275, kMmToUm),
    239       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_PA_KAI, 267, 389, kMmToUm),
    240       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_DAI_PA_KAI, 275, 395, kMmToUm),
    241       MAP_CLOUD_PRINT_MEDIA_TYPE(PRC_10, 324, 458, kMmToUm),
    242       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A10, 26, 37, kMmToUm),
    243       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A9, 37, 52, kMmToUm),
    244       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A8, 52, 74, kMmToUm),
    245       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A7, 74, 105, kMmToUm),
    246       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A6, 105, 148, kMmToUm),
    247       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A5, 148, 210, kMmToUm),
    248       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A5_EXTRA, 174, 235, kMmToUm),
    249       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4, 210, 297, kMmToUm),
    250       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4_TAB, 225, 297, kMmToUm),
    251       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4_EXTRA, 235, 322, kMmToUm),
    252       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3, 297, 420, kMmToUm),
    253       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X3, 297, 630, kMmToUm),
    254       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X4, 297, 841, kMmToUm),
    255       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X5, 297, 1051, kMmToUm),
    256       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X6, 297, 1261, kMmToUm),
    257       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X7, 297, 1471, kMmToUm),
    258       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X8, 297, 1682, kMmToUm),
    259       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A4X9, 297, 1892, kMmToUm),
    260       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3_EXTRA, 322, 445, kMmToUm),
    261       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2, 420, 594, kMmToUm),
    262       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X3, 420, 891, kMmToUm),
    263       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X4, 420, 1189, kMmToUm),
    264       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X5, 420, 1486, kMmToUm),
    265       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X6, 420, 1783, kMmToUm),
    266       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A3X7, 420, 2080, kMmToUm),
    267       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1, 594, 841, kMmToUm),
    268       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X3, 594, 1261, kMmToUm),
    269       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X4, 594, 1682, kMmToUm),
    270       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A2X5, 594, 2102, kMmToUm),
    271       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A0, 841, 1189, kMmToUm),
    272       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1X3, 841, 1783, kMmToUm),
    273       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A1X4, 841, 2378, kMmToUm),
    274       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_2A0, 1189, 1682, kMmToUm),
    275       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_A0X3, 1189, 2523, kMmToUm),
    276       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B10, 31, 44, kMmToUm),
    277       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B9, 44, 62, kMmToUm),
    278       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B8, 62, 88, kMmToUm),
    279       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B7, 88, 125, kMmToUm),
    280       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B6, 125, 176, kMmToUm),
    281       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B6C4, 125, 324, kMmToUm),
    282       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B5, 176, 250, kMmToUm),
    283       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B5_EXTRA, 201, 276, kMmToUm),
    284       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B4, 250, 353, kMmToUm),
    285       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B3, 353, 500, kMmToUm),
    286       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B2, 500, 707, kMmToUm),
    287       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B1, 707, 1000, kMmToUm),
    288       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_B0, 1000, 1414, kMmToUm),
    289       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C10, 28, 40, kMmToUm),
    290       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C9, 40, 57, kMmToUm),
    291       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C8, 57, 81, kMmToUm),
    292       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C7, 81, 114, kMmToUm),
    293       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C7C6, 81, 162, kMmToUm),
    294       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C6, 114, 162, kMmToUm),
    295       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C6C5, 114, 229, kMmToUm),
    296       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C5, 162, 229, kMmToUm),
    297       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C4, 229, 324, kMmToUm),
    298       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C3, 324, 458, kMmToUm),
    299       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C2, 458, 648, kMmToUm),
    300       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C1, 648, 917, kMmToUm),
    301       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_C0, 917, 1297, kMmToUm),
    302       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_DL, 110, 220, kMmToUm),
    303       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA2, 430, 610, kMmToUm),
    304       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA2, 450, 640, kMmToUm),
    305       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA1, 610, 860, kMmToUm),
    306       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA1, 640, 900, kMmToUm),
    307       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_RA0, 860, 1220, kMmToUm),
    308       MAP_CLOUD_PRINT_MEDIA_TYPE(ISO_SRA0, 900, 1280, kMmToUm),
    309       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B10, 32, 45, kMmToUm),
    310       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B9, 45, 64, kMmToUm),
    311       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B8, 64, 91, kMmToUm),
    312       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B7, 91, 128, kMmToUm),
    313       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B6, 128, 182, kMmToUm),
    314       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B5, 182, 257, kMmToUm),
    315       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B4, 257, 364, kMmToUm),
    316       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B3, 364, 515, kMmToUm),
    317       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B2, 515, 728, kMmToUm),
    318       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B1, 728, 1030, kMmToUm),
    319       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_B0, 1030, 1456, kMmToUm),
    320       MAP_CLOUD_PRINT_MEDIA_TYPE(JIS_EXEC, 216, 330, kMmToUm),
    321       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU4, 90, 205, kMmToUm),
    322       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_HAGAKI, 100, 148, kMmToUm),
    323       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_YOU4, 105, 235, kMmToUm),
    324       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU2, 111.1f, 146, kMmToUm),
    325       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_CHOU3, 120, 235, kMmToUm),
    326       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_OUFUKU, 148, 200, kMmToUm),
    327       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_KAHU, 240, 322.1f, kMmToUm),
    328       MAP_CLOUD_PRINT_MEDIA_TYPE(JPN_KAKU2, 240, 332, kMmToUm),
    329       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_SMALL_PHOTO, 100, 150, kMmToUm),
    330       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_ITALIAN, 110, 230, kMmToUm),
    331       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_POSTFIX, 114, 229, kMmToUm),
    332       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_LARGE_PHOTO, 200, 300, kMmToUm),
    333       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_FOLIO, 210, 330, kMmToUm),
    334       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_FOLIO_SP, 215, 315, kMmToUm),
    335       MAP_CLOUD_PRINT_MEDIA_TYPE(OM_INVITE, 220, 220, kMmToUm)};
    336 #undef MAP_CLOUD_PRINT_MEDIA_TYPE
    337 
    338 const MediaDefinition& FindMediaByType(MediaType type) {
    339   for (size_t i = 0; i < arraysize(kMediaDefinitions); ++i) {
    340     if (kMediaDefinitions[i].id == type)
    341       return kMediaDefinitions[i];
    342   }
    343   NOTREACHED();
    344   return kMediaDefinitions[0];
    345 }
    346 
    347 const MediaDefinition* FindMediaBySize(int32 width_um, int32 height_um) {
    348   const MediaDefinition* result = NULL;
    349   for (size_t i = 0; i < arraysize(kMediaDefinitions); ++i) {
    350     int32 diff = std::max(std::abs(width_um - kMediaDefinitions[i].width_um),
    351                           std::abs(height_um - kMediaDefinitions[i].height_um));
    352     if (diff < kSizeTrasholdUm)
    353       result = &kMediaDefinitions[i];
    354   }
    355   return result;
    356 }
    357 
    358 template <class T, class IdType>
    359 std::string TypeToString(const T& names, IdType id) {
    360   for (size_t i = 0; i < arraysize(names); ++i) {
    361     if (id == names[i].id)
    362       return names[i].json_name;
    363   }
    364   NOTREACHED();
    365   return std::string();
    366 }
    367 
    368 template <class T, class IdType>
    369 bool TypeFromString(const T& names, const std::string& type, IdType* id) {
    370   for (size_t i = 0; i < arraysize(names); ++i) {
    371     if (type == names[i].json_name) {
    372       *id = names[i].id;
    373       return true;
    374     }
    375   }
    376   return false;
    377 }
    378 
    379 }  // namespace
    380 
    381 PwgRasterConfig::PwgRasterConfig()
    382     : document_sheet_back(ROTATED),
    383       reverse_order_streaming(false),
    384       rotate_all_pages(false) {
    385 }
    386 
    387 Color::Color() : type(AUTO_COLOR) {
    388 }
    389 
    390 Color::Color(ColorType type) : type(type) {
    391 }
    392 
    393 bool Color::operator==(const Color& other) const {
    394   return type == other.type && vendor_id == other.vendor_id &&
    395          custom_display_name == other.custom_display_name;
    396 }
    397 
    398 bool Color::IsValid() const {
    399   if (type != CUSTOM_COLOR && type != CUSTOM_MONOCHROME)
    400     return true;
    401   return !vendor_id.empty() && !custom_display_name.empty();
    402 }
    403 
    404 Margins::Margins()
    405     : type(STANDARD_MARGINS), top_um(0), right_um(0), bottom_um(0), left_um(0) {
    406 }
    407 
    408 Margins::Margins(MarginsType type,
    409                  int32 top_um,
    410                  int32 right_um,
    411                  int32 bottom_um,
    412                  int32 left_um)
    413     : type(type),
    414       top_um(top_um),
    415       right_um(right_um),
    416       bottom_um(bottom_um),
    417       left_um(left_um) {
    418 }
    419 
    420 bool Margins::operator==(const Margins& other) const {
    421   return type == other.type && top_um == other.top_um &&
    422          right_um == other.right_um && bottom_um == other.bottom_um;
    423 }
    424 
    425 Dpi::Dpi() : horizontal(0), vertical(0) {
    426 }
    427 
    428 Dpi::Dpi(int32 horizontal, int32 vertical)
    429     : horizontal(horizontal), vertical(vertical) {
    430 }
    431 
    432 bool Dpi::IsValid() const {
    433   return horizontal > 0 && vertical > 0;
    434 }
    435 
    436 bool Dpi::operator==(const Dpi& other) const {
    437   return horizontal == other.horizontal && vertical == other.vertical;
    438 }
    439 
    440 Media::Media()
    441     : type(CUSTOM_MEDIA), width_um(0), height_um(0), is_continuous_feed(false) {
    442 }
    443 
    444 Media::Media(MediaType type)
    445     : type(type),
    446       width_um(0),
    447       height_um(0),
    448       is_continuous_feed(false) {
    449   const MediaDefinition& media = FindMediaByType(type);
    450   width_um = media.width_um;
    451   height_um = media.height_um;
    452   is_continuous_feed = width_um <= 0 || height_um <= 0;
    453 }
    454 
    455 Media::Media(MediaType type, int32 width_um, int32 height_um)
    456     : type(type),
    457       width_um(width_um),
    458       height_um(height_um),
    459       is_continuous_feed(width_um <= 0 || height_um <= 0) {
    460 }
    461 
    462 Media::Media(const std::string& custom_display_name,
    463              const std::string& vendor_id,
    464              int32 width_um,
    465              int32 height_um)
    466     : type(CUSTOM_MEDIA),
    467       width_um(width_um),
    468       height_um(height_um),
    469       is_continuous_feed(width_um <= 0 || height_um <= 0),
    470       custom_display_name(custom_display_name),
    471       vendor_id(vendor_id) {
    472 }
    473 
    474 bool Media::MatchBySize() {
    475   const MediaDefinition* media = FindMediaBySize(width_um, height_um);
    476   if (!media)
    477     return false;
    478   type = media->id;
    479   return true;
    480 }
    481 
    482 bool Media::IsValid() const {
    483   if (is_continuous_feed) {
    484     if (width_um <= 0 && height_um <= 0)
    485       return false;
    486   } else {
    487     if (width_um <= 0 || height_um <= 0)
    488       return false;
    489   }
    490   return true;
    491 }
    492 
    493 bool Media::operator==(const Media& other) const {
    494   return type == other.type && width_um == other.width_um &&
    495          height_um == other.height_um &&
    496          is_continuous_feed == other.is_continuous_feed;
    497 }
    498 
    499 Interval::Interval() : start(0), end(0) {
    500 }
    501 
    502 Interval::Interval(int32 start, int32 end) : start(start), end(end) {
    503 }
    504 
    505 Interval::Interval(int32 start) : start(start), end(kMaxPageNumber) {
    506 }
    507 
    508 bool Interval::operator==(const Interval& other) const {
    509   return start == other.start && end == other.end;
    510 }
    511 
    512 template <const char* kName>
    513 class ItemsTraits {
    514  public:
    515   static std::string GetCapabilityPath() {
    516     std::string result = kSectionPrinter;
    517     result += '.';
    518     result += kName;
    519     return result;
    520   }
    521 
    522   static std::string GetTicketItemPath() {
    523     std::string result = kSectionPrint;
    524     result += '.';
    525     result += kName;
    526     return result;
    527   }
    528 };
    529 
    530 class NoValueValidation {
    531  public:
    532   template <class Option>
    533   static bool IsValid(const Option&) {
    534     return true;
    535   }
    536 };
    537 
    538 class ContentTypeTraits : public NoValueValidation,
    539                           public ItemsTraits<kOptionContentType> {
    540  public:
    541   static bool Load(const base::DictionaryValue& dict, ContentType* option) {
    542     return dict.GetString(kKeyContentType, option);
    543   }
    544 
    545   static void Save(ContentType option, base::DictionaryValue* dict) {
    546     dict->SetString(kKeyContentType, option);
    547   }
    548 };
    549 
    550 class PwgRasterConfigTraits : public NoValueValidation,
    551                               public ItemsTraits<kOptionPwgRasterConfig> {
    552  public:
    553   static bool Load(const base::DictionaryValue& dict, PwgRasterConfig* option) {
    554     std::string document_sheet_back;
    555     PwgRasterConfig option_out;
    556     if (dict.GetString(kPwgRasterDocumentSheetBack, &document_sheet_back)) {
    557       if (!TypeFromString(kDocumentSheetBackNames,
    558                           document_sheet_back,
    559                           &option_out.document_sheet_back)) {
    560         return false;
    561       }
    562     }
    563 
    564     dict.GetBoolean(kPwgRasterReverseOrderStreaming,
    565                     &option_out.reverse_order_streaming);
    566     dict.GetBoolean(kPwgRasterRotateAllPages, &option_out.rotate_all_pages);
    567     *option = option_out;
    568     return true;
    569   }
    570 
    571   static void Save(const PwgRasterConfig& option, base::DictionaryValue* dict) {
    572     dict->SetString(
    573         kPwgRasterDocumentSheetBack,
    574         TypeToString(kDocumentSheetBackNames, option.document_sheet_back));
    575     if (option.reverse_order_streaming)
    576       dict->SetBoolean(kPwgRasterReverseOrderStreaming,
    577                        option.reverse_order_streaming);
    578 
    579     if (option.rotate_all_pages)
    580       dict->SetBoolean(kPwgRasterRotateAllPages, option.rotate_all_pages);
    581   }
    582 };
    583 
    584 class ColorTraits : public ItemsTraits<kOptionColor> {
    585  public:
    586   static bool IsValid(const Color& option) { return option.IsValid(); }
    587 
    588   static bool Load(const base::DictionaryValue& dict, Color* option) {
    589     std::string type_str;
    590     if (!dict.GetString(kKeyType, &type_str))
    591       return false;
    592     if (!TypeFromString(kColorNames, type_str, &option->type))
    593       return false;
    594     dict.GetString(kKeyVendorId, &option->vendor_id);
    595     dict.GetString(kCustomName, &option->custom_display_name);
    596     return true;
    597   }
    598 
    599   static void Save(const Color& option, base::DictionaryValue* dict) {
    600     dict->SetString(kKeyType, TypeToString(kColorNames, option.type));
    601     if (!option.vendor_id.empty())
    602       dict->SetString(kKeyVendorId, option.vendor_id);
    603     if (!option.custom_display_name.empty())
    604       dict->SetString(kCustomName, option.custom_display_name);
    605   }
    606 };
    607 
    608 class DuplexTraits : public NoValueValidation,
    609                      public ItemsTraits<kOptionDuplex> {
    610  public:
    611   static bool Load(const base::DictionaryValue& dict, DuplexType* option) {
    612     std::string type_str;
    613     return dict.GetString(kKeyType, &type_str) &&
    614            TypeFromString(kDuplexNames, type_str, option);
    615   }
    616 
    617   static void Save(DuplexType option, base::DictionaryValue* dict) {
    618     dict->SetString(kKeyType, TypeToString(kDuplexNames, option));
    619   }
    620 };
    621 
    622 class OrientationTraits : public NoValueValidation,
    623                           public ItemsTraits<kOptionPageOrientation> {
    624  public:
    625   static bool Load(const base::DictionaryValue& dict, OrientationType* option) {
    626     std::string type_str;
    627     return dict.GetString(kKeyType, &type_str) &&
    628            TypeFromString(kOrientationNames, type_str, option);
    629   }
    630 
    631   static void Save(OrientationType option, base::DictionaryValue* dict) {
    632     dict->SetString(kKeyType, TypeToString(kOrientationNames, option));
    633   }
    634 };
    635 
    636 class CopiesTraits : public ItemsTraits<kOptionCopies> {
    637  public:
    638   static bool IsValid(int32 option) { return option >= 1; }
    639 
    640   static bool Load(const base::DictionaryValue& dict, int32* option) {
    641     return dict.GetInteger(kOptionCopies, option);
    642   }
    643 
    644   static void Save(int32 option, base::DictionaryValue* dict) {
    645     dict->SetInteger(kOptionCopies, option);
    646   }
    647 };
    648 
    649 class MarginsTraits : public NoValueValidation,
    650                       public ItemsTraits<kOptionMargins> {
    651  public:
    652   static bool Load(const base::DictionaryValue& dict, Margins* option) {
    653     std::string type_str;
    654     if (!dict.GetString(kKeyType, &type_str))
    655       return false;
    656     if (!TypeFromString(kMarginsNames, type_str, &option->type))
    657       return false;
    658     return dict.GetInteger(kMargineTop, &option->top_um) &&
    659            dict.GetInteger(kMargineRight, &option->right_um) &&
    660            dict.GetInteger(kMargineBottom, &option->bottom_um) &&
    661            dict.GetInteger(kMargineLeft, &option->left_um);
    662   }
    663 
    664   static void Save(const Margins& option, base::DictionaryValue* dict) {
    665     dict->SetString(kKeyType, TypeToString(kMarginsNames, option.type));
    666     dict->SetInteger(kMargineTop, option.top_um);
    667     dict->SetInteger(kMargineRight, option.right_um);
    668     dict->SetInteger(kMargineBottom, option.bottom_um);
    669     dict->SetInteger(kMargineLeft, option.left_um);
    670   }
    671 };
    672 
    673 class DpiTraits : public ItemsTraits<kOptionDpi> {
    674  public:
    675   static bool IsValid(const Dpi& option) { return option.IsValid(); }
    676 
    677   static bool Load(const base::DictionaryValue& dict, Dpi* option) {
    678     if (!dict.GetInteger(kDpiHorizontal, &option->horizontal) ||
    679         !dict.GetInteger(kDpiVertical, &option->vertical)) {
    680       return false;
    681     }
    682     return true;
    683   }
    684 
    685   static void Save(const Dpi& option, base::DictionaryValue* dict) {
    686     dict->SetInteger(kDpiHorizontal, option.horizontal);
    687     dict->SetInteger(kDpiVertical, option.vertical);
    688   }
    689 };
    690 
    691 class FitToPageTraits : public NoValueValidation,
    692                         public ItemsTraits<kOptionFitToPage> {
    693  public:
    694   static bool Load(const base::DictionaryValue& dict, FitToPageType* option) {
    695     std::string type_str;
    696     return dict.GetString(kKeyType, &type_str) &&
    697            TypeFromString(kFitToPageNames, type_str, option);
    698   }
    699 
    700   static void Save(FitToPageType option, base::DictionaryValue* dict) {
    701     dict->SetString(kKeyType, TypeToString(kFitToPageNames, option));
    702   }
    703 };
    704 
    705 class PageRangeTraits : public ItemsTraits<kOptionPageRange> {
    706  public:
    707   static bool IsValid(const PageRange& option) {
    708     for (size_t i = 0; i < option.size(); ++i) {
    709       if (option[i].start < 1 || option[i].end < 1) {
    710         return false;
    711       }
    712     }
    713     return true;
    714   }
    715 
    716   static bool Load(const base::DictionaryValue& dict, PageRange* option) {
    717     const base::ListValue* list = NULL;
    718     if (!dict.GetList(kPageRangeInterval, &list))
    719       return false;
    720     for (size_t i = 0; i < list->GetSize(); ++i) {
    721       const base::DictionaryValue* interval = NULL;
    722       if (!list->GetDictionary(i, &interval))
    723         return false;
    724       Interval new_interval(1, kMaxPageNumber);
    725       interval->GetInteger(kPageRangeStart, &new_interval.start);
    726       interval->GetInteger(kPageRangeEnd, &new_interval.end);
    727       option->push_back(new_interval);
    728     }
    729     return true;
    730   }
    731 
    732   static void Save(const PageRange& option, base::DictionaryValue* dict) {
    733     if (!option.empty()) {
    734       base::ListValue* list = new base::ListValue;
    735       dict->Set(kPageRangeInterval, list);
    736       for (size_t i = 0; i < option.size(); ++i) {
    737         base::DictionaryValue* interval = new base::DictionaryValue;
    738         list->Append(interval);
    739         interval->SetInteger(kPageRangeStart, option[i].start);
    740         if (option[i].end < kMaxPageNumber)
    741           interval->SetInteger(kPageRangeEnd, option[i].end);
    742       }
    743     }
    744   }
    745 };
    746 
    747 class MediaTraits : public ItemsTraits<kOptionMediaSize> {
    748  public:
    749   static bool IsValid(const Media& option) { return option.IsValid(); }
    750 
    751   static bool Load(const base::DictionaryValue& dict, Media* option) {
    752     std::string type_str;
    753     if (dict.GetString(kKeyName, &type_str)) {
    754       if (!TypeFromString(kMediaDefinitions, type_str, &option->type))
    755         return false;
    756     }
    757 
    758     dict.GetInteger(kMediaWidth, &option->width_um);
    759     dict.GetInteger(kMediaHeight, &option->height_um);
    760     dict.GetBoolean(kMediaIsContinuous, &option->is_continuous_feed);
    761     dict.GetString(kCustomName, &option->custom_display_name);
    762     dict.GetString(kKeyVendorId, &option->vendor_id);
    763     return true;
    764   }
    765 
    766   static void Save(const Media& option, base::DictionaryValue* dict) {
    767     if (option.type != CUSTOM_MEDIA)
    768       dict->SetString(kKeyName, TypeToString(kMediaDefinitions, option.type));
    769     if (!option.custom_display_name.empty() || option.type == CUSTOM_MEDIA)
    770       dict->SetString(kCustomName, option.custom_display_name);
    771     if (!option.vendor_id.empty())
    772       dict->SetString(kKeyVendorId, option.vendor_id);
    773     if (option.width_um > 0)
    774       dict->SetInteger(kMediaWidth, option.width_um);
    775     if (option.height_um > 0)
    776       dict->SetInteger(kMediaHeight, option.height_um);
    777     if (option.is_continuous_feed)
    778       dict->SetBoolean(kMediaIsContinuous, true);
    779   }
    780 };
    781 
    782 class CollateTraits : public NoValueValidation,
    783                       public ItemsTraits<kOptionCollate> {
    784  public:
    785   static const bool kDefault = true;
    786 
    787   static bool Load(const base::DictionaryValue& dict, bool* option) {
    788     return dict.GetBoolean(kOptionCollate, option);
    789   }
    790 
    791   static void Save(bool option, base::DictionaryValue* dict) {
    792     dict->SetBoolean(kOptionCollate, option);
    793   }
    794 };
    795 
    796 class ReverseTraits : public NoValueValidation,
    797                       public ItemsTraits<kOptionReverse> {
    798  public:
    799   static const bool kDefault = false;
    800 
    801   static bool Load(const base::DictionaryValue& dict, bool* option) {
    802     return dict.GetBoolean(kOptionReverse, option);
    803   }
    804 
    805   static void Save(bool option, base::DictionaryValue* dict) {
    806     dict->SetBoolean(kOptionReverse, option);
    807   }
    808 };
    809 
    810 }  // namespace printer
    811 
    812 using namespace printer;
    813 
    814 template class ListCapability<ContentType, ContentTypeTraits>;
    815 template class ValueCapability<PwgRasterConfig, PwgRasterConfigTraits>;
    816 template class SelectionCapability<Color, ColorTraits>;
    817 template class SelectionCapability<DuplexType, DuplexTraits>;
    818 template class SelectionCapability<OrientationType, OrientationTraits>;
    819 template class SelectionCapability<Margins, MarginsTraits>;
    820 template class SelectionCapability<Dpi, DpiTraits>;
    821 template class SelectionCapability<FitToPageType, FitToPageTraits>;
    822 template class SelectionCapability<Media, MediaTraits>;
    823 template class EmptyCapability<class CopiesTraits>;
    824 template class EmptyCapability<class PageRangeTraits>;
    825 template class BooleanCapability<class CollateTraits>;
    826 template class BooleanCapability<class ReverseTraits>;
    827 
    828 template class TicketItem<PwgRasterConfig, PwgRasterConfigTraits>;
    829 template class TicketItem<Color, ColorTraits>;
    830 template class TicketItem<DuplexType, DuplexTraits>;
    831 template class TicketItem<OrientationType, OrientationTraits>;
    832 template class TicketItem<Margins, MarginsTraits>;
    833 template class TicketItem<Dpi, DpiTraits>;
    834 template class TicketItem<FitToPageType, FitToPageTraits>;
    835 template class TicketItem<Media, MediaTraits>;
    836 template class TicketItem<int32, CopiesTraits>;
    837 template class TicketItem<PageRange, PageRangeTraits>;
    838 template class TicketItem<bool, CollateTraits>;
    839 template class TicketItem<bool, ReverseTraits>;
    840 
    841 }  // namespace cloud_devices
    842