Chromium Code Reviews| 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..91169ce4cab3d8c37c0d5d0b9a00b0b66e515286 |
| --- /dev/null |
| +++ b/printing/backend/cups_ipp_util.cc |
| @@ -0,0 +1,289 @@ |
| +// 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 <map> |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "base/logging.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, |
| +}; |
| + |
| +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.
|
| + {CUPS_PRINT_COLOR_MODE_COLOR, COLORMODE_COLOR}, |
| + {CUPS_PRINT_COLOR_MODE_MONOCHROME, COLORMODE_MONOCHROME}, |
| +}; |
| + |
| +ColorModel ColorModelFromIppColor(base::StringPiece ippColor) { |
| + auto found = kColorMap.find(ippColor); |
| + return found == kColorMap.end() ? UNKNOWN_COLOR_MODEL : found->second; |
| +} |
| + |
| +bool PrinterSupportsValue(const CupsPrinter& printer, |
| + base::StringPiece name, |
| + base::StringPiece value) { |
| + std::vector<base::StringPiece> values = |
| + printer.GetSupportedOptionValueStrings(name); |
| + auto iter = std::find(values.begin(), values.end(), value); |
| + return iter != values.end(); |
| +} |
| + |
| +DuplexMode PrinterDefaultDuplex(const CupsPrinter& 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); |
| + if (pieces.size() < 2) { |
| + // we expect at least a display string and a dimension string |
| + 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 CupsPrinter& 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); |
| +} |
| + |
| +void ExtractCopies(const CupsPrinter& 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); |
| +} |
| + |
| +} // anonymous namespace |
|
Lei Zhang
2016/07/19 22:26:39
no "anonymous "
skau
2016/07/20 23:58:22
Done.
|
| + |
| +ColorModel DefaultColorModel(const CupsPrinter& printer) { |
| + // default color |
| + ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppColor); |
| + if (!attr) |
| + return UNKNOWN_COLOR_MODEL; |
| + |
| + 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.
|
| + return ColorModelFromIppColor(value); |
| +} |
| + |
| +std::vector<ColorModel> SupportedColorModels(const CupsPrinter& 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 CupsPrinter& printer) { |
| + ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMedia); |
| + if (!attr) |
| + return PrinterSemanticCapsAndDefaults::Paper(); |
| + |
| + const char* value = ippGetString(attr, 0, nullptr); |
| + return ParsePaper(value); |
| +} |
| + |
| +std::vector<PrinterSemanticCapsAndDefaults::Paper> SupportedPapers( |
| + const CupsPrinter& printer) { |
| + std::vector<base::StringPiece> papers = |
| + printer.GetSupportedOptionValueStrings(kIppMedia); |
| + std::vector<PrinterSemanticCapsAndDefaults::Paper> parsed_papers; |
| + for (base::StringPiece paper : papers) { |
| + 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.
|
| + parsed_papers.push_back(p); |
| + } |
| + |
| + return parsed_papers; |
| +} |
| + |
| +void CopiesRange(const CupsPrinter& printer, |
| + int* lower_bound, |
| + int* upper_bound) { |
| + ipp_attribute_t* attr = printer.GetSupportedOptionValues(kIppCopies); |
| + 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.
|
| + *lower_bound = -1; |
| + *upper_bound = -1; |
| + } |
| + |
| + *lower_bound = ippGetRange(attr, 0, upper_bound); |
| +} |
| + |
| +bool CollateCapable(const CupsPrinter& printer) { |
| + std::vector<base::StringPiece> values = |
| + printer.GetSupportedOptionValueStrings(kIppCollate); |
| + 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.
|
| + return iter != values.end(); |
| +} |
| + |
| +bool CollateDefault(const CupsPrinter& 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 CupsPrinter& 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 |