summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/printing/print_system_task_proxy.cc445
-rw-r--r--chrome/browser/printing/print_system_task_proxy_unittest.cc321
-rw-r--r--chrome/browser/ui/webui/print_preview/print_preview_handler.cc11
-rw-r--r--chrome/chrome_tests.gypi8
-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
13 files changed, 697 insertions, 760 deletions
diff --git a/chrome/browser/printing/print_system_task_proxy.cc b/chrome/browser/printing/print_system_task_proxy.cc
index 2bd9744..16f6e54 100644
--- a/chrome/browser/printing/print_system_task_proxy.cc
+++ b/chrome/browser/printing/print_system_task_proxy.cc
@@ -7,12 +7,9 @@
#include <ctype.h>
#include <string>
-#include <vector>
#include "base/bind.h"
#include "base/metrics/histogram.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
#include "chrome/common/child_process_logging.h"
@@ -23,93 +20,6 @@
#if defined(USE_CUPS)
#include <cups/cups.h>
#include <cups/ppd.h>
-
-#include "base/file_util.h"
-#endif
-
-#if defined(USE_CUPS) && !defined(OS_MACOSX)
-namespace printing_internal {
-
-void parse_lpoptions(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";
- size_t kDestLen = sizeof(kDest) - 1;
- 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 mark_lpoptions(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;
- parse_lpoptions(*it, printer_name, &num_options, &options);
- if (num_options > 0 && options) {
- cupsMarkOptions(*ppd, num_options, options);
- cupsFreeOptions(num_options, options);
- }
- }
-}
-
-} // printing_internal namespace
#endif
using content::BrowserThread;
@@ -123,185 +33,6 @@ const char kPrinterColorModelForBlack[] = "printerColorModelForBlack";
const char kPrinterColorModelForColor[] = "printerColorModelForColor";
const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
-#if defined(OS_WIN)
-const char kPskColor[] = "psk:Color";
-const char kPskGray[] = "psk:Grayscale";
-const char kPskMonochrome[] = "psk:Monochrome";
-const char kPskDuplexFeature[] = "psk:JobDuplexAllDocumentsContiguously";
-const char kPskTwoSided[] = "psk:TwoSided";
-#elif defined(USE_CUPS)
-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";
-
-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);
- }
- 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;
-}
-#endif
-
} // namespace
PrintSystemTaskProxy::PrintSystemTaskProxy(
@@ -378,121 +109,6 @@ void PrintSystemTaskProxy::SetupPrinterList(ListValue* printers) {
delete printers;
}
-bool PrintSystemTaskProxy::ParsePrinterCapabilities(
- const printing::PrinterCapsAndDefaults& printer_info,
- const std::string& printer_name,
- bool* set_color_as_default,
- int* printer_color_space_for_color,
- int* printer_color_space_for_black,
- bool* set_duplex_as_default,
- int* default_duplex_setting_value) {
-#if defined(USE_CUPS)
- FilePath ppd_file_path;
- if (!file_util::CreateTemporaryFile(&ppd_file_path))
- return false;
-
- int data_size = printer_info.printer_capabilities.length();
- if (data_size != file_util::WriteFile(
- ppd_file_path,
- printer_info.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) {
-#if !defined(OS_MACOSX)
- printing_internal::mark_lpoptions(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) {
- if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0) {
- *set_duplex_as_default = true;
- *default_duplex_setting_value = printing::LONG_EDGE;
- } else {
- *default_duplex_setting_value = printing::SIMPLEX;
- }
- }
-
- bool is_color_device = false;
- ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
- if (attr && attr->value)
- is_color_device = ppd->color_device;
- *set_color_as_default = is_color_device;
-
- if (!((is_color_device && getBasicColorModelSettings(
- ppd, printer_color_space_for_black,
- printer_color_space_for_color, set_color_as_default)) ||
- getPrintOutModeColorSettings(
- ppd, printer_color_space_for_black,
- printer_color_space_for_color, set_color_as_default) ||
- getColorModeSettings(
- ppd, printer_color_space_for_black,
- printer_color_space_for_color, set_color_as_default) ||
- getHPColorSettings(
- ppd, printer_color_space_for_black,
- printer_color_space_for_color, set_color_as_default) ||
- getProcessColorModelSettings(
- ppd, printer_color_space_for_black,
- printer_color_space_for_color, set_color_as_default))) {
- VLOG(1) << "Unknown printer color model";
- }
- ppdClose(ppd);
- }
- file_util::Delete(ppd_file_path, false);
- return true;
-
-#elif defined(OS_WIN)
-
- // According to XPS 1.0 spec, only color printers have psk:Color.
- // Therefore we don't need to parse the whole XML file, we just need to
- // search the string. The spec can be found at:
- // http://msdn.microsoft.com/en-us/windows/hardware/gg463431.
- if (printer_info.printer_capabilities.find(kPskColor) != std::string::npos)
- *printer_color_space_for_color = printing::COLOR;
-
- if ((printer_info.printer_capabilities.find(kPskGray) !=
- std::string::npos) ||
- (printer_info.printer_capabilities.find(kPskMonochrome) !=
- std::string::npos)) {
- *printer_color_space_for_black = printing::GRAY;
- }
- *set_color_as_default =
- (printer_info.printer_defaults.find(kPskColor) != std::string::npos);
-
- *set_duplex_as_default =
- (printer_info.printer_defaults.find(kPskDuplexFeature) !=
- std::string::npos) &&
- (printer_info.printer_defaults.find(kPskTwoSided) !=
- std::string::npos);
-
- if (printer_info.printer_defaults.find(kPskDuplexFeature) !=
- std::string::npos) {
- if (printer_info.printer_defaults.find(kPskTwoSided) !=
- std::string::npos) {
- *default_duplex_setting_value = printing::LONG_EDGE;
- } else {
- *default_duplex_setting_value = printing::SIMPLEX;
- }
- }
- return true;
-
-#else
-
- NOTIMPLEMENTED();
- return false;
-
-#endif // defined(OS_WIN)
-}
-
-
void PrintSystemTaskProxy::GetPrinterCapabilities(
const std::string& printer_name) {
VLOG(1) << "Get printer capabilities start for " << printer_name;
@@ -500,6 +116,8 @@ void PrintSystemTaskProxy::GetPrinterCapabilities(
print_backend_->GetPrinterDriverInfo(printer_name));
if (!print_backend_->IsValidPrinter(printer_name)) {
+ // TODO(gene): Notify explicitly if printer is not valid, instead of
+ // failed to get capabilities.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintSystemTaskProxy::SendFailedToGetPrinterCapabilities,
@@ -507,48 +125,35 @@ void PrintSystemTaskProxy::GetPrinterCapabilities(
return;
}
- bool set_color_as_default = false;
- bool set_duplex_as_default = false;
- int printer_color_space_for_color = printing::UNKNOWN_COLOR_MODEL;
- int printer_color_space_for_black = printing::UNKNOWN_COLOR_MODEL;
- int default_duplex_setting_value = printing::UNKNOWN_DUPLEX_MODE;
- bool disable_color_options = false;
-
- printing::PrinterCapsAndDefaults info;
- if (print_backend_->GetPrinterCapsAndDefaults(printer_name, &info) &&
- ParsePrinterCapabilities(info,
- printer_name,
- &set_color_as_default,
- &printer_color_space_for_color,
- &printer_color_space_for_black,
- &set_duplex_as_default,
- &default_duplex_setting_value)) {
- disable_color_options = (!printer_color_space_for_color ||
- !printer_color_space_for_black ||
- (printer_color_space_for_color ==
- printer_color_space_for_black));
- } else {
+ printing::PrinterSemanticCapsAndDefaults info;
+ if (!print_backend_->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
VLOG(1) << "Failed to get capabilities for " << printer_name;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&PrintSystemTaskProxy::SendFailedToGetPrinterCapabilities,
+ this, printer_name));
+ return;
}
DictionaryValue settings_info;
settings_info.SetString(kPrinterId, printer_name);
- settings_info.SetBoolean(kDisableColorOption, disable_color_options);
- if (printer_color_space_for_color == printing::UNKNOWN_COLOR_MODEL)
- printer_color_space_for_color = printing::COLOR;
-
- if (printer_color_space_for_black == printing::UNKNOWN_COLOR_MODEL)
- printer_color_space_for_black = printing::GRAY;
-
+ settings_info.SetBoolean(kDisableColorOption, !info.color_capable);
settings_info.SetBoolean(printing::kSettingSetColorAsDefault,
- set_color_as_default);
- settings_info.SetBoolean(kSetDuplexAsDefault, set_duplex_as_default);
- settings_info.SetInteger(kPrinterColorModelForColor,
- printer_color_space_for_color);
- settings_info.SetInteger(kPrinterColorModelForBlack,
- printer_color_space_for_black);
- settings_info.SetInteger(kPrinterDefaultDuplexValue,
- default_duplex_setting_value);
+ info.color_default);
+ // TODO(gene): Make new capabilities format for Print Preview
+ // that will suit semantic capabiltities better.
+ // Refactor pld API code below
+ if (info.duplex_capable) {
+ settings_info.SetBoolean(kSetDuplexAsDefault,
+ info.duplex_default != printing::SIMPLEX);
+ settings_info.SetInteger(kPrinterDefaultDuplexValue,
+ printing::LONG_EDGE);
+ } else {
+ settings_info.SetBoolean(kSetDuplexAsDefault, false);
+ settings_info.SetInteger(kPrinterDefaultDuplexValue,
+ printing::UNKNOWN_DUPLEX_MODE);
+ }
+
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintSystemTaskProxy::SendPrinterCapabilities, this,
diff --git a/chrome/browser/printing/print_system_task_proxy_unittest.cc b/chrome/browser/printing/print_system_task_proxy_unittest.cc
deleted file mode 100644
index cf82631..0000000
--- a/chrome/browser/printing/print_system_task_proxy_unittest.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-// 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 <cups/cups.h>
-#include <cups/ppd.h>
-
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/scoped_temp_dir.h"
-#include "chrome/browser/printing/print_system_task_proxy.h"
-#include "content/public/test/test_browser_thread.h"
-#include "printing/backend/print_backend.h"
-#include "printing/print_job_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-#if !defined(OS_MACOSX)
-
-// TestEntry stores the printer name and the expected number of options.
-struct TestEntry {
- TestEntry(std::string name, int count)
- : printer_name(name),
- expected_option_count(count) {}
-
- std::string printer_name;
- int expected_option_count;
-};
-
-// Verify the option marked in |ppd|.
-void verifyOptionValue(ppd_file_t* ppd,
- const std::string& option_name,
- const std::string& expected_choice_value) {
- ppd_choice_t* option_choice = ppdFindMarkedChoice(ppd, option_name.c_str());
- if (option_choice == NULL) {
- ppd_option_t* option = ppdFindOption(ppd, option_name.c_str());
- if (option != NULL)
- option_choice = ppdFindChoice(option, option->defchoice);
- }
- ASSERT_TRUE(option_choice);
- EXPECT_EQ(strcmp(option_choice->choice, expected_choice_value.c_str()), 0);
-}
-
-#endif // !defined(OS_MACOSX)
-
-class PrintSystemTaskProxyTest : public testing::Test {
- public:
- PrintSystemTaskProxyTest()
- : loop_(MessageLoop::TYPE_UI),
- ui_thread_(content::BrowserThread::UI, &loop_) {
- }
-
- protected:
- virtual void TearDown() OVERRIDE {
- MessageLoop::current()->RunAllPending();
- }
-
- private:
- MessageLoop loop_;
- content::TestBrowserThread ui_thread_;
-};
-
-} // namespace
-
-#if !defined(OS_MACOSX)
-
-using printing_internal::parse_lpoptions;
-
-
-
-// Test to verify that lpoption custom settings are marked on the ppd file.
-TEST_F(PrintSystemTaskProxyTest, MarkLpoptionsInPPD) {
- const std::string kColorModel = "ColorModel";
- const std::string kBlack = "Black";
- const std::string kGray = "Gray";
-
- const std::string kDuplex = "Duplex";
- const std::string kDuplexNone = "None";
- const std::string kDuplexNoTumble = "DuplexNoTumble";
- const std::string kDuplexTumble = "DuplexTumble";
- const std::string kTestPrinterName = "printerE";
-
- ScopedTempDir temp_directory;
- ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-
- std::string system_lpoptions; // Specifies the system lpoption data.
- system_lpoptions.append("Dest printerE ColorModel=Black Duplex=");
- system_lpoptions.append(kDuplexNone+" ");
-
- // Create and write the system lpoptions to a temp file.
- FilePath system_lp_options_file;
- ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
- &system_lp_options_file));
- ASSERT_TRUE(file_util::WriteFile(system_lp_options_file,
- system_lpoptions.c_str(),
- system_lpoptions.size()));
-
- // Specifies the user lpoption data.
- std::string user_lpoptions;
- user_lpoptions.append("Dest printerE Duplex="+kDuplexNoTumble+"\n");
-
- // Create and write the user lpoptions to a temp file.
- FilePath user_lp_options_file;
- ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
- &user_lp_options_file));
- ASSERT_TRUE(file_util::WriteFile(user_lp_options_file, user_lpoptions.c_str(),
- user_lpoptions.size()));
- // Specifies the test ppd data.
- 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");
-
- // Create a test ppd file.
- FilePath ppd_file_path;
- ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
- &ppd_file_path));
- ASSERT_TRUE(file_util::WriteFile(ppd_file_path, test_ppd_data.c_str(),
- test_ppd_data.size()));
-
- ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str());
- ASSERT_TRUE(ppd);
- ppdMarkDefaults(ppd);
-
- // Verify the default settings.
- verifyOptionValue(ppd, kDuplex, kDuplexTumble);
- verifyOptionValue(ppd, kColorModel, kGray);
-
- // Parse the system lpoptions data.
- int num_options = 0;
- cups_option_t* options = NULL;
- parse_lpoptions(system_lp_options_file, kTestPrinterName, &num_options,
- &options);
- ASSERT_EQ(num_options, 2);
- EXPECT_EQ(num_options != 0, options != NULL);
- cupsMarkOptions(ppd, num_options, options);
- cupsFreeOptions(num_options, options);
-
- // Verify that the settings are updated as per system lpoptions.
- verifyOptionValue(ppd, kDuplex, kDuplexNone);
- verifyOptionValue(ppd, kColorModel, kBlack);
-
- // Parse the user lpoptions data.
- num_options = 0;
- options = NULL;
- parse_lpoptions(user_lp_options_file, kTestPrinterName, &num_options,
- &options);
- ASSERT_EQ(num_options, 1);
- EXPECT_EQ(num_options != 0, options != NULL);
- cupsMarkOptions(ppd, num_options, options);
- cupsFreeOptions(num_options, options);
-
- // Verify that the settings are updated as per user lpoptions. Make sure
- // duplex setting is updated but the color setting remains the same.
- verifyOptionValue(ppd, kDuplex, kDuplexNoTumble);
- verifyOptionValue(ppd, kColorModel, kBlack);
- ppdClose(ppd);
-}
-
-// Test the lpoption parsing code.
-TEST_F(PrintSystemTaskProxyTest, ParseLpoptionData) {
- // Specifies the user lpoption data.
- std::string user_lpoptions;
-
- // Printer A default printer settings.
- user_lpoptions.append("Default printerA Duplex=None landscape=true ");
- user_lpoptions.append("media=A4 Collate=True sides=two-sided-long-edge ");
- user_lpoptions.append("ColorModel=Color nUp=7\n");
-
- // PrinterB custom settings.
- user_lpoptions.append("Dest printerB Duplex=None scaling=98 ");
- user_lpoptions.append("landscape=true media=A4 collate=True\n");
-
- // PrinterC has a invalid key and value but the format is valid.
- user_lpoptions.append("Dest printerC invalidKey1=invalidValue1 ");
- user_lpoptions.append("invalidKey2=invalidValue2 ");
- user_lpoptions.append("invalidKey3=invalidValue3 \n");
-
- // PrinterA instance custom settings. These settings will not override
- // PrinterA settings.
- user_lpoptions.append("Dest printerA/instanceA ");
- user_lpoptions.append("scaling=33 Duplex=DuplexTumble landscape=true\n");
-
- // PrinterD custom settings but the format is invalid because of the tab key
- // delimiter.
- user_lpoptions.append("Dest printerD\tDuplex=DuplexNoTumble\n");
-
- // PrinterE custom settings.
- user_lpoptions.append("Dest printerE Duplex=DuplexNoTumble\n");
-
- ScopedTempDir temp_directory;
- ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-
- // Create and write the user lpoptions to a temp file.
- FilePath userLpOptionsFile;
- ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
- &userLpOptionsFile));
- ASSERT_TRUE(file_util::WriteFile(userLpOptionsFile, user_lpoptions.c_str(),
- user_lpoptions.size()));
- std::vector<TestEntry> test_cases;
- test_cases.push_back(
- TestEntry("printerA", 7)); // Parse generic printer.
- test_cases.push_back(
- TestEntry("printerB", 5)); // Valid printer info.
- test_cases.push_back(
- TestEntry("printerC", 3)); // Invalid settings found.
- test_cases.push_back(
- TestEntry("printerD", 0)); // Tab key delimiter used.
- test_cases.push_back(
- TestEntry("printerE", 1)); // user specified custom settings.
- test_cases.push_back(
- TestEntry("printerF", 0)); // Custom settings not found.
-
- // Parse the lpoptions for each printer. Parse the system file followed by the
- // user file. Ordering is important.
- int num_options;
- cups_option_t* options;
- for (std::vector<TestEntry>::iterator it = test_cases.begin();
- it != test_cases.end(); ++it) {
- num_options = 0;
- options = NULL;
- printing_internal::parse_lpoptions(userLpOptionsFile, it->printer_name,
- &num_options, &options);
- ASSERT_EQ(num_options, it->expected_option_count);
- EXPECT_EQ(num_options != 0, options != NULL);
- cupsFreeOptions(num_options, options);
- }
-}
-#endif // !defined(OS_MACOSX)
-
-// Test duplex detection code, which regressed in http://crbug.com/103999.
-TEST_F(PrintSystemTaskProxyTest, DetectDuplexModeCUPS) {
- // Specifies the test ppd data.
- printing::PrinterCapsAndDefaults printer_info;
- printer_info.printer_capabilities.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");
-
- bool set_color_as_default = false;
- bool set_duplex_as_default = false;
- int printer_color_space_for_color = printing::UNKNOWN_COLOR_MODEL;
- int printer_color_space_for_black = printing::UNKNOWN_COLOR_MODEL;
- int default_duplex_setting_value = printing::UNKNOWN_DUPLEX_MODE;
-
- scoped_refptr<PrintSystemTaskProxy> proxy(
- new PrintSystemTaskProxy(base::WeakPtr<PrintPreviewHandler>(), NULL,
- false));
- ASSERT_TRUE(proxy->ParsePrinterCapabilities(
- printer_info,
- "InvalidPrinter",
- &set_color_as_default,
- &printer_color_space_for_color,
- &printer_color_space_for_black,
- &set_duplex_as_default,
- &default_duplex_setting_value));
- EXPECT_FALSE(set_duplex_as_default);
- EXPECT_EQ(printing::SIMPLEX, default_duplex_setting_value);
-}
-
-TEST_F(PrintSystemTaskProxyTest, DetectNoDuplexModeCUPS) {
- // Specifies the test ppd data.
- printing::PrinterCapsAndDefaults printer_info;
- printer_info.printer_capabilities.append(
- "*PPD-Adobe: \"4.3\"\n\n"
- "*OpenGroup: General/General\n\n"
- "*CloseGroup: General\n");
-
- bool set_color_as_default = false;
- bool set_duplex_as_default = false;
- int printer_color_space_for_color = printing::UNKNOWN_COLOR_MODEL;
- int printer_color_space_for_black = printing::UNKNOWN_COLOR_MODEL;
- int default_duplex_setting_value = printing::UNKNOWN_DUPLEX_MODE;
-
- scoped_refptr<PrintSystemTaskProxy> proxy(
- new PrintSystemTaskProxy(base::WeakPtr<PrintPreviewHandler>(), NULL,
- false));
- ASSERT_TRUE(proxy->ParsePrinterCapabilities(
- printer_info,
- "InvalidPrinter",
- &set_color_as_default,
- &printer_color_space_for_color,
- &printer_color_space_for_black,
- &set_duplex_as_default,
- &default_duplex_setting_value));
- EXPECT_FALSE(set_duplex_as_default);
- EXPECT_EQ(printing::UNKNOWN_DUPLEX_MODE, default_duplex_setting_value);
-}
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 0c1d60a..26f8239 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -7,7 +7,6 @@
#include <ctype.h>
#include <string>
-#include <vector>
#include "base/base64.h"
#include "base/bind.h"
@@ -763,16 +762,8 @@ void PrintPreviewHandler::ActivateInitiatorTabAndClosePreviewTab() {
void PrintPreviewHandler::SendPrinterCapabilities(
const DictionaryValue& settings_info) {
VLOG(1) << "Get printer capabilities finished";
- // Copy so we can override with sticky values.
- scoped_ptr<DictionaryValue> settings(settings_info.DeepCopy());
- if (GetStickySettings()->color_model() != printing::UNKNOWN_COLOR_MODEL) {
- settings->SetBoolean(
- printing::kSettingSetColorAsDefault,
- printing::isColorModelSelected(
- GetStickySettings()->color_model()));
- }
web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
- *settings);
+ settings_info);
}
void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index b297f33..64f443f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2605,14 +2605,6 @@
['exclude', '^browser/importer/'],
],
}],
- ['use_cups==1', {
- 'defines': [
- 'USE_CUPS',
- ],
- 'sources': [
- 'browser/printing/print_system_task_proxy_unittest.cc',
- ],
- }],
['component=="shared_library" and incremental_chrome_dll!=1', {
# This is needed for tests that subclass
# RendererWebKitPlatformSupportImpl, which subclasses stuff in
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',