OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "printing/backend/cups_ipp_util.h" |
| 6 |
| 7 #include <cups/cups.h> |
| 8 |
| 9 #include <algorithm> |
| 10 #include <string> |
| 11 #include <vector> |
| 12 |
| 13 #include "base/logging.h" |
| 14 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/string_piece.h" |
| 16 #include "base/strings/string_split.h" |
| 17 #include "base/strings/string_util.h" |
| 18 #include "printing/backend/cups_printer.h" |
| 19 #include "printing/backend/print_backend_consts.h" |
| 20 #include "printing/units.h" |
| 21 |
| 22 namespace printing { |
| 23 |
| 24 namespace { |
| 25 |
| 26 const char kIppCollate[] = "sheet-collate"; // RFC 3381 |
| 27 const char kIppCopies[] = CUPS_COPIES; |
| 28 const char kIppColor[] = CUPS_PRINT_COLOR_MODE; |
| 29 const char kIppMedia[] = CUPS_MEDIA; |
| 30 const char kIppDuplex[] = CUPS_SIDES; |
| 31 |
| 32 const int kMicronsPerMM = 1000; |
| 33 const double kMMPerInch = 25.4; |
| 34 const double kMicronsPerInch = kMMPerInch * kMicronsPerMM; |
| 35 |
| 36 enum Unit { |
| 37 INCHES, |
| 38 MILLIMETERS, |
| 39 }; |
| 40 |
| 41 bool PrinterSupportsValue(const CupsPrinter& printer, |
| 42 base::StringPiece name, |
| 43 base::StringPiece value) { |
| 44 std::vector<base::StringPiece> values = |
| 45 printer.GetSupportedOptionValueStrings(name); |
| 46 auto iter = std::find(values.begin(), values.end(), value); |
| 47 return iter != values.end(); |
| 48 } |
| 49 |
| 50 DuplexMode PrinterDefaultDuplex(const CupsPrinter& printer) { |
| 51 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppDuplex); |
| 52 if (attr == nullptr) { |
| 53 return UNKNOWN_DUPLEX_MODE; |
| 54 } |
| 55 |
| 56 const char* value = ippGetString(attr, 0, NULL); |
| 57 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_ONE_SIDED)) |
| 58 return SIMPLEX; |
| 59 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_PORTRAIT)) |
| 60 return LONG_EDGE; |
| 61 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_LANDSCAPE)) |
| 62 return SHORT_EDGE; |
| 63 |
| 64 return UNKNOWN_DUPLEX_MODE; |
| 65 } |
| 66 |
| 67 gfx::Size DimensionsToMicrons(base::StringPiece value) { |
| 68 Unit unit; |
| 69 base::StringPiece dims; |
| 70 size_t unit_position; |
| 71 if ((unit_position = value.find("mm")) != base::StringPiece::npos) { |
| 72 unit = MILLIMETERS; |
| 73 dims = value.substr(0, unit_position); |
| 74 } else if ((unit_position = value.find("in")) != base::StringPiece::npos) { |
| 75 unit = INCHES; |
| 76 dims = value.substr(0, unit_position); |
| 77 } else { |
| 78 LOG(WARNING) << "Could not parse paper dimensions"; |
| 79 return {0, 0}; |
| 80 } |
| 81 |
| 82 std::vector<std::string> pieces = base::SplitString( |
| 83 dims, "x", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 84 double width; |
| 85 double height; |
| 86 |
| 87 if (pieces.size() != 2 || !base::StringToDouble(pieces[0], &width) || |
| 88 !base::StringToDouble(pieces[1], &height)) { |
| 89 return {0, 0}; |
| 90 } |
| 91 |
| 92 int width_microns; |
| 93 int height_microns; |
| 94 |
| 95 switch (unit) { |
| 96 case MILLIMETERS: |
| 97 width_microns = width * kMicronsPerMM; |
| 98 height_microns = height * kMicronsPerMM; |
| 99 break; |
| 100 case INCHES: |
| 101 width_microns = width * kMicronsPerInch; |
| 102 height_microns = height * kMicronsPerInch; |
| 103 break; |
| 104 default: |
| 105 NOTREACHED(); |
| 106 break; |
| 107 } |
| 108 |
| 109 return gfx::Size{width_microns, height_microns}; |
| 110 } |
| 111 |
| 112 PrinterSemanticCapsAndDefaults::Paper ParsePaper(base::StringPiece value) { |
| 113 // <name>_<width>x<height>{in,mm} |
| 114 // e.g. na_letter_8.5x11in, iso_a4_210x297mm |
| 115 |
| 116 std::vector<base::StringPiece> pieces = base::SplitStringPiece( |
| 117 value, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 118 if (pieces.size() < 2) { |
| 119 // we expect at least a display string and a dimension string |
| 120 return PrinterSemanticCapsAndDefaults::Paper(); |
| 121 } |
| 122 |
| 123 base::StringPiece dimensions = pieces.back(); |
| 124 |
| 125 std::string display = pieces[0].as_string(); |
| 126 for (size_t i = 1; i <= pieces.size() - 2; ++i) { |
| 127 display.append(" "); |
| 128 pieces[i].AppendToString(&display); |
| 129 } |
| 130 |
| 131 PrinterSemanticCapsAndDefaults::Paper paper; |
| 132 paper.display_name = display; |
| 133 paper.vendor_id = value.as_string(); |
| 134 paper.size_um = DimensionsToMicrons(dimensions); |
| 135 |
| 136 return paper; |
| 137 } |
| 138 |
| 139 } // namespace |
| 140 |
| 141 void ExtractColor(const CupsPrinter& printer, |
| 142 PrinterSemanticCapsAndDefaults* printer_info) { |
| 143 std::vector<base::StringPiece> color_modes = |
| 144 printer.GetSupportedOptionValueStrings(kIppColor); |
| 145 auto iter = std::find(color_modes.begin(), color_modes.end(), |
| 146 CUPS_PRINT_COLOR_MODE_COLOR); |
| 147 if (iter != color_modes.end()) { |
| 148 printer_info->color_model = COLORMODE_COLOR; |
| 149 } else { |
| 150 printer_info->color_model = UNKNOWN_COLOR_MODEL; |
| 151 } |
| 152 |
| 153 iter = std::find(color_modes.begin(), color_modes.end(), |
| 154 CUPS_PRINT_COLOR_MODE_MONOCHROME); |
| 155 if (iter != color_modes.end()) { |
| 156 printer_info->bw_model = COLORMODE_MONOCHROME; |
| 157 } else { |
| 158 printer_info->bw_model = UNKNOWN_COLOR_MODEL; |
| 159 } |
| 160 |
| 161 printer_info->color_changeable = |
| 162 (printer_info->color_model != UNKNOWN_COLOR_MODEL && |
| 163 printer_info->bw_model != UNKNOWN_COLOR_MODEL); |
| 164 |
| 165 // default color |
| 166 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppColor); |
| 167 if (attr != nullptr) { |
| 168 const char* value = ippGetString(attr, 0, NULL); |
| 169 printer_info->color_default = !base::EqualsCaseInsensitiveASCII( |
| 170 value, CUPS_PRINT_COLOR_MODE_MONOCHROME); |
| 171 } |
| 172 } |
| 173 |
| 174 PrinterSemanticCapsAndDefaults::Paper DefaultPaper(const CupsPrinter& printer) { |
| 175 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMedia); |
| 176 if (attr == nullptr) { |
| 177 return PrinterSemanticCapsAndDefaults::Paper(); |
| 178 } |
| 179 |
| 180 const char* value = ippGetString(attr, 0, NULL); |
| 181 return ParsePaper(value); |
| 182 } |
| 183 |
| 184 void ExtractPaper(const CupsPrinter& printer, |
| 185 PrinterSemanticCapsAndDefaults* printer_info) { |
| 186 // paper |
| 187 std::vector<base::StringPiece> papers = |
| 188 printer.GetSupportedOptionValueStrings(kIppMedia); |
| 189 for (base::StringPiece paper : papers) { |
| 190 PrinterSemanticCapsAndDefaults::Paper p = ParsePaper(paper); |
| 191 printer_info->papers.push_back(p); |
| 192 } |
| 193 |
| 194 // default paper |
| 195 printer_info->default_paper = DefaultPaper(printer); |
| 196 } |
| 197 |
| 198 void ExtractCopies(const CupsPrinter& printer, |
| 199 PrinterSemanticCapsAndDefaults* printer_info) { |
| 200 // copies |
| 201 ipp_attribute_t* attr = printer.GetSupportedOptionValues(kIppCopies); |
| 202 if (attr != nullptr) { |
| 203 int upper_bound; |
| 204 int lower_bound = ippGetRange(attr, 0, &upper_bound); |
| 205 printer_info->copies_capable = (lower_bound != -1) && (upper_bound >= 2); |
| 206 } else { |
| 207 printer_info->copies_capable = false; |
| 208 } |
| 209 } |
| 210 |
| 211 void ExtractCollate(const CupsPrinter& printer, |
| 212 PrinterSemanticCapsAndDefaults* printer_info) { |
| 213 ipp_attribute_t* attr; |
| 214 |
| 215 // collate |
| 216 std::vector<base::StringPiece> values = |
| 217 printer.GetSupportedOptionValueStrings(kIppCollate); |
| 218 auto iter = std::find(values.begin(), values.end(), "collated"); |
| 219 printer_info->collate_capable = iter != values.end(); |
| 220 |
| 221 // collate default |
| 222 attr = printer.GetDefaultOptionValue(kIppCollate); |
| 223 if (attr != nullptr) { |
| 224 base::StringPiece name = ippGetString(attr, 0, NULL); |
| 225 printer_info->collate_default = name.compare("collated") == 0; |
| 226 } else { |
| 227 printer_info->collate_default = false; |
| 228 } |
| 229 } |
| 230 |
| 231 void ExtractDuplex(const CupsPrinter& printer, |
| 232 PrinterSemanticCapsAndDefaults* printer_info) { |
| 233 printer_info->duplex_capable = |
| 234 PrinterSupportsValue(printer, kIppDuplex, CUPS_SIDES_TWO_SIDED_PORTRAIT); |
| 235 printer_info->duplex_default = PrinterDefaultDuplex(printer); |
| 236 } |
| 237 |
| 238 } // namespace printing |
OLD | NEW |