summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorgene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-07 04:21:21 +0000
committergene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-07 04:21:21 +0000
commit8b6098e412722d5b34d6a085f8fc0fd5cb78c6f5 (patch)
treeb4c7a2a65a49dbf5655b43a3a96394979847f7d5 /printing
parent58df36ac048af7d31edf3b7b1bf217853c8b3c20 (diff)
downloadchromium_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.cc344
-rw-r--r--printing/backend/cups_helper.h11
-rw-r--r--printing/backend/cups_helper_unittest.cc159
-rw-r--r--printing/backend/print_backend.cc8
-rw-r--r--printing/backend/print_backend.h22
-rw-r--r--printing/backend/print_backend_chromeos.cc10
-rw-r--r--printing/backend/print_backend_cups.cc14
-rw-r--r--printing/backend/print_backend_win.cc96
-rw-r--r--printing/printing.gyp8
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',