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

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

Powered by Google App Engine
This is Rietveld 408576698