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
This commit is contained in:
@ -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,
|
||||
|
@ -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);
|
||||
}
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
159
printing/backend/cups_helper_unittest.cc
Normal file
159
printing/backend/cups_helper_unittest.cc
Normal file
@ -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);
|
||||
}
|
@ -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() {}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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',
|
||||
|
Reference in New Issue
Block a user