Index: printing/backend/cups_ipp_util.cc |
diff --git a/printing/backend/cups_ipp_util.cc b/printing/backend/cups_ipp_util.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..49f02d08a7a41b0d05308aa37340d3ea7f958710 |
--- /dev/null |
+++ b/printing/backend/cups_ipp_util.cc |
@@ -0,0 +1,298 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "printing/backend/cups_ipp_util.h" |
+ |
+#include <cups/cups.h> |
+ |
+#include <algorithm> |
+#include <string> |
+#include <vector> |
+ |
+#include "base/logging.h" |
+#include "base/stl_util.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/strings/string_piece.h" |
+#include "base/strings/string_split.h" |
+#include "base/strings/string_util.h" |
+#include "printing/backend/cups_printer.h" |
+#include "printing/backend/print_backend_consts.h" |
+#include "printing/units.h" |
+ |
+namespace printing { |
+ |
+namespace { |
+ |
+const char kIppCollate[] = "sheet-collate"; // RFC 3381 |
+const char kIppCopies[] = CUPS_COPIES; |
+const char kIppColor[] = CUPS_PRINT_COLOR_MODE; |
+const char kIppMedia[] = CUPS_MEDIA; |
+const char kIppDuplex[] = CUPS_SIDES; |
+ |
+const char kCollated[] = "collated"; |
+ |
+const int kMicronsPerMM = 1000; |
+const double kMMPerInch = 25.4; |
+const double kMicronsPerInch = kMMPerInch * kMicronsPerMM; |
+ |
+enum Unit { |
+ INCHES, |
+ MILLIMETERS, |
+}; |
+ |
+struct ColorMap { |
+ const char* color; |
+ ColorModel model; |
+}; |
+ |
+const ColorMap kColorList[]{ |
+ {CUPS_PRINT_COLOR_MODE_COLOR, COLORMODE_COLOR}, |
+ {CUPS_PRINT_COLOR_MODE_MONOCHROME, COLORMODE_MONOCHROME}, |
+}; |
+ |
+ColorModel ColorModelFromIppColor(base::StringPiece ippColor) { |
+ for (const ColorMap& color : kColorList) { |
+ if (ippColor.compare(color.color) == 0) { |
+ return color.model; |
+ } |
+ } |
+ |
+ return UNKNOWN_COLOR_MODEL; |
+} |
+ |
+bool PrinterSupportsValue(const CupsOptionProvider& printer, |
+ base::StringPiece name, |
+ base::StringPiece value) { |
+ std::vector<base::StringPiece> values = |
+ printer.GetSupportedOptionValueStrings(name); |
+ return ContainsValue(values, value); |
+} |
+ |
+DuplexMode PrinterDefaultDuplex(const CupsOptionProvider& printer) { |
+ ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppDuplex); |
+ if (!attr) |
+ return UNKNOWN_DUPLEX_MODE; |
+ |
+ const char* value = ippGetString(attr, 0, nullptr); |
+ if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_ONE_SIDED)) |
+ return SIMPLEX; |
+ |
+ if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_PORTRAIT)) |
+ return LONG_EDGE; |
+ |
+ if (base::EqualsCaseInsensitiveASCII(value, CUPS_SIDES_TWO_SIDED_LANDSCAPE)) |
+ return SHORT_EDGE; |
+ |
+ return UNKNOWN_DUPLEX_MODE; |
+} |
+ |
+gfx::Size DimensionsToMicrons(base::StringPiece value) { |
+ Unit unit; |
+ base::StringPiece dims; |
+ size_t unit_position; |
+ if ((unit_position = value.find("mm")) != base::StringPiece::npos) { |
+ unit = MILLIMETERS; |
+ dims = value.substr(0, unit_position); |
+ } else if ((unit_position = value.find("in")) != base::StringPiece::npos) { |
+ unit = INCHES; |
+ dims = value.substr(0, unit_position); |
+ } else { |
+ LOG(WARNING) << "Could not parse paper dimensions"; |
+ return {0, 0}; |
+ } |
+ |
+ std::vector<std::string> pieces = base::SplitString( |
+ dims, "x", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
+ double width; |
+ double height; |
+ |
+ if (pieces.size() != 2 || !base::StringToDouble(pieces[0], &width) || |
+ !base::StringToDouble(pieces[1], &height)) { |
+ return {0, 0}; |
+ } |
+ |
+ int width_microns; |
+ int height_microns; |
+ |
+ switch (unit) { |
+ case MILLIMETERS: |
+ width_microns = width * kMicronsPerMM; |
+ height_microns = height * kMicronsPerMM; |
+ break; |
+ case INCHES: |
+ width_microns = width * kMicronsPerInch; |
+ height_microns = height * kMicronsPerInch; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ |
+ return gfx::Size{width_microns, height_microns}; |
+} |
+ |
+PrinterSemanticCapsAndDefaults::Paper ParsePaper(base::StringPiece value) { |
+ // <name>_<width>x<height>{in,mm} |
+ // e.g. na_letter_8.5x11in, iso_a4_210x297mm |
+ |
+ std::vector<base::StringPiece> pieces = base::SplitStringPiece( |
+ value, "_", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
+ // we expect at least a display string and a dimension string |
+ if (pieces.size() < 2) |
+ return PrinterSemanticCapsAndDefaults::Paper(); |
+ |
+ base::StringPiece dimensions = pieces.back(); |
+ |
+ std::string display = pieces[0].as_string(); |
+ for (size_t i = 1; i <= pieces.size() - 2; ++i) { |
+ display.append(" "); |
+ pieces[i].AppendToString(&display); |
+ } |
+ |
+ PrinterSemanticCapsAndDefaults::Paper paper; |
+ paper.display_name = display; |
+ paper.vendor_id = value.as_string(); |
+ paper.size_um = DimensionsToMicrons(dimensions); |
+ |
+ return paper; |
+} |
+ |
+void ExtractColor(const CupsOptionProvider& printer, |
+ PrinterSemanticCapsAndDefaults* printer_info) { |
+ printer_info->bw_model = UNKNOWN_COLOR_MODEL; |
+ printer_info->color_model = UNKNOWN_COLOR_MODEL; |
+ |
+ // color and b&w |
+ std::vector<ColorModel> color_models = SupportedColorModels(printer); |
+ for (ColorModel color : color_models) { |
+ switch (color) { |
+ case COLORMODE_COLOR: |
+ printer_info->color_model = COLORMODE_COLOR; |
+ break; |
+ case COLORMODE_MONOCHROME: |
+ printer_info->bw_model = COLORMODE_MONOCHROME; |
+ break; |
+ default: |
+ // value not needed |
+ break; |
+ } |
+ } |
+ |
+ // changeable |
+ printer_info->color_changeable = |
+ (printer_info->color_model != UNKNOWN_COLOR_MODEL && |
+ printer_info->bw_model != UNKNOWN_COLOR_MODEL); |
+ |
+ // default color |
+ printer_info->color_default = DefaultColorModel(printer) == COLORMODE_COLOR; |
+} |
+ |
+void ExtractCopies(const CupsOptionProvider& printer, |
+ PrinterSemanticCapsAndDefaults* printer_info) { |
+ // copies |
+ int upper_bound; |
+ int lower_bound; |
+ CopiesRange(printer, &lower_bound, &upper_bound); |
+ printer_info->copies_capable = (lower_bound != -1) && (upper_bound >= 2); |
+} |
+ |
+} // namespace |
+ |
+ColorModel DefaultColorModel(const CupsOptionProvider& printer) { |
+ // default color |
+ ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppColor); |
+ if (!attr) |
+ return UNKNOWN_COLOR_MODEL; |
+ |
+ return ColorModelFromIppColor(ippGetString(attr, 0, nullptr)); |
+} |
+ |
+std::vector<ColorModel> SupportedColorModels( |
+ const CupsOptionProvider& printer) { |
+ std::vector<ColorModel> colors; |
+ |
+ std::vector<base::StringPiece> color_modes = |
+ printer.GetSupportedOptionValueStrings(kIppColor); |
+ |
+ for (base::StringPiece color : color_modes) { |
+ ColorModel color_model = ColorModelFromIppColor(color); |
+ if (color_model != UNKNOWN_COLOR_MODEL) { |
+ colors.push_back(color_model); |
+ } |
+ } |
+ |
+ return colors; |
+} |
+ |
+PrinterSemanticCapsAndDefaults::Paper DefaultPaper( |
+ const CupsOptionProvider& printer) { |
+ ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMedia); |
+ if (!attr) |
+ return PrinterSemanticCapsAndDefaults::Paper(); |
+ |
+ return ParsePaper(ippGetString(attr, 0, nullptr)); |
+} |
+ |
+std::vector<PrinterSemanticCapsAndDefaults::Paper> SupportedPapers( |
+ const CupsOptionProvider& printer) { |
+ std::vector<base::StringPiece> papers = |
+ printer.GetSupportedOptionValueStrings(kIppMedia); |
+ std::vector<PrinterSemanticCapsAndDefaults::Paper> parsed_papers; |
+ for (base::StringPiece paper : papers) { |
+ parsed_papers.push_back(ParsePaper(paper)); |
+ } |
+ |
+ return parsed_papers; |
+} |
+ |
+void CopiesRange(const CupsOptionProvider& printer, |
+ int* lower_bound, |
+ int* upper_bound) { |
+ ipp_attribute_t* attr = printer.GetSupportedOptionValues(kIppCopies); |
+ if (!attr) { |
+ *lower_bound = -1; |
+ *upper_bound = -1; |
+ } |
+ |
+ *lower_bound = ippGetRange(attr, 0, upper_bound); |
+} |
+ |
+bool CollateCapable(const CupsOptionProvider& printer) { |
+ std::vector<base::StringPiece> values = |
+ printer.GetSupportedOptionValueStrings(kIppCollate); |
+ auto iter = std::find(values.begin(), values.end(), kCollated); |
+ return iter != values.end(); |
+} |
+ |
+bool CollateDefault(const CupsOptionProvider& printer) { |
+ ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppCollate); |
+ if (!attr) |
+ return false; |
+ |
+ base::StringPiece name = ippGetString(attr, 0, nullptr); |
+ return name.compare(kCollated) == 0; |
+} |
+ |
+void CapsAndDefaultsFromPrinter(const CupsOptionProvider& printer, |
+ PrinterSemanticCapsAndDefaults* printer_info) { |
+ // duplex |
+ printer_info->duplex_default = PrinterDefaultDuplex(printer); |
+ printer_info->duplex_capable = |
+ PrinterSupportsValue(printer, kIppDuplex, CUPS_SIDES_TWO_SIDED_PORTRAIT); |
+ |
+ // collate |
+ printer_info->collate_default = CollateDefault(printer); |
+ printer_info->collate_capable = CollateCapable(printer); |
+ |
+ // paper |
+ printer_info->default_paper = DefaultPaper(printer); |
+ printer_info->papers = SupportedPapers(printer); |
+ |
+ ExtractCopies(printer, printer_info); |
+ ExtractColor(printer, printer_info); |
+ |
+ // TODO(skau): Add dpi and default_dpi |
+} |
+ |
+} // namespace printing |