diff options
author | gene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 04:21:21 +0000 |
---|---|---|
committer | gene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-07 04:21:21 +0000 |
commit | 8b6098e412722d5b34d6a085f8fc0fd5cb78c6f5 (patch) | |
tree | b4c7a2a65a49dbf5655b43a3a96394979847f7d5 /printing | |
parent | 58df36ac048af7d31edf3b7b1bf217853c8b3c20 (diff) | |
download | chromium_src-8b6098e412722d5b34d6a085f8fc0fd5cb78c6f5.zip chromium_src-8b6098e412722d5b34d6a085f8fc0fd5cb78c6f5.tar.gz chromium_src-8b6098e412722d5b34d6a085f8fc0fd5cb78c6f5.tar.bz2 |
Get semantic capabilities from Print Backend.
Moved OS specific code into OS specific print backends (vs. print_system_task_proxy.cc).
On Windows get capabilities using native API (vs. XPS parsing)
Some clean up on code and interfaces for Print Backend.
BUG=144031
TEST=Verify Print Preview on ALL platforms (Win XP, Win 7, Linux, Mac).
Review URL: https://chromiumcodereview.appspot.com/10905006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155310 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'printing')
-rw-r--r-- | printing/backend/cups_helper.cc | 344 | ||||
-rw-r--r-- | printing/backend/cups_helper.h | 11 | ||||
-rw-r--r-- | printing/backend/cups_helper_unittest.cc | 159 | ||||
-rw-r--r-- | printing/backend/print_backend.cc | 8 | ||||
-rw-r--r-- | printing/backend/print_backend.h | 22 | ||||
-rw-r--r-- | printing/backend/print_backend_chromeos.cc | 10 | ||||
-rw-r--r-- | printing/backend/print_backend_cups.cc | 14 | ||||
-rw-r--r-- | printing/backend/print_backend_win.cc | 96 | ||||
-rw-r--r-- | printing/printing.gyp | 8 |
9 files changed, 671 insertions, 1 deletions
diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc index 7fc6983..c2251c6 100644 --- a/printing/backend/cups_helper.cc +++ b/printing/backend/cups_helper.cc @@ -4,8 +4,296 @@ #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 { @@ -46,4 +334,60 @@ http_t* HttpConnectionCUPS::http() { 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 diff --git a/printing/backend/cups_helper.h b/printing/backend/cups_helper.h index 43907bd..04ff08a 100644 --- a/printing/backend/cups_helper.h +++ b/printing/backend/cups_helper.h @@ -7,6 +7,8 @@ #include <cups/cups.h> +#include <string> + #include "printing/printing_export.h" class GURL; @@ -14,6 +16,8 @@ class GURL; // These are helper functions for dealing with CUPS. namespace printing { +struct PrinterSemanticCapsAndDefaults; + // Helper wrapper around http_t structure, with connection and cleanup // functionality. class PRINTING_EXPORT HttpConnectionCUPS { @@ -30,6 +34,13 @@ class PRINTING_EXPORT HttpConnectionCUPS { http_t* http_; }; +// Helper function to parse and convert PPD capabilitites to +// semantic options. +PRINTING_EXPORT bool parsePpdCapabilities( + const std::string& printer_name, + const std::string& printer_capabilities, + PrinterSemanticCapsAndDefaults* printer_info); + } // namespace printing #endif // PRINTING_BACKEND_CUPS_HELPER_H_ diff --git a/printing/backend/cups_helper_unittest.cc b/printing/backend/cups_helper_unittest.cc new file mode 100644 index 0000000..d83b3b7 --- /dev/null +++ b/printing/backend/cups_helper_unittest.cc @@ -0,0 +1,159 @@ +// Copyright (c) 2012 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_helper.h" +#include "printing/backend/print_backend.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexLongEdge) { + std::string test_ppd_data; + test_ppd_data.append( + "*PPD-Adobe: \"4.3\"\n\n" + "*OpenGroup: General/General\n\n" + "*OpenUI *ColorModel/Color Model: PickOne\n" + "*DefaultColorModel: Gray\n" + "*ColorModel Gray/Grayscale: \"" + "<</cupsColorSpace 0/cupsColorOrder 0>>" + "setpagedevice\"\n" + "*ColorModel Black/Inverted Grayscale: \"" + "<</cupsColorSpace 3/cupsColorOrder 0>>" + "setpagedevice\"\n" + "*CloseUI: *ColorModel\n" + "*OpenUI *Duplex/2-Sided Printing: PickOne\n" + "*DefaultDuplex: DuplexTumble\n" + "*Duplex None/Off: \"<</Duplex false>>" + "setpagedevice\"\n" + "*Duplex DuplexNoTumble/LongEdge: \"" + "<</Duplex true/Tumble false>>setpagedevice\"\n" + "*Duplex DuplexTumble/ShortEdge: \"" + "<</Duplex true/Tumble true>>setpagedevice\"\n" + "*CloseUI: *Duplex\n\n" + "*CloseGroup: General\n"); + + printing::PrinterSemanticCapsAndDefaults caps; + EXPECT_TRUE(printing::parsePpdCapabilities("test", test_ppd_data, &caps)); + EXPECT_FALSE(caps.color_capable); + EXPECT_FALSE(caps.color_default); + EXPECT_TRUE(caps.duplex_capable); + EXPECT_EQ(caps.duplex_default, printing::LONG_EDGE); +} + +// Test duplex detection code, which regressed in http://crbug.com/103999. +TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexSimples) { + std::string test_ppd_data; + test_ppd_data.append( + "*PPD-Adobe: \"4.3\"\n\n" + "*OpenGroup: General/General\n\n" + "*OpenUI *Duplex/Double-Sided Printing: PickOne\n" + "*DefaultDuplex: None\n" + "*Duplex None/Off: " + "\"<</Duplex false>>setpagedevice\"\n" + "*Duplex DuplexNoTumble/Long Edge (Standard): " + "\"<</Duplex true/Tumble false>>setpagedevice\"\n" + "*Duplex DuplexTumble/Short Edge (Flip): " + "\"<</Duplex true/Tumble true>>setpagedevice\"\n" + "*CloseUI: *Duplex\n\n" + "*CloseGroup: General\n"); + + printing::PrinterSemanticCapsAndDefaults caps; + EXPECT_TRUE(printing::parsePpdCapabilities("test", test_ppd_data, &caps)); + EXPECT_FALSE(caps.color_capable); + EXPECT_FALSE(caps.color_default); + EXPECT_TRUE(caps.duplex_capable); + EXPECT_EQ(caps.duplex_default, printing::SIMPLEX); +} + +TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorNoDuplex) { + std::string test_ppd_data; + test_ppd_data.append( + "*PPD-Adobe: \"4.3\"\n\n" + "*OpenGroup: General/General\n\n" + "*OpenUI *ColorModel/Color Model: PickOne\n" + "*DefaultColorModel: Gray\n" + "*ColorModel Gray/Grayscale: \"" + "<</cupsColorSpace 0/cupsColorOrder 0>>" + "setpagedevice\"\n" + "*ColorModel Black/Inverted Grayscale: \"" + "<</cupsColorSpace 3/cupsColorOrder 0>>" + "setpagedevice\"\n" + "*CloseUI: *ColorModel\n" + "*CloseGroup: General\n"); + + printing::PrinterSemanticCapsAndDefaults caps; + EXPECT_TRUE(printing::parsePpdCapabilities("test", test_ppd_data, &caps)); + EXPECT_FALSE(caps.color_capable); + EXPECT_FALSE(caps.color_default); + EXPECT_FALSE(caps.duplex_capable); + EXPECT_EQ(caps.duplex_default, printing::UNKNOWN_DUPLEX_MODE); +} + +TEST(PrintBackendCupsHelperTest, TestPpdParsingColorTrueDuplexLongEdge) { + std::string test_ppd_data; + test_ppd_data.append( + "*PPD-Adobe: \"4.3\"\n\n" + "*ColorDevice: True\n" + "*DefaultColorSpace: CMYK\n\n" + "*OpenGroup: General/General\n\n" + "*OpenUI *ColorModel/Color Model: PickOne\n" + "*DefaultColorModel: CMYK\n" + "*ColorModel CMYK/Color: " + "\"(cmyk) RCsetdevicecolor\"\n" + "*ColorModel Gray/Black and White: " + "\"(gray) RCsetdevicecolor\"\n" + "*CloseUI: *ColorModel\n" + "*OpenUI *Duplex/2-Sided Printing: PickOne\n" + "*DefaultDuplex: DuplexTumble\n" + "*Duplex None/Off: \"<</Duplex false>>" + "setpagedevice\"\n" + "*Duplex DuplexNoTumble/LongEdge: \"" + "<</Duplex true/Tumble false>>setpagedevice\"\n" + "*Duplex DuplexTumble/ShortEdge: \"" + "<</Duplex true/Tumble true>>setpagedevice\"\n" + "*CloseUI: *Duplex\n\n" + "*CloseGroup: General\n"); + + printing::PrinterSemanticCapsAndDefaults caps; + EXPECT_TRUE(printing::parsePpdCapabilities("test", test_ppd_data, &caps)); + EXPECT_TRUE(caps.color_capable); + EXPECT_TRUE(caps.color_default); + EXPECT_TRUE(caps.duplex_capable); + EXPECT_EQ(caps.duplex_default, printing::LONG_EDGE); +} + +TEST(PrintBackendCupsHelperTest, TestPpdParsingColorFalseDuplexLongEdge) { + std::string test_ppd_data; + test_ppd_data.append( + "*PPD-Adobe: \"4.3\"\n\n" + "*ColorDevice: True\n" + "*DefaultColorSpace: CMYK\n\n" + "*OpenGroup: General/General\n\n" + "*OpenUI *ColorModel/Color Model: PickOne\n" + "*DefaultColorModel: Grayscale\n" + "*ColorModel Color/Color: " + "\"%% FoomaticRIPOptionSetting: ColorModel=Color\"\n" + "*FoomaticRIPOptionSetting ColorModel=Color: " + "\"JCLDatamode=Color GSCmdLine=Color\"\n" + "*ColorModel Grayscale/Grayscale: " + "\"%% FoomaticRIPOptionSetting: ColorModel=Grayscale\"\n" + "*FoomaticRIPOptionSetting ColorModel=Grayscale: " + "\"JCLDatamode=Grayscale GSCmdLine=Grayscale\"\n" + "*CloseUI: *ColorModel\n" + "*OpenUI *Duplex/2-Sided Printing: PickOne\n" + "*DefaultDuplex: DuplexTumble\n" + "*Duplex None/Off: \"<</Duplex false>>" + "setpagedevice\"\n" + "*Duplex DuplexNoTumble/LongEdge: \"" + "<</Duplex true/Tumble false>>setpagedevice\"\n" + "*Duplex DuplexTumble/ShortEdge: \"" + "<</Duplex true/Tumble true>>setpagedevice\"\n" + "*CloseUI: *Duplex\n\n" + "*CloseGroup: General\n"); + + printing::PrinterSemanticCapsAndDefaults caps; + EXPECT_TRUE(printing::parsePpdCapabilities("test", test_ppd_data, &caps)); + EXPECT_TRUE(caps.color_capable); + EXPECT_FALSE(caps.color_default); + EXPECT_TRUE(caps.duplex_capable); + EXPECT_EQ(caps.duplex_default, printing::LONG_EDGE); +} diff --git a/printing/backend/print_backend.cc b/printing/backend/print_backend.cc index f3de089..b993bfc 100644 --- a/printing/backend/print_backend.cc +++ b/printing/backend/print_backend.cc @@ -12,6 +12,14 @@ PrinterBasicInfo::PrinterBasicInfo() PrinterBasicInfo::~PrinterBasicInfo() {} +PrinterSemanticCapsAndDefaults::PrinterSemanticCapsAndDefaults() + : color_capable(false), + duplex_capable(false), + color_default(false), + duplex_default(UNKNOWN_DUPLEX_MODE) {} + +PrinterSemanticCapsAndDefaults::~PrinterSemanticCapsAndDefaults() {} + PrinterCapsAndDefaults::PrinterCapsAndDefaults() {} PrinterCapsAndDefaults::~PrinterCapsAndDefaults() {} diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h index dfa4762..3cbf162 100644 --- a/printing/backend/print_backend.h +++ b/printing/backend/print_backend.h @@ -10,6 +10,7 @@ #include <vector> #include "base/memory/ref_counted.h" +#include "printing/print_job_constants.h" #include "printing/printing_export.h" namespace base { @@ -32,6 +33,19 @@ struct PRINTING_EXPORT PrinterBasicInfo { typedef std::vector<PrinterBasicInfo> PrinterList; +struct PRINTING_EXPORT PrinterSemanticCapsAndDefaults { + PrinterSemanticCapsAndDefaults(); + ~PrinterSemanticCapsAndDefaults(); + + // Capabilities. + bool color_capable; + bool duplex_capable; + + // Current defaults. + bool color_default; + DuplexMode duplex_default; +}; + struct PRINTING_EXPORT PrinterCapsAndDefaults { PrinterCapsAndDefaults(); ~PrinterCapsAndDefaults(); @@ -58,6 +72,14 @@ class PRINTING_EXPORT PrintBackend // Get the default printer name. Empty string if no default printer. virtual std::string GetDefaultPrinterName() = 0; + // Gets the semantic capabilities and defaults for a specific printer. + // This is usually a lighter implementation than GetPrinterCapsAndDefaults(). + // NOTE: on some old platforms (WinXP without XPS pack) + // GetPrinterCapsAndDefaults() will fail, while this function will succeed. + virtual bool GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) = 0; + // Gets the capabilities and defaults for a specific printer. virtual bool GetPrinterCapsAndDefaults( const std::string& printer_name, diff --git a/printing/backend/print_backend_chromeos.cc b/printing/backend/print_backend_chromeos.cc index 003b0fd..c206d51 100644 --- a/printing/backend/print_backend_chromeos.cc +++ b/printing/backend/print_backend_chromeos.cc @@ -16,6 +16,9 @@ class PrintBackendChromeOS : public PrintBackend { // PrintBackend implementation. virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE; virtual std::string GetDefaultPrinterName() OVERRIDE; + virtual bool GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE; virtual bool GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) OVERRIDE; @@ -33,7 +36,12 @@ bool PrintBackendChromeOS::EnumeratePrinters(PrinterList* printer_list) { return true; } - +bool PrintBackendChromeOS::GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) { + NOTREACHED(); + return false; +} bool PrintBackendChromeOS::GetPrinterCapsAndDefaults( const std::string& printer_name, diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc index d0d8abb..5c515f16 100644 --- a/printing/backend/print_backend_cups.cc +++ b/printing/backend/print_backend_cups.cc @@ -108,6 +108,9 @@ class PrintBackendCUPS : public PrintBackend { // PrintBackend implementation. virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE; virtual std::string GetDefaultPrinterName() OVERRIDE; + virtual bool GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE; virtual bool GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) OVERRIDE; @@ -210,6 +213,17 @@ std::string PrintBackendCUPS::GetDefaultPrinterName() { return dest ? std::string(dest->name) : std::string(); } +bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) { + PrinterCapsAndDefaults info; + if (!GetPrinterCapsAndDefaults(printer_name, &info) ) + return false; + + return parsePpdCapabilities( + printer_name, info.printer_capabilities, printer_info); +} + bool PrintBackendCUPS::GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) { diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc index 46ea15a..f7f84bf 100644 --- a/printing/backend/print_backend_win.cc +++ b/printing/backend/print_backend_win.cc @@ -18,6 +18,29 @@ namespace { +// This class is designed to work with PRINTER_INFO_X structures +// and calls GetPrinter internally with correctly allocated buffer. +template <typename T> +class PrinterInfo { + public: + bool GetPrinterInfo(HANDLE printer, int level) { + DWORD buf_size = 0; + GetPrinter(printer, level, NULL, 0, &buf_size); + if (buf_size == 0) + return false; + buffer_.reset(new uint8[buf_size]); + memset(buffer_.get(), 0, buf_size); + return !!GetPrinter(printer, level, buffer_.get(), buf_size, &buf_size); + } + + const T* get() const { + return reinterpret_cast<T*>(buffer_.get()); + } + + private: + scoped_array<uint8> buffer_; +}; + HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { DCHECK(stream); DCHECK(out); @@ -42,6 +65,9 @@ class PrintBackendWin : public PrintBackend { // PrintBackend implementation. virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE; virtual std::string GetDefaultPrinterName() OVERRIDE; + virtual bool GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE; virtual bool GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) OVERRIDE; @@ -93,6 +119,76 @@ std::string PrintBackendWin::GetDefaultPrinterName() { return WideToUTF8(default_printer_name); } +bool PrintBackendWin::GetPrinterSemanticCapsAndDefaults( + const std::string& printer_name, + PrinterSemanticCapsAndDefaults* printer_info) { + ScopedPrinterHandle printer_handle; + OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()), + printer_handle.Receive(), NULL); + DCHECK(printer_handle); + if (!printer_handle.IsValid()) + return false; + + PrinterInfo<PRINTER_INFO_5> info_5; + if (!info_5.GetPrinterInfo(printer_handle, 5)) + return false; + + // Get printer capabilities. For more info see here: + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183552(v=vs.85).aspx + bool color_supported = (DeviceCapabilities(info_5.get()->pPrinterName, + info_5.get()->pPortName, + DC_COLORDEVICE, + NULL, + NULL) == 1); + + bool duplex_supported = (DeviceCapabilities(info_5.get()->pPrinterName, + info_5.get()->pPortName, + DC_DUPLEX, + NULL, + NULL) == 1); + + // PRINTER_INFO_9 retrieves current user settings. + PrinterInfo<PRINTER_INFO_9> info_9; + if (!info_9.GetPrinterInfo(printer_handle, 9)) + return false; + DEVMODE* devmode = info_9.get()->pDevMode; + + // Sometimes user settings are not available (have not been setted up yet). + // Use printer default settings (PRINTER_INFO_8) in this case. + PrinterInfo<PRINTER_INFO_8> info_8; + if (!devmode) { + if (info_8.GetPrinterInfo(printer_handle, 8)) + devmode = info_8.get()->pDevMode; + } + if (!devmode) + return false; + + PrinterSemanticCapsAndDefaults caps; + caps.color_capable = color_supported; + if ((devmode->dmFields & DM_COLOR) == DM_COLOR) + caps.color_default = (devmode->dmColor == DMCOLOR_COLOR); + + caps.duplex_capable = duplex_supported; + if ((devmode->dmFields & DM_DUPLEX) == DM_DUPLEX) { + switch (devmode->dmDuplex) { + case DMDUP_SIMPLEX: + caps.duplex_default = SIMPLEX; + break; + case DMDUP_VERTICAL: + caps.duplex_default = LONG_EDGE; + break; + case DMDUP_HORIZONTAL: + caps.duplex_default = SHORT_EDGE; + break; + default: + NOTREACHED(); + } + } + + *printer_info = caps; + return true; +} + bool PrintBackendWin::GetPrinterCapsAndDefaults( const std::string& printer_name, PrinterCapsAndDefaults* printer_info) { diff --git a/printing/printing.gyp b/printing/printing.gyp index 6af7b88..89d0d1d 100644 --- a/printing/printing.gyp +++ b/printing/printing.gyp @@ -234,6 +234,14 @@ 'printing_context_win_unittest.cc', ] }], + ['use_cups==1', { + 'defines': [ + 'USE_CUPS', + ], + 'sources': [ + 'backend/cups_helper_unittest.cc', + ], + }], ['toolkit_uses_gtk == 1', { 'dependencies': [ '../build/linux/system.gyp:gtk', |