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

Side by Side Diff: printing/printing_context_chromeos.cc

Issue 2117713002: Print directly to CUPS using the IPP APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ippRead
Patch Set: Update patch Created 4 years, 5 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "printing/printing_context_chromeos.h"
6
7 #include <cups/cups.h>
8 #include <stdint.h>
9 #include <unicode/ulocdata.h>
10
11 #include <memory>
12 #include <vector>
13
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "printing/backend/cups_connection.h"
20 #include "printing/backend/cups_ipp_util.h"
21 #include "printing/backend/cups_printer.h"
22 #include "printing/metafile.h"
23 #include "printing/print_job_constants.h"
24 #include "printing/print_settings.h"
25 #include "printing/printing_context_no_system_dialog.h"
26 #include "printing/units.h"
27
28 namespace printing {
29
30 namespace {
31
32 const char kPageSize[] = "media";
33 const char kResolution[] = "printer-resolution";
34
35 // PWG 5100.13: JPS3
36 const char kColorMode[] = "print-color-mode";
37
38 const char kColorAuto[] = "auto";
39 const char kPwgColor[] = "color";
40 const char kPwgMonochrome[] = "monochrome";
41 const char kColorBiLevel[] = "bi-level";
42 const char kHighlight[] = "highlight";
43 const char kProcessBiLevel[] = "process-bi-level";
44 const char kProcessMonochrome[] = "process-monochrome";
45
46 // convert from a ColorMode setting to a print-color-mode value from PWG 5100.13
47 const char* GetColorModelForMode(int color_mode) {
48 const char* mode_string;
49 switch (color_mode) {
50 case COLOR:
51 case CMYK:
52 case CMY:
53 case KCMY:
54 case CMY_K:
55 case RGB:
56 case RGB16:
57 case RGBA:
58 case COLORMODE_COLOR:
59 case HP_COLOR_COLOR:
60 case PRINTOUTMODE_NORMAL:
61 case PROCESSCOLORMODEL_CMYK:
62 case PROCESSCOLORMODEL_RGB:
63 mode_string = kPwgColor;
64 break;
65 case GRAY:
66 case BLACK:
67 case GRAYSCALE:
68 case COLORMODE_MONOCHROME:
69 case HP_COLOR_BLACK:
70 case PRINTOUTMODE_NORMAL_GRAY:
71 case PROCESSCOLORMODEL_GREYSCALE:
72 mode_string = kPwgMonochrome;
73 break;
74 default:
75 mode_string = nullptr;
76 LOG(WARNING) << "Unrecognized color mode";
77 break;
78 }
79
80 return mode_string;
81 }
82
83 char* CopyStringToChar(const base::StringPiece value, char** dst) {
84 int value_len = value.size() + 1;
85 *dst = new char[value_len];
86 value.copy(*dst, value_len);
87 (*dst)[value_len - 1] = '\0';
88
89 return *dst;
90 }
91
92 cups_option_t ConstructOption(base::StringPiece name, base::StringPiece value) {
93 cups_option_t opt;
94 opt.name = CopyStringToChar(name, &opt.name);
95 opt.value = CopyStringToChar(value, &opt.value);
96
97 return opt;
98 }
99
100 std::vector<cups_option_t> SettingsToCupsOptions(
101 const PrintSettings& settings) {
102 const char* sides = NULL;
103 switch (settings.duplex_mode()) {
104 case SIMPLEX:
105 sides = CUPS_SIDES_ONE_SIDED;
106 break;
107 case LONG_EDGE:
108 sides = CUPS_SIDES_TWO_SIDED_PORTRAIT;
109 break;
110 case SHORT_EDGE:
111 sides = CUPS_SIDES_TWO_SIDED_LANDSCAPE;
112 break;
113 default:
114 NOTREACHED();
115 }
116
117 std::vector<cups_option_t> cups_options = {
118 ConstructOption(kColorMode,
119 GetColorModelForMode(settings.color())), // color
120 ConstructOption(CUPS_SIDES, sides), // duplexing
121 ConstructOption(kPageSize,
122 settings.requested_media().vendor_id) // paper size
123 };
124
125 return cups_options;
126 }
127
128 void SetPrintableArea(PrintSettings* settings,
129 const PrintSettings::RequestedMedia& media,
130 bool flip) {
131 if (!media.size_microns.IsEmpty()) {
132 float deviceMicronsPerDeviceUnit =
133 (kHundrethsMMPerInch * 10.0f) / settings->device_units_per_inch();
134 gfx::Size paper_size =
135 gfx::Size(media.size_microns.width() / deviceMicronsPerDeviceUnit,
136 media.size_microns.height() / deviceMicronsPerDeviceUnit);
137
138 gfx::Rect paper_rect(0, 0, paper_size.width(), paper_size.height());
139 settings->SetPrinterPrintableArea(paper_size, paper_rect, flip);
140 }
141 }
142
143 } // namespace
144
145 // static
146 std::unique_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
147 if (PrintBackend::GetNativeCupsEnabled()) {
148 return base::WrapUnique(new PrintingContextChromeos(delegate));
Lei Zhang 2016/07/13 01:43:05 base::MakeUnique
skau 2016/07/14 23:47:12 Done.
149 }
150
151 return base::WrapUnique(new PrintingContextNoSystemDialog(delegate));
152 }
153
154 PrintingContextChromeos::PrintingContextChromeos(Delegate* delegate)
155 : PrintingContext(delegate),
156 connection_(GURL(), HTTP_ENCRYPT_NEVER, true) {}
157
158 PrintingContextChromeos::~PrintingContextChromeos() {
159 ReleaseContext();
160 }
161
162 void PrintingContextChromeos::AskUserForSettings(
163 int max_pages,
164 bool has_selection,
165 bool is_scripted,
166 const PrintSettingsCallback& callback) {
167 // We don't want to bring up a dialog here. Ever. Just signal the callback.
168 callback.Run(OK);
169 }
170
171 PrintingContext::Result PrintingContextChromeos::UseDefaultSettings() {
172 DCHECK(!in_print_job_);
173
174 ResetSettings();
175
176 std::string device_name = base::UTF16ToUTF8(settings_.device_name());
177 if (device_name.empty()) {
178 LOG(WARNING) << "No printer selected";
Lei Zhang 2016/07/13 01:43:05 BTW, consider only logging the serious stuff. http
skau 2016/07/14 23:47:12 I've switched some to debug logging and removed th
179 return OnError();
180 }
181
182 if (settings_.dpi() == 0) {
183 LOG(WARNING) << "Using Default DPI";
184 settings_.set_dpi(kDefaultPdfDpi);
185 }
186
187 // Retrieve device information and set it
188 if (InitializeDevice(device_name) != OK) {
189 LOG(ERROR) << "Could not initialize printer";
190 return OnError();
191 }
192
193 // Set printable area
194 DCHECK(printer_);
195 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
196
197 PrintSettings::RequestedMedia media;
198 media.vendor_id = paper.vendor_id;
199 media.size_microns = paper.size_um;
200 settings_.set_requested_media(media);
201
202 SetPrintableArea(&settings_, media, true /* flip landscape */);
203
204 return OK;
205 }
206
207 gfx::Size PrintingContextChromeos::GetPdfPaperSizeDeviceUnits() {
208 int32_t width = 0;
209 int32_t height = 0;
210 UErrorCode error = U_ZERO_ERROR;
211 ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
212 &error);
213 if (error > U_ZERO_ERROR) {
214 // If the call failed, assume a paper size of 8.5 x 11 inches.
215 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
216 << error;
217 width =
218 static_cast<int>(kLetterWidthInch * settings_.device_units_per_inch());
219 height =
220 static_cast<int>(kLetterHeightInch * settings_.device_units_per_inch());
221 } else {
222 // ulocdata_getPaperSize returns the width and height in mm.
223 // Convert this to pixels based on the dpi.
224 float multiplier = 100 * settings_.device_units_per_inch();
225 multiplier /= kHundrethsMMPerInch;
226 width *= multiplier;
227 height *= multiplier;
228 }
229 return gfx::Size(width, height);
230 }
231
232 PrintingContext::Result PrintingContextChromeos::UpdatePrinterSettings(
233 bool external_preview,
234 bool show_system_dialog,
235 int page_count) {
236 DCHECK(!show_system_dialog);
237
238 if (InitializeDevice(base::UTF16ToUTF8(settings_.device_name())) != OK)
239 return OnError();
240
241 // TODO(skau): Convert to DCHECK when https://crbug.com/613779 is resolved
Lei Zhang 2016/07/13 01:43:05 Should this also mention line 182 above?
skau 2016/07/14 23:47:12 They're linked now.
242 // Print quality suffers when this is set to the resolution reported by the
243 // printer but print quality is fine at this resolution.
244 if (settings_.dpi() == 0) {
245 LOG(WARNING) << "Using Default DPI";
246 settings_.set_dpi(kDefaultPdfDpi);
247 }
248
249 // compute paper size
250 PrintSettings::RequestedMedia media = settings_.requested_media();
251
252 if (media.IsDefault()) {
253 DCHECK(printer_);
254 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
255
256 media.vendor_id = paper.vendor_id;
257 media.size_microns = paper.size_um;
258 settings_.set_requested_media(media);
259 }
260
261 SetPrintableArea(&settings_, media, true);
262
263 return OK;
264 }
265
266 PrintingContext::Result PrintingContextChromeos::InitializeDevice(
267 const std::string& device) {
268 DCHECK(!in_print_job_);
269
270 CupsPrinter* printer = connection_.GetPrinter(device);
271 if (printer == nullptr) {
Lei Zhang 2016/07/13 01:43:05 More nullptr comparisons
skau 2016/07/14 23:47:12 Done.
skau 2016/07/14 23:47:12 Done.
272 LOG(WARNING) << "Could not initialize device";
273 return OnError();
274 }
275
276 printer_.reset(printer);
277
278 return OK;
279 }
280
281 PrintingContext::Result PrintingContextChromeos::InitWithSettings(
282 const PrintSettings& settings) {
283 DCHECK(!in_print_job_);
284
285 settings_ = settings;
286
287 return OK;
288 }
289
290 PrintingContext::Result PrintingContextChromeos::NewDocument(
291 const base::string16& document_name) {
292 DCHECK(!in_print_job_);
293 in_print_job_ = true;
294
295 std::string converted_name = base::UTF16ToUTF8(document_name);
296 std::string title = base::UTF16ToUTF8(settings_.title());
297 std::vector<cups_option_t> cups_options = SettingsToCupsOptions(settings_);
298
299 bool all_supported = true;
300
301 for (auto option : cups_options) {
302 bool supported = printer_->CheckOptionSupported(option.name, option.value);
303 all_supported = all_supported && supported;
304 }
305
306 if (!all_supported) {
307 LOG(WARNING) << "Unsupported options detected";
308 return OnError();
309 }
310
311 ipp_status_t create_status =
312 printer_->CreateJob(&job_id_, title, cups_options);
313
314 if (job_id_ == 0) {
315 LOG(ERROR) << "Creating cups job failed" << ippErrorString(create_status);
316 return OnError();
317 }
318
319 // we only send one document, so it's always the last one
320 if (!printer_->StartDocument(job_id_, converted_name, true, cups_options)) {
321 LOG(ERROR) << "Starting document failed";
322 return OnError();
323 }
324
325 return OK;
326 }
327
328 PrintingContext::Result PrintingContextChromeos::NewPage() {
329 if (abort_printing_)
330 return CANCEL;
Lei Zhang 2016/07/13 01:43:05 Consider putting a new line after, just like line
skau 2016/07/14 23:47:12 Done.
331 DCHECK(in_print_job_);
332
333 // Intentional No-op.
334
335 return OK;
336 }
337
338 PrintingContext::Result PrintingContextChromeos::StreamData(char* buffer,
339 int len) {
340 if (abort_printing_)
341 return CANCEL;
342 DCHECK(in_print_job_);
343 DCHECK(printer_);
344
345 if (!printer_->StreamData(buffer, len))
346 return OnError();
347
348 return OK;
349 }
350
351 PrintingContext::Result PrintingContextChromeos::PageDone() {
352 if (abort_printing_)
353 return CANCEL;
354 DCHECK(in_print_job_);
355
356 // Intentional No-op.
357
358 return OK;
359 }
360
361 PrintingContext::Result PrintingContextChromeos::DocumentDone() {
362 if (abort_printing_)
363 return CANCEL;
364 DCHECK(in_print_job_);
365
366 if (!printer_->FinishDocument()) {
367 LOG(WARNING) << "Finishing document failed";
368 return OnError();
369 }
370
371 ipp_status_t job_status = printer_->CloseJob(job_id_);
372 job_id_ = 0;
373
374 if (job_status != IPP_STATUS_OK) {
375 LOG(WARNING) << "Closing job failed";
376 return OnError();
377 }
378
379 ResetSettings();
380 return OK;
381 }
382
383 void PrintingContextChromeos::Cancel() {
384 abort_printing_ = true;
385 in_print_job_ = false;
386 }
387
388 void PrintingContextChromeos::ReleaseContext() {
389 printer_.reset(nullptr);
Lei Zhang 2016/07/13 01:43:05 Just reset()
skau 2016/07/14 23:47:12 Done.
390 options_.clear();
391 }
392
393 gfx::NativeDrawingContext PrintingContextChromeos::context() const {
394 // Intentional No-op.
395 return NULL;
396 }
397
398 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698