Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: chrome/browser/printing/print_system_task_proxy.cc

Issue 8138020: PrintPreview: Fix printer color settings issues based on printer ppd/schema information. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/printing/print_system_task_proxy.h"
6
7 #include <ctype.h>
8
9 #include <string>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/metrics/histogram.h"
14 #include "base/string_split.h"
15 #include "base/string_util.h"
16 #include "base/values.h"
17 #include "printing/backend/print_backend.h"
18 #include "printing/print_job_constants.h"
19
20 #if defined(USE_CUPS)
21 #include <cups/cups.h>
22 #include <cups/ppd.h>
23
24 #include "base/file_util.h"
25 #endif
26
27 #if defined(USE_CUPS) && !defined(OS_MACOSX)
28 namespace printing_internal {
29
30 void parse_lpoptions(const FilePath& filepath, const std::string& printer_name,
31 int* num_options, cups_option_t** options) {
32 std::string content;
33 if (!file_util::ReadFileToString(filepath, &content))
34 return;
35
36 const char kDest[] = "dest";
37 const char kDefault[] = "default";
38 size_t kDestLen = sizeof(kDest) - 1;
39 size_t kDefaultLen = sizeof(kDefault) - 1;
40 std::vector <std::string> lines;
41 base::SplitString(content, '\n', &lines);
42
43 for (size_t i = 0; i < lines.size(); ++i) {
44 std::string line = lines[i];
45 if (line.empty())
46 continue;
47
48 if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 &&
49 isspace(line[kDefaultLen])) {
50 line = line.substr(kDefaultLen);
51 } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 &&
52 isspace(line[kDestLen])) {
53 line = line.substr(kDestLen);
54 } else {
55 continue;
56 }
57
58 TrimWhitespaceASCII(line, TRIM_ALL, &line);
59 if (line.empty())
60 continue;
61
62 size_t space_found = line.find(' ');
63 if (space_found == std::string::npos)
64 continue;
65
66 std::string name = line.substr(0, space_found);
67 if (name.empty())
68 continue;
69
70 if (base::strncasecmp(printer_name.c_str(), name.c_str(),
71 name.length()) != 0) {
72 continue; // This is not the required printer.
73 }
74
75 line = line.substr(space_found + 1);
76 TrimWhitespaceASCII(line, TRIM_ALL, &line); // Remove extra spaces.
77 if (line.empty())
78 continue;
79 // Parse the selected printer custom options.
80 *num_options = cupsParseOptions(line.c_str(), 0, options);
81 }
82 }
83
84 void mark_lpoptions(const std::string& printer_name, ppd_file_t** ppd) {
85 cups_option_t* options = NULL;
86 int num_options = 0;
87 ppdMarkDefaults(*ppd);
88
89 const char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
90 const char kUserLpOptionPath[] = ".cups/lpoptions";
91
92 std::vector<FilePath> file_locations;
93 file_locations.push_back(FilePath(kSystemLpOptionPath));
94 file_locations.push_back(FilePath(
95 file_util::GetHomeDir().Append(kUserLpOptionPath)));
96
97 for (std::vector<FilePath>::const_iterator it = file_locations.begin();
98 it != file_locations.end(); ++it) {
99 num_options = 0;
100 options = NULL;
101 parse_lpoptions(*it, printer_name, &num_options, &options);
102 if (num_options > 0 && options) {
103 cupsMarkOptions(*ppd, num_options, options);
104 cupsFreeOptions(num_options, options);
105 }
106 }
107 }
108
109 } // printing_internal namespace
110 #endif
111
112 namespace {
113
114 const char kDisableColorOption[] = "disableColorOption";
115 const char kSetColorAsDefault[] = "setColorAsDefault";
116 const char kSetDuplexAsDefault[] = "setDuplexAsDefault";
117 const char kPrinterColorModelForBlack[] = "printerColorModelForBlack";
118 const char kPrinterColorModelForColor[] = "printerColorModelForColor";
119 const char kPrinterDefaultDuplexValue[] = "printerDefaultDuplexValue";
120
121 #if defined(USE_CUPS)
122 const char kColorDevice[] = "ColorDevice";
123 const char kColorModel[] = "ColorModel";
124 const char kColorMode[] = "ColorMode";
125 const char kProcessColorModel[] = "ProcessColorModel";
126 const char kPrintoutMode[] = "PrintoutMode";
127 const char kDraftGray[] = "Draft.Gray";
128 const char kHighGray[] = "High.Gray";
129
130 const char kDuplex[] = "Duplex";
131 const char kDuplexNone[] = "None";
132
133 void getBasicColorModelSettings(
134 ppd_file_t* ppd, int* color_model_for_black, int* color_model_for_color,
135 bool* color_is_default) {
136 ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
137 if (ppdFindChoice(color_model, printing::kBlack))
138 *color_model_for_black = printing::BLACK;
139 else if (ppdFindChoice(color_model, printing::kGray))
140 *color_model_for_black = printing::GRAY;
141
142 if (ppdFindChoice(color_model, printing::kColor))
143 *color_model_for_color = printing::COLOR;
144 else if (ppdFindChoice(color_model, printing::kCMYK))
145 *color_model_for_color = printing::CMYK;
146 else if (ppdFindChoice(color_model, printing::kRGB))
147 *color_model_for_color = printing::RGB;
148 else if (ppdFindChoice(color_model, printing::kRGBA))
149 *color_model_for_color = printing::RGBA;
150 else if (ppdFindChoice(color_model, printing::kRGB16))
151 *color_model_for_color = printing::RGB16;
152 else if (ppdFindChoice(color_model, printing::kCMY))
153 *color_model_for_color = printing::CMY;
154 else if (ppdFindChoice(color_model, printing::kKCMY))
155 *color_model_for_color = printing::KCMY;
156 else if (ppdFindChoice(color_model, printing::kCMY_K))
157 *color_model_for_color = printing::CMY_K;
158
159 ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
160 if (!marked_choice)
161 marked_choice = ppdFindChoice(color_model, color_model->defchoice);
162
163 if (marked_choice) {
164 *color_is_default =
165 (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) &&
166 (base::strcasecmp(marked_choice->choice, printing::kGray) != 0);
167 }
168 }
169
170 void getPrintOutModeColorSettings(
171 ppd_file_t* ppd, int* color_model_for_black, int* color_model_for_color,
172 bool* color_is_default) {
173 ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
174 *color_model_for_color = printing::PRINTOUTMODE_NORMAL;
175 *color_model_for_black = printing::PRINTOUTMODE_NORMAL;
176
177 // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
178 // If NORMAL_GRAY is not supported, NORMAL value is used to
179 // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
180 // represent color.
181 if (ppdFindChoice(printout_mode, printing::kNormalGray))
182 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
183
184 // Get the default marked choice to identify the default color setting
185 // value.
186 ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
187 if (!printout_mode_choice) {
188 printout_mode_choice = ppdFindChoice(printout_mode,
189 printout_mode->defchoice);
190 }
191 if (printout_mode_choice) {
192 if ((base::strcasecmp(printout_mode_choice->choice,
193 printing::kNormalGray) == 0) ||
194 (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) ||
195 (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) {
196 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
197 *color_is_default = false;
198 }
199 }
200 }
201
202 void getColorModeSettings(
203 ppd_file_t* ppd, int* color_model_for_black, int* color_model_for_color,
204 bool* color_is_default) {
205 // Samsung printers use "ColorMode" attribute in their ppds.
206 ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
207 if (ppdFindChoice(color_mode_option, printing::kColor))
208 *color_model_for_color = printing::COLORMODE_COLOR;
209
210 if (ppdFindChoice(color_mode_option, printing::kMonochrome))
211 *color_model_for_black = printing::COLORMODE_MONOCHROME;
212
213 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
214 if (!mode_choice) {
215 mode_choice = ppdFindChoice(color_mode_option,
216 color_mode_option->defchoice);
217 }
218
219 if (mode_choice) {
220 *color_is_default =
221 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
222 }
223 }
224
225 void getHPColorSettings(
226 ppd_file_t* ppd, int* color_model_for_black, int* color_model_for_color,
227 bool* color_is_default) {
228 // HP printers use "Color/Color Model" attribute in their ppds.
229 ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor);
230 if (ppdFindChoice(color_mode_option, printing::kColor))
231 *color_model_for_color = printing::HP_COLOR_COLOR;
232 if (ppdFindChoice(color_mode_option, printing::kBlack))
233 *color_model_for_black = printing::HP_COLOR_BLACK;
234
235 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
236 if (!mode_choice) {
237 mode_choice = ppdFindChoice(color_mode_option,
238 color_mode_option->defchoice);
239 }
240 if (mode_choice) {
241 *color_is_default =
242 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
243 }
244 }
245
246 void getProcessColorModelSettings(
247 ppd_file_t* ppd, int* color_model_for_black, int* color_model_for_color,
248 bool* color_is_default) {
249 // Canon printers use "ProcessColorModel" attribute in their ppds.
250 ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
251 if (ppdFindChoice(color_mode_option, printing::kRGB))
252 *color_model_for_color = printing::PROCESSCOLORMODEL_RGB;
253 else if (ppdFindChoice(color_mode_option, printing::kCMYK))
254 *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK;
255
256 if (ppdFindChoice(color_mode_option, printing::kGreyscale))
257 *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE;
258
259 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
260 if (!mode_choice) {
261 mode_choice = ppdFindChoice(color_mode_option,
262 color_mode_option->defchoice);
263 }
264
265 if (mode_choice) {
266 *color_is_default =
267 (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0);
268 }
269 }
270 #elif defined(OS_WIN)
271 const char kPskColor[] = "psk:Color";
vandebo (ex-Chrome) 2011/10/11 19:11:42 Consider putting this block first since it is much
kmadhusu 2011/10/11 21:36:03 Done.
272 const char kPskGray[] = "psk:Grayscale";
273 const char kPskMonochrome[] = "psk:Monochrome";
274 const char kPskDuplexFeature[] = "psk:JobDuplexAllDocumentsContiguously";
275 const char kPskTwoSided[] = "psk:TwoSided";
276 #endif
277
278 } // namespace
279
280 PrintSystemTaskProxy::PrintSystemTaskProxy(
281 const base::WeakPtr<PrintPreviewHandler>& handler,
282 printing::PrintBackend* print_backend,
283 bool has_logged_printers_count)
284 : handler_(handler),
285 print_backend_(print_backend),
286 has_logged_printers_count_(has_logged_printers_count) {
287 }
288
289 PrintSystemTaskProxy::~PrintSystemTaskProxy() {
290 }
291
292 void PrintSystemTaskProxy::GetDefaultPrinter() {
293 VLOG(1) << "Get default printer start";
294 StringValue* default_printer = NULL;
295 if (PrintPreviewHandler::last_used_printer_name_ == NULL) {
296 default_printer = new StringValue(
297 print_backend_->GetDefaultPrinterName());
298 } else {
299 default_printer = new StringValue(
300 *PrintPreviewHandler::last_used_printer_name_);
301 }
302 std::string default_printer_string;
303 default_printer->GetAsString(&default_printer_string);
304 VLOG(1) << "Get default printer finished, found: "
305 << default_printer_string;
306
307 StringValue* cloud_print_data = NULL;
308 if (PrintPreviewHandler::last_used_printer_cloud_print_data_ != NULL) {
309 cloud_print_data = new StringValue(
310 *PrintPreviewHandler::last_used_printer_cloud_print_data_);
311 } else {
312 cloud_print_data = new StringValue("");
313 }
314
315 BrowserThread::PostTask(
316 BrowserThread::UI, FROM_HERE,
317 base::Bind(&PrintSystemTaskProxy::SendDefaultPrinter, this,
318 default_printer, cloud_print_data));
319 }
320
321 void PrintSystemTaskProxy::SendDefaultPrinter(
322 const StringValue* default_printer, const StringValue* cloud_print_data) {
323 if (handler_)
324 handler_->SendDefaultPrinter(*default_printer, *cloud_print_data);
325 delete default_printer;
326 }
327
328 void PrintSystemTaskProxy::EnumeratePrinters() {
329 VLOG(1) << "Enumerate printers start";
330 ListValue* printers = new ListValue;
331 printing::PrinterList printer_list;
332 print_backend_->EnumeratePrinters(&printer_list);
333
334 if (!has_logged_printers_count_) {
335 // Record the total number of printers.
336 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters",
337 printer_list.size());
338 }
339 int i = 0;
340 for (printing::PrinterList::iterator iter = printer_list.begin();
341 iter != printer_list.end(); ++iter, ++i) {
342 DictionaryValue* printer_info = new DictionaryValue;
343 std::string printerName;
344 #if defined(OS_MACOSX)
345 // On Mac, |iter->printer_description| specifies the printer name and
346 // |iter->printer_name| specifies the device name / printer queue name.
347 printerName = iter->printer_description;
348 #else
349 printerName = iter->printer_name;
350 #endif
351 printer_info->SetString(printing::kSettingPrinterName, printerName);
352 printer_info->SetString(printing::kSettingDeviceName, iter->printer_name);
353 printers->Append(printer_info);
354 }
355 VLOG(1) << "Enumerate printers finished, found " << i << " printers";
356
357 BrowserThread::PostTask(
358 BrowserThread::UI, FROM_HERE,
359 base::Bind(&PrintSystemTaskProxy::SetupPrinterList, this, printers));
360 }
361
362 void PrintSystemTaskProxy::SetupPrinterList(ListValue* printers) {
363 if (handler_)
364 handler_->SetupPrinterList(*printers);
365 delete printers;
366 }
367
368 void PrintSystemTaskProxy::GetPrinterCapabilities(
369 const std::string& printer_name) {
370 VLOG(1) << "Get printer capabilities start for " << printer_name;
371 printing::PrinterCapsAndDefaults printer_info;
372
373 bool set_color_as_default = false;
374 bool disable_color_options = true;
375 bool set_duplex_as_default = false;
376 int printer_color_space_for_color = printing::UNKNOWN_COLOR_MODEL;
377 int printer_color_space_for_black = printing::UNKNOWN_COLOR_MODEL;
378 int default_duplex_setting_value = printing::UNKNOWN_DUPLEX_MODE;
379 if (!print_backend_->GetPrinterCapsAndDefaults(printer_name,
380 &printer_info)) {
381 return;
382 }
383
384 #if defined(USE_CUPS)
385 FilePath ppd_file_path;
386 if (!file_util::CreateTemporaryFile(&ppd_file_path))
387 return;
388
389 int data_size = printer_info.printer_capabilities.length();
390 if (data_size != file_util::WriteFile(
391 ppd_file_path,
392 printer_info.printer_capabilities.data(),
393 data_size)) {
394 file_util::Delete(ppd_file_path, false);
395 return;
396 }
397
398 ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str());
399 if (ppd) {
400 #if !defined(OS_MACOSX)
401 printing_internal::mark_lpoptions(printer_name, &ppd);
402 #endif
403 bool is_color_device = false;
vandebo (ex-Chrome) 2011/10/11 19:11:42 consider moving this block down to 425, so all the
kmadhusu 2011/10/11 21:36:03 Done.
404 ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
405 if (attr && attr->value)
406 is_color_device = ppd->color_device;
407 disable_color_options = !is_color_device;
408
409 ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex);
410 if (duplex_choice) {
411 ppd_option_t* option = ppdFindOption(ppd, kDuplex);
412 if (option)
413 duplex_choice = ppdFindChoice(option, option->defchoice);
414 }
415
416 if (duplex_choice) {
417 if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0) {
418 set_duplex_as_default = true;
419 default_duplex_setting_value = printing::LONG_EDGE;
420 } else {
421 default_duplex_setting_value = printing::SIMPLEX;
422 }
423 }
424
425 set_color_as_default = is_color_device;
426
427 if (is_color_device && ppdFindOption(ppd, kColorModel)) {
kmadhusu 2011/10/10 23:34:26 All the data members and member functions of this
vandebo (ex-Chrome) 2011/10/11 19:11:42 Hmm, this structure ends up calling ppdFindOption
kmadhusu 2011/10/11 21:36:03 Done.
428 getBasicColorModelSettings(
429 ppd, &printer_color_space_for_black, &printer_color_space_for_color,
430 &set_color_as_default);
431 } else if (ppdFindOption(ppd, kPrintoutMode)) {
432 getPrintOutModeColorSettings(
433 ppd, &printer_color_space_for_black, &printer_color_space_for_color,
434 &set_color_as_default);
435 } else if (ppdFindOption(ppd, kColorMode)) {
436 getColorModeSettings(
437 ppd, &printer_color_space_for_black, &printer_color_space_for_color,
438 &set_color_as_default);
439 } else if (ppdFindOption(ppd, printing::kColor)) {
440 getHPColorSettings(
441 ppd, &printer_color_space_for_black, &printer_color_space_for_color,
442 &set_color_as_default);
443 } else if (ppdFindOption(ppd, kProcessColorModel)) {
444 getProcessColorModelSettings(
445 ppd, &printer_color_space_for_black, &printer_color_space_for_color,
446 &set_color_as_default);
447 }
448 ppdClose(ppd);
449 }
450 file_util::Delete(ppd_file_path, false);
451 #elif defined(OS_WIN)
452 // According to XPS 1.0 spec, only color printers have psk:Color.
453 // Therefore we don't need to parse the whole XML file, we just need to
454 // search the string. The spec can be found at:
455 // http://msdn.microsoft.com/en-us/windows/hardware/gg463431.
456 if (printer_info.printer_capabilities.find(kPskColor) != std::string::npos)
457 printer_color_space_for_color = printing::COLOR;
458
459 if ((printer_info.printer_capabilities.find(kPskGray) !=
460 std::string::npos) ||
461 (printer_info.printer_capabilities.find(kPskMonochrome) !=
462 std::string::npos)) {
463 printer_color_space_for_black = printing::GRAY;
464 }
465
466 set_duplex_as_default =
467 (printer_info.printer_defaults.find(kPskDuplexFeature) !=
468 std::string::npos) &&
469 (printer_info.printer_defaults.find(kPskTwoSided) !=
470 std::string::npos);
471
472 if (printer_info.printer_defaults.find(kPskDuplexFeature) !=
473 std::string::npos) {
474 if (printer_info.printer_defaults.find(kPskTwoSided) !=
475 std::string::npos) {
476 default_duplex_setting_value = printing::LONG_EDGE;
477 } else {
478 default_duplex_setting_value = printing::SIMPLEX;
479 }
480 }
481 set_color_as_default =
vandebo (ex-Chrome) 2011/10/11 19:11:42 move with the other color code.
kmadhusu 2011/10/11 21:36:03 Done.
482 (printer_info.printer_defaults.find(kPskColor) != std::string::npos);
483 #else
484 NOTIMPLEMENTED();
485 #endif
486 disable_color_options = !printer_color_space_for_color ||
487 !printer_color_space_for_black ||
488 (printer_color_space_for_color ==
489 printer_color_space_for_black);
490
491 DictionaryValue settings_info;
492 settings_info.SetBoolean(kDisableColorOption, disable_color_options);
493 if (printer_color_space_for_color == printing::UNKNOWN_COLOR_MODEL)
494 printer_color_space_for_color = printing::COLOR;
495
496 if (printer_color_space_for_black == printing::UNKNOWN_COLOR_MODEL)
497 printer_color_space_for_black = printing::GRAY;
498
499 if (disable_color_options ||
500 PrintPreviewHandler::last_used_color_model_ ==
501 printing::UNKNOWN_COLOR_MODEL) {
502 settings_info.SetBoolean(kSetColorAsDefault, set_color_as_default);
503 } else {
504 settings_info.SetBoolean(kSetColorAsDefault,
505 printing::isColorModelSelected(
506 PrintPreviewHandler::last_used_color_model_));
507 }
508
509 settings_info.SetBoolean(kSetDuplexAsDefault, set_duplex_as_default);
510 settings_info.SetInteger(kPrinterColorModelForColor,
511 printer_color_space_for_color);
512 settings_info.SetInteger(kPrinterColorModelForBlack,
513 printer_color_space_for_black);
514 settings_info.SetInteger(kPrinterDefaultDuplexValue,
515 default_duplex_setting_value);
516 BrowserThread::PostTask(
517 BrowserThread::UI, FROM_HERE,
518 base::Bind(&PrintSystemTaskProxy::SendPrinterCapabilities, this,
519 settings_info.DeepCopy()));
520 }
521
522 void PrintSystemTaskProxy::SendPrinterCapabilities(
523 DictionaryValue* settings_info) {
524 if (handler_)
525 handler_->SendPrinterCapabilities(*settings_info);
526 delete settings_info;
527 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698