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 <map> | |
11 #include <string> | |
12 #include <vector> | |
13 | |
14 #include "base/logging.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "base/strings/string_piece.h" | |
17 #include "base/strings/string_split.h" | |
18 #include "base/strings/string_util.h" | |
19 #include "printing/backend/cups_printer.h" | |
20 #include "printing/backend/print_backend_consts.h" | |
21 #include "printing/units.h" | |
22 | |
23 namespace printing { | |
24 | |
25 namespace { | |
26 | |
27 const char kIppCollate[] = "sheet-collate"; // RFC 3381 | |
28 const char kIppCopies[] = CUPS_COPIES; | |
29 const char kIppColor[] = CUPS_PRINT_COLOR_MODE; | |
30 const char kIppMedia[] = CUPS_MEDIA; | |
31 const char kIppDuplex[] = CUPS_SIDES; | |
32 | |
33 const char kCollated[] = "collated"; | |
34 | |
35 const int kMicronsPerMM = 1000; | |
36 const double kMMPerInch = 25.4; | |
37 const double kMicronsPerInch = kMMPerInch * kMicronsPerMM; | |
38 | |
39 enum Unit { | |
40 INCHES, | |
41 MILLIMETERS, | |
42 }; | |
43 | |
44 const std::map<const base::StringPiece, ColorModel> kColorMap{ | |
Lei Zhang
2016/07/19 22:26:39
Can't do this. It adds a static initializer. Given
skau
2016/07/20 23:58:22
Thanks. That works well.
| |
45 {CUPS_PRINT_COLOR_MODE_COLOR, COLORMODE_COLOR}, | |
46 {CUPS_PRINT_COLOR_MODE_MONOCHROME, COLORMODE_MONOCHROME}, | |
47 }; | |
48 | |
49 ColorModel ColorModelFromIppColor(base::StringPiece ippColor) { | |
50 auto found = kColorMap.find(ippColor); | |
51 return found == kColorMap.end() ? UNKNOWN_COLOR_MODEL : found->second; | |
52 } | |
53 | |
54 bool PrinterSupportsValue(const CupsPrinter& printer, | |
55 base::StringPiece name, | |
56 base::StringPiece value) { | |
57 std::vector<base::StringPiece> values = | |
58 printer.GetSupportedOptionValueStrings(name); | |
59 auto iter = std::find(values.begin(), values.end(), value); | |
60 return iter != values.end(); | |
61 } | |
62 | |
63 DuplexMode PrinterDefaultDuplex(const CupsPrinter& printer) { | |
64 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppDuplex); | |
65 if (!attr) | |
66 return UNKNOWN_DUPLEX_MODE; | |
67 | |
68 const char* value = ippGetString(attr, 0, nullptr); | |
69 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_ONE_SIDED)) | |
70 return SIMPLEX; | |
71 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_PORTRAIT)) | |
72 return LONG_EDGE; | |
73 if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_LANDSCAPE)) | |
74 return SHORT_EDGE; | |
75 | |
76 return UNKNOWN_DUPLEX_MODE; | |
77 } | |
78 | |
79 gfx::Size DimensionsToMicrons(base::StringPiece value) { | |
80 Unit unit; | |
81 base::StringPiece dims; | |
82 size_t unit_position; | |
83 if ((unit_position = value.find("mm")) != base::StringPiece::npos) { | |
84 unit = MILLIMETERS; | |
85 dims = value.substr(0, unit_position); | |
86 } else if ((unit_position = value.find("in")) != base::StringPiece::npos) { | |
87 unit = INCHES; | |
88 dims = value.substr(0, unit_position); | |
89 } else { | |
90 LOG(WARNING) << "Could not parse paper dimensions"; | |
91 return {0, 0}; | |
92 } | |
93 | |
94 std::vector<std::string> pieces = base::SplitString( | |
95 dims, "x", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
96 double width; | |
97 double height; | |
98 | |
99 if (pieces.size() != 2 || !base::StringToDouble(pieces[0], &width) || | |
100 !base::StringToDouble(pieces[1], &height)) { | |
101 return {0, 0}; | |
102 } | |
103 | |
104 int width_microns; | |
105 int height_microns; | |
106 | |
107 switch (unit) { | |
108 case MILLIMETERS: | |
109 width_microns = width * kMicronsPerMM; | |
110 height_microns = height * kMicronsPerMM; | |
111 break; | |
112 case INCHES: | |
113 width_microns = width * kMicronsPerInch; | |
114 height_microns = height * kMicronsPerInch; | |
115 break; | |
116 default: | |
117 NOTREACHED(); | |
118 break; | |
119 } | |
120 | |
121 return gfx::Size{width_microns, height_microns}; | |
122 } | |
123 | |
124 PrinterSemanticCapsAndDefaults::Paper ParsePaper(base::StringPiece value) { | |
125 // <name>_<width>x<height>{in,mm} | |
126 // e.g. na_letter_8.5x11in, iso_a4_210x297mm | |
127 | |
128 std::vector<base::StringPiece> pieces = base::SplitStringPiece( | |
129 value, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
130 if (pieces.size() < 2) { | |
131 // we expect at least a display string and a dimension string | |
132 return PrinterSemanticCapsAndDefaults::Paper(); | |
133 } | |
134 | |
135 base::StringPiece dimensions = pieces.back(); | |
136 | |
137 std::string display = pieces[0].as_string(); | |
138 for (size_t i = 1; i <= pieces.size() - 2; ++i) { | |
139 display.append(" "); | |
140 pieces[i].AppendToString(&display); | |
141 } | |
142 | |
143 PrinterSemanticCapsAndDefaults::Paper paper; | |
144 paper.display_name = display; | |
145 paper.vendor_id = value.as_string(); | |
146 paper.size_um = DimensionsToMicrons(dimensions); | |
147 | |
148 return paper; | |
149 } | |
150 | |
151 void ExtractColor(const CupsPrinter& printer, | |
152 PrinterSemanticCapsAndDefaults* printer_info) { | |
153 printer_info->bw_model = UNKNOWN_COLOR_MODEL; | |
154 printer_info->color_model = UNKNOWN_COLOR_MODEL; | |
155 | |
156 // color and b&w | |
157 std::vector<ColorModel> color_models = SupportedColorModels(printer); | |
158 for (ColorModel color : color_models) { | |
159 switch (color) { | |
160 case COLORMODE_COLOR: | |
161 printer_info->color_model = COLORMODE_COLOR; | |
162 break; | |
163 case COLORMODE_MONOCHROME: | |
164 printer_info->bw_model = COLORMODE_MONOCHROME; | |
165 break; | |
166 default: | |
167 // value not needed | |
168 break; | |
169 } | |
170 } | |
171 | |
172 // changeable | |
173 printer_info->color_changeable = | |
174 (printer_info->color_model != UNKNOWN_COLOR_MODEL && | |
175 printer_info->bw_model != UNKNOWN_COLOR_MODEL); | |
176 | |
177 // default color | |
178 printer_info->color_default = DefaultColorModel(printer); | |
179 } | |
180 | |
181 void ExtractCopies(const CupsPrinter& printer, | |
182 PrinterSemanticCapsAndDefaults* printer_info) { | |
183 // copies | |
184 int upper_bound; | |
185 int lower_bound; | |
186 CopiesRange(printer, &lower_bound, &upper_bound); | |
187 printer_info->copies_capable = (lower_bound != -1) && (upper_bound >= 2); | |
188 } | |
189 | |
190 } // anonymous namespace | |
Lei Zhang
2016/07/19 22:26:39
no "anonymous "
skau
2016/07/20 23:58:22
Done.
| |
191 | |
192 ColorModel DefaultColorModel(const CupsPrinter& printer) { | |
193 // default color | |
194 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppColor); | |
195 if (!attr) | |
196 return UNKNOWN_COLOR_MODEL; | |
197 | |
198 const char* value = ippGetString(attr, 0, nullptr); | |
Lei Zhang
2016/07/19 22:26:39
Just combine with the next line and drop |value|.
skau
2016/07/20 23:58:23
Done.
| |
199 return ColorModelFromIppColor(value); | |
200 } | |
201 | |
202 std::vector<ColorModel> SupportedColorModels(const CupsPrinter& printer) { | |
203 std::vector<ColorModel> colors; | |
204 | |
205 std::vector<base::StringPiece> color_modes = | |
206 printer.GetSupportedOptionValueStrings(kIppColor); | |
207 | |
208 for (base::StringPiece color : color_modes) { | |
209 ColorModel color_model = ColorModelFromIppColor(color); | |
210 if (color_model != UNKNOWN_COLOR_MODEL) { | |
211 colors.push_back(color_model); | |
212 } | |
213 } | |
214 | |
215 return colors; | |
216 } | |
217 | |
218 PrinterSemanticCapsAndDefaults::Paper DefaultPaper(const CupsPrinter& printer) { | |
219 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMedia); | |
220 if (!attr) | |
221 return PrinterSemanticCapsAndDefaults::Paper(); | |
222 | |
223 const char* value = ippGetString(attr, 0, nullptr); | |
224 return ParsePaper(value); | |
225 } | |
226 | |
227 std::vector<PrinterSemanticCapsAndDefaults::Paper> SupportedPapers( | |
228 const CupsPrinter& printer) { | |
229 std::vector<base::StringPiece> papers = | |
230 printer.GetSupportedOptionValueStrings(kIppMedia); | |
231 std::vector<PrinterSemanticCapsAndDefaults::Paper> parsed_papers; | |
232 for (base::StringPiece paper : papers) { | |
233 PrinterSemanticCapsAndDefaults::Paper p = ParsePaper(paper); | |
Lei Zhang
2016/07/19 22:26:39
Also less wordy if it's just combined with the nex
skau
2016/07/20 23:58:23
Done.
| |
234 parsed_papers.push_back(p); | |
235 } | |
236 | |
237 return parsed_papers; | |
238 } | |
239 | |
240 void CopiesRange(const CupsPrinter& printer, | |
241 int* lower_bound, | |
242 int* upper_bound) { | |
243 ipp_attribute_t* attr = printer.GetSupportedOptionValues(kIppCopies); | |
244 if (attr) { | |
Lei Zhang
2016/07/19 22:26:39
If |attr| is nullptr, what happens? Does |lower_bo
skau
2016/07/20 23:58:22
Whoops. I'll write some unit tests.
| |
245 *lower_bound = -1; | |
246 *upper_bound = -1; | |
247 } | |
248 | |
249 *lower_bound = ippGetRange(attr, 0, upper_bound); | |
250 } | |
251 | |
252 bool CollateCapable(const CupsPrinter& printer) { | |
253 std::vector<base::StringPiece> values = | |
254 printer.GetSupportedOptionValueStrings(kIppCollate); | |
255 auto iter = std::find(values.begin(), values.end(), kCollated); | |
Lei Zhang
2016/07/19 22:26:39
Just: return ContainsValue(values, kCollated);
Sa
skau
2016/07/20 23:58:22
Thanks. I didn't know we had that.
| |
256 return iter != values.end(); | |
257 } | |
258 | |
259 bool CollateDefault(const CupsPrinter& printer) { | |
260 ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppCollate); | |
261 if (!attr) | |
262 return false; | |
263 | |
264 base::StringPiece name = ippGetString(attr, 0, nullptr); | |
265 return name.compare(kCollated) == 0; | |
266 } | |
267 | |
268 void CapsAndDefaultsFromPrinter(const CupsPrinter& printer, | |
269 PrinterSemanticCapsAndDefaults* printer_info) { | |
270 // duplex | |
271 printer_info->duplex_default = PrinterDefaultDuplex(printer); | |
272 printer_info->duplex_capable = | |
273 PrinterSupportsValue(printer, kIppDuplex, CUPS_SIDES_TWO_SIDED_PORTRAIT); | |
274 | |
275 // collate | |
276 printer_info->collate_default = CollateDefault(printer); | |
277 printer_info->collate_capable = CollateCapable(printer); | |
278 | |
279 // paper | |
280 printer_info->default_paper = DefaultPaper(printer); | |
281 printer_info->papers = SupportedPapers(printer); | |
282 | |
283 ExtractCopies(printer, printer_info); | |
284 ExtractColor(printer, printer_info); | |
285 | |
286 // TODO(skau): Add dpi and default_dpi | |
287 } | |
288 | |
289 } // namespace printing | |
OLD | NEW |