| Index: printing/backend/cups_helper.cc
|
| ===================================================================
|
| --- printing/backend/cups_helper.cc (revision 153539)
|
| +++ printing/backend/cups_helper.cc (working copy)
|
| @@ -4,9 +4,297 @@
|
|
|
| #include "printing/backend/cups_helper.h"
|
|
|
| +#include "base/file_util.h"
|
| #include "base/logging.h"
|
| +#include "base/string_number_conversions.h"
|
| +#include "base/string_split.h"
|
| +#include "base/string_util.h"
|
| +#include "base/values.h"
|
| #include "googleurl/src/gurl.h"
|
| +#include "printing/backend/print_backend.h"
|
| +#include "printing/backend/print_backend_consts.h"
|
|
|
| +// This section contains helper code for PPD parsing for semantic capabilities.
|
| +namespace {
|
| +
|
| +const char kColorDevice[] = "ColorDevice";
|
| +const char kColorModel[] = "ColorModel";
|
| +const char kColorMode[] = "ColorMode";
|
| +const char kProcessColorModel[] = "ProcessColorModel";
|
| +const char kPrintoutMode[] = "PrintoutMode";
|
| +const char kDraftGray[] = "Draft.Gray";
|
| +const char kHighGray[] = "High.Gray";
|
| +
|
| +const char kDuplex[] = "Duplex";
|
| +const char kDuplexNone[] = "None";
|
| +
|
| +#if !defined(OS_MACOSX)
|
| +void ParseLpOptions(const FilePath& filepath, const std::string& printer_name,
|
| + int* num_options, cups_option_t** options) {
|
| + std::string content;
|
| + if (!file_util::ReadFileToString(filepath, &content))
|
| + return;
|
| +
|
| + const char kDest[] = "dest";
|
| + const char kDefault[] = "default";
|
| + const size_t kDestLen = sizeof(kDest) - 1;
|
| + const size_t kDefaultLen = sizeof(kDefault) - 1;
|
| + std::vector<std::string> lines;
|
| + base::SplitString(content, '\n', &lines);
|
| +
|
| + for (size_t i = 0; i < lines.size(); ++i) {
|
| + std::string line = lines[i];
|
| + if (line.empty())
|
| + continue;
|
| +
|
| + if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 &&
|
| + isspace(line[kDefaultLen])) {
|
| + line = line.substr(kDefaultLen);
|
| + } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 &&
|
| + isspace(line[kDestLen])) {
|
| + line = line.substr(kDestLen);
|
| + } else {
|
| + continue;
|
| + }
|
| +
|
| + TrimWhitespaceASCII(line, TRIM_ALL, &line);
|
| + if (line.empty())
|
| + continue;
|
| +
|
| + size_t space_found = line.find(' ');
|
| + if (space_found == std::string::npos)
|
| + continue;
|
| +
|
| + std::string name = line.substr(0, space_found);
|
| + if (name.empty())
|
| + continue;
|
| +
|
| + if (base::strncasecmp(printer_name.c_str(), name.c_str(),
|
| + name.length()) != 0) {
|
| + continue; // This is not the required printer.
|
| + }
|
| +
|
| + line = line.substr(space_found + 1);
|
| + TrimWhitespaceASCII(line, TRIM_ALL, &line); // Remove extra spaces.
|
| + if (line.empty())
|
| + continue;
|
| + // Parse the selected printer custom options.
|
| + *num_options = cupsParseOptions(line.c_str(), 0, options);
|
| + }
|
| +}
|
| +
|
| +void MarkLpOptions(const std::string& printer_name, ppd_file_t** ppd) {
|
| + cups_option_t* options = NULL;
|
| + int num_options = 0;
|
| + ppdMarkDefaults(*ppd);
|
| +
|
| + const char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
|
| + const char kUserLpOptionPath[] = ".cups/lpoptions";
|
| +
|
| + std::vector<FilePath> file_locations;
|
| + file_locations.push_back(FilePath(kSystemLpOptionPath));
|
| + file_locations.push_back(FilePath(
|
| + file_util::GetHomeDir().Append(kUserLpOptionPath)));
|
| +
|
| + for (std::vector<FilePath>::const_iterator it = file_locations.begin();
|
| + it != file_locations.end(); ++it) {
|
| + num_options = 0;
|
| + options = NULL;
|
| + ParseLpOptions(*it, printer_name, &num_options, &options);
|
| + if (num_options > 0 && options) {
|
| + cupsMarkOptions(*ppd, num_options, options);
|
| + cupsFreeOptions(num_options, options);
|
| + }
|
| + }
|
| +}
|
| +#endif // !defined(OS_MACOSX)
|
| +
|
| +bool GetBasicColorModelSettings(ppd_file_t* ppd,
|
| + int* color_model_for_black,
|
| + int* color_model_for_color,
|
| + bool* color_is_default) {
|
| + ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
|
| + if (!color_model)
|
| + return false;
|
| +
|
| + if (ppdFindChoice(color_model, printing::kBlack))
|
| + *color_model_for_black = printing::BLACK;
|
| + else if (ppdFindChoice(color_model, printing::kGray))
|
| + *color_model_for_black = printing::GRAY;
|
| + else if (ppdFindChoice(color_model, printing::kGrayscale))
|
| + *color_model_for_black = printing::GRAYSCALE;
|
| +
|
| + if (ppdFindChoice(color_model, printing::kColor))
|
| + *color_model_for_color = printing::COLOR;
|
| + else if (ppdFindChoice(color_model, printing::kCMYK))
|
| + *color_model_for_color = printing::CMYK;
|
| + else if (ppdFindChoice(color_model, printing::kRGB))
|
| + *color_model_for_color = printing::RGB;
|
| + else if (ppdFindChoice(color_model, printing::kRGBA))
|
| + *color_model_for_color = printing::RGBA;
|
| + else if (ppdFindChoice(color_model, printing::kRGB16))
|
| + *color_model_for_color = printing::RGB16;
|
| + else if (ppdFindChoice(color_model, printing::kCMY))
|
| + *color_model_for_color = printing::CMY;
|
| + else if (ppdFindChoice(color_model, printing::kKCMY))
|
| + *color_model_for_color = printing::KCMY;
|
| + else if (ppdFindChoice(color_model, printing::kCMY_K))
|
| + *color_model_for_color = printing::CMY_K;
|
| +
|
| + ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
|
| + if (!marked_choice)
|
| + marked_choice = ppdFindChoice(color_model, color_model->defchoice);
|
| +
|
| + if (marked_choice) {
|
| + *color_is_default =
|
| + (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) &&
|
| + (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) &&
|
| + (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetPrintOutModeColorSettings(ppd_file_t* ppd,
|
| + int* color_model_for_black,
|
| + int* color_model_for_color,
|
| + bool* color_is_default) {
|
| + ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
|
| + if (!printout_mode)
|
| + return false;
|
| +
|
| + *color_model_for_color = printing::PRINTOUTMODE_NORMAL;
|
| + *color_model_for_black = printing::PRINTOUTMODE_NORMAL;
|
| +
|
| + // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
|
| + // If NORMAL_GRAY is not supported, NORMAL value is used to
|
| + // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
|
| + // represent color.
|
| + if (ppdFindChoice(printout_mode, printing::kNormalGray))
|
| + *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
|
| +
|
| + // Get the default marked choice to identify the default color setting
|
| + // value.
|
| + ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
|
| + if (!printout_mode_choice) {
|
| + printout_mode_choice = ppdFindChoice(printout_mode,
|
| + printout_mode->defchoice);
|
| + }
|
| + if (printout_mode_choice) {
|
| + if ((base::strcasecmp(printout_mode_choice->choice,
|
| + printing::kNormalGray) == 0) ||
|
| + (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) ||
|
| + (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) {
|
| + *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
|
| + *color_is_default = false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetColorModeSettings(ppd_file_t* ppd,
|
| + int* color_model_for_black,
|
| + int* color_model_for_color,
|
| + bool* color_is_default) {
|
| + // Samsung printers use "ColorMode" attribute in their ppds.
|
| + ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
|
| + if (!color_mode_option)
|
| + return false;
|
| +
|
| + if (ppdFindChoice(color_mode_option, printing::kColor))
|
| + *color_model_for_color = printing::COLORMODE_COLOR;
|
| +
|
| + if (ppdFindChoice(color_mode_option, printing::kMonochrome))
|
| + *color_model_for_black = printing::COLORMODE_MONOCHROME;
|
| +
|
| + ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
|
| + if (!mode_choice) {
|
| + mode_choice = ppdFindChoice(color_mode_option,
|
| + color_mode_option->defchoice);
|
| + }
|
| +
|
| + if (mode_choice) {
|
| + *color_is_default =
|
| + (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetHPColorSettings(ppd_file_t* ppd,
|
| + int* color_model_for_black,
|
| + int* color_model_for_color,
|
| + bool* color_is_default) {
|
| + // HP printers use "Color/Color Model" attribute in their ppds.
|
| + ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor);
|
| + if (!color_mode_option)
|
| + return false;
|
| +
|
| + if (ppdFindChoice(color_mode_option, printing::kColor))
|
| + *color_model_for_color = printing::HP_COLOR_COLOR;
|
| + if (ppdFindChoice(color_mode_option, printing::kBlack))
|
| + *color_model_for_black = printing::HP_COLOR_BLACK;
|
| +
|
| + ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
|
| + if (!mode_choice) {
|
| + mode_choice = ppdFindChoice(color_mode_option,
|
| + color_mode_option->defchoice);
|
| + }
|
| + if (mode_choice) {
|
| + *color_is_default =
|
| + (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetProcessColorModelSettings(ppd_file_t* ppd,
|
| + int* color_model_for_black,
|
| + int* color_model_for_color,
|
| + bool* color_is_default) {
|
| + // Canon printers use "ProcessColorModel" attribute in their ppds.
|
| + ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
|
| + if (!color_mode_option)
|
| + return false;
|
| +
|
| + if (ppdFindChoice(color_mode_option, printing::kRGB))
|
| + *color_model_for_color = printing::PROCESSCOLORMODEL_RGB;
|
| + else if (ppdFindChoice(color_mode_option, printing::kCMYK))
|
| + *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK;
|
| +
|
| + if (ppdFindChoice(color_mode_option, printing::kGreyscale))
|
| + *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE;
|
| +
|
| + ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
|
| + if (!mode_choice) {
|
| + mode_choice = ppdFindChoice(color_mode_option,
|
| + color_mode_option->defchoice);
|
| + }
|
| +
|
| + if (mode_choice) {
|
| + *color_is_default =
|
| + (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GetColorModelSettings(ppd_file_t* ppd,
|
| + int* cm_black,
|
| + int* cm_color,
|
| + bool* is_color) {
|
| + bool is_color_device = false;
|
| + ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
|
| + if (attr && attr->value)
|
| + is_color_device = ppd->color_device;
|
| +
|
| + *is_color = is_color_device;
|
| + return (is_color_device &&
|
| + GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) ||
|
| + GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
|
| + GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
|
| + GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
|
| + GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace printing {
|
|
|
| // Default port for IPP print servers.
|
| @@ -46,4 +334,60 @@
|
| return http_;
|
| }
|
|
|
| +bool parsePpdCapabilities(
|
| + const std::string& printer_name,
|
| + const std::string& printer_capabilities,
|
| + PrinterSemanticCapsAndDefaults* printer_info) {
|
| + FilePath ppd_file_path;
|
| + if (!file_util::CreateTemporaryFile(&ppd_file_path))
|
| + return false;
|
| +
|
| + int data_size = printer_capabilities.length();
|
| + if (data_size != file_util::WriteFile(
|
| + ppd_file_path,
|
| + printer_capabilities.data(),
|
| + data_size)) {
|
| + file_util::Delete(ppd_file_path, false);
|
| + return false;
|
| + }
|
| +
|
| + ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str());
|
| + if (!ppd)
|
| + return false;
|
| +
|
| + printing::PrinterSemanticCapsAndDefaults caps;
|
| +#if !defined(OS_MACOSX)
|
| + MarkLpOptions(printer_name, &ppd);
|
| +#endif
|
| + ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex);
|
| + if (!duplex_choice) {
|
| + ppd_option_t* option = ppdFindOption(ppd, kDuplex);
|
| + if (option)
|
| + duplex_choice = ppdFindChoice(option, option->defchoice);
|
| + }
|
| +
|
| + if (duplex_choice) {
|
| + caps.duplex_capable = true;
|
| + if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0)
|
| + caps.duplex_default = printing::LONG_EDGE;
|
| + else
|
| + caps.duplex_default = printing::SIMPLEX;
|
| + }
|
| +
|
| + bool is_color = false;
|
| + int cm_color = 0, cm_black = 0;
|
| + if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) {
|
| + VLOG(1) << "Unknown printer color model";
|
| + }
|
| +
|
| + caps.color_capable = (cm_color && cm_black && (cm_color != cm_black));
|
| + caps.color_default = is_color;
|
| +
|
| + ppdClose(ppd);
|
| + file_util::Delete(ppd_file_path, false);
|
| +
|
| + *printer_info = caps;
|
| + return true;
|
| +}
|
| +
|
| } // namespace printing
|
|
|