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

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: lint Created 4 years, 4 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 <utility>
13 #include <vector>
14
15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "printing/backend/cups_connection.h"
22 #include "printing/backend/cups_ipp_util.h"
23 #include "printing/backend/cups_printer.h"
24 #include "printing/metafile.h"
25 #include "printing/print_job_constants.h"
26 #include "printing/print_settings.h"
27 #include "printing/printing_context_no_system_dialog.h"
28 #include "printing/units.h"
29
30 namespace printing {
31
32 namespace {
33
34 using CupsOption = std::unique_ptr<cups_option_t, OptionDeleter>;
Lei Zhang 2016/07/25 21:06:04 Can you name this ScopedCupsOption, so it's more o
skau 2016/07/27 00:16:47 Done.
35
36 // convert from a ColorMode setting to a print-color-mode value from PWG 5100.13
37 const char* GetColorModelForMode(int color_mode) {
38 const char* mode_string;
39 switch (color_mode) {
40 case COLOR:
41 case CMYK:
42 case CMY:
43 case KCMY:
44 case CMY_K:
45 case RGB:
46 case RGB16:
47 case RGBA:
48 case COLORMODE_COLOR:
49 case HP_COLOR_COLOR:
50 case PRINTOUTMODE_NORMAL:
51 case PROCESSCOLORMODEL_CMYK:
52 case PROCESSCOLORMODEL_RGB:
53 mode_string = CUPS_PRINT_COLOR_MODE_COLOR;
54 break;
55 case GRAY:
56 case BLACK:
57 case GRAYSCALE:
58 case COLORMODE_MONOCHROME:
59 case HP_COLOR_BLACK:
60 case PRINTOUTMODE_NORMAL_GRAY:
61 case PROCESSCOLORMODEL_GREYSCALE:
62 mode_string = CUPS_PRINT_COLOR_MODE_MONOCHROME;
63 break;
64 default:
65 mode_string = nullptr;
66 LOG(WARNING) << "Unrecognized color mode";
67 break;
68 }
69
70 return mode_string;
71 }
72
73 // Copies the contents |value| into a newly allocated char* buffer. The result
74 // is null terminated and will need to be deleted.
Lei Zhang 2016/07/25 21:06:04 The more common phrase here would be "the caller o
skau 2016/07/27 00:16:47 Done.
75 char* ToCString(const base::StringPiece value) {
Lei Zhang 2016/07/25 21:06:04 TOCString() -> more like, DuplicateString() ?
skau 2016/07/27 00:16:47 Done.
76 size_t buffer_size = value.size() + 1;
77 char* dst = new char[buffer_size];
78 strncpy(dst, value.as_string().c_str(), buffer_size);
79 return dst;
80 }
81
82 CupsOption ConstructOption(const base::StringPiece name,
83 const base::StringPiece value) {
84 CupsOption option = CupsOption(new cups_option_t);
85 option->name = ToCString(name);
Lei Zhang 2016/07/25 21:06:04 It's probably not obvious to readers that CupsOpti
skau 2016/07/27 00:16:47 Done.
86 option->value = ToCString(value);
87 return option;
88 }
89
90 base::StringPiece GetCollateString(bool collate) {
91 return collate ? kCollated : kUncollated;
92 }
93
94 std::vector<CupsOption> SettingsToCupsOptions(const PrintSettings& settings) {
95 const char* sides = nullptr;
96 switch (settings.duplex_mode()) {
97 case SIMPLEX:
98 sides = CUPS_SIDES_ONE_SIDED;
99 break;
100 case LONG_EDGE:
101 sides = CUPS_SIDES_TWO_SIDED_PORTRAIT;
102 break;
103 case SHORT_EDGE:
104 sides = CUPS_SIDES_TWO_SIDED_LANDSCAPE;
105 break;
106 default:
107 NOTREACHED();
108 }
109
110 std::vector<CupsOption> options;
111 options.push_back(
112 ConstructOption(kIppColor,
113 GetColorModelForMode(settings.color()))); // color
114 options.push_back(ConstructOption(kIppDuplex, sides)); // duplexing
115 options.push_back(
116 ConstructOption(kIppMedia,
117 settings.requested_media().vendor_id)); // paper size
118 options.push_back(
119 ConstructOption(kIppCopies,
120 base::IntToString(settings.copies()))); // copies
121 options.push_back(
122 ConstructOption(kIppCollate,
123 GetCollateString(settings.collate()))); // collate
124
125 return 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::MakeUnique<PrintingContextChromeos>(delegate);
149
150 return base::MakeUnique<PrintingContextNoSystemDialog>(delegate);
151 }
152
153 PrintingContextChromeos::PrintingContextChromeos(Delegate* delegate)
154 : PrintingContext(delegate),
155 connection_(GURL(), HTTP_ENCRYPT_NEVER, true) {}
156
157 PrintingContextChromeos::~PrintingContextChromeos() {
158 ReleaseContext();
159 }
160
161 void PrintingContextChromeos::AskUserForSettings(
162 int max_pages,
163 bool has_selection,
164 bool is_scripted,
165 const PrintSettingsCallback& callback) {
166 // We don't want to bring up a dialog here. Ever. Just signal the callback.
167 callback.Run(OK);
168 }
169
170 PrintingContext::Result PrintingContextChromeos::UseDefaultSettings() {
171 DCHECK(!in_print_job_);
172
173 ResetSettings();
174
175 std::string device_name = base::UTF16ToUTF8(settings_.device_name());
176 if (device_name.empty())
177 return OnError();
178
179 // TODO(skau): https://crbug.com/613779. See UpdatePrinterSettings for more
180 // info.
181 if (settings_.dpi() == 0) {
182 DVLOG(1) << "Using Default DPI";
183 settings_.set_dpi(kDefaultPdfDpi);
184 }
185
186 // Retrieve device information and set it
187 if (InitializeDevice(device_name) != OK) {
188 LOG(ERROR) << "Could not initialize printer";
189 return OnError();
190 }
191
192 // Set printable area
193 DCHECK(printer_);
194 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
195
196 PrintSettings::RequestedMedia media;
197 media.vendor_id = paper.vendor_id;
198 media.size_microns = paper.size_um;
199 settings_.set_requested_media(media);
200
201 SetPrintableArea(&settings_, media, true /* flip landscape */);
202
203 return OK;
204 }
205
206 gfx::Size PrintingContextChromeos::GetPdfPaperSizeDeviceUnits() {
207 int32_t width = 0;
208 int32_t height = 0;
209 UErrorCode error = U_ZERO_ERROR;
210 ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
211 &error);
212 if (error > U_ZERO_ERROR) {
213 // If the call failed, assume a paper size of 8.5 x 11 inches.
214 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
215 << error;
216 width =
217 static_cast<int>(kLetterWidthInch * settings_.device_units_per_inch());
218 height =
219 static_cast<int>(kLetterHeightInch * settings_.device_units_per_inch());
220 } else {
221 // ulocdata_getPaperSize returns the width and height in mm.
222 // Convert this to pixels based on the dpi.
223 float multiplier = 100 * settings_.device_units_per_inch();
224 multiplier /= kHundrethsMMPerInch;
225 width *= multiplier;
226 height *= multiplier;
227 }
228 return gfx::Size(width, height);
229 }
230
231 PrintingContext::Result PrintingContextChromeos::UpdatePrinterSettings(
232 bool external_preview,
233 bool show_system_dialog,
234 int page_count) {
235 DCHECK(!show_system_dialog);
236
237 if (InitializeDevice(base::UTF16ToUTF8(settings_.device_name())) != OK)
238 return OnError();
239
240 // TODO(skau): Convert to DCHECK when https://crbug.com/613779 is resolved
241 // Print quality suffers when this is set to the resolution reported by the
242 // printer but print quality is fine at this resolution. UseDefaultSettings
243 // exhibits the same problem.
244 if (settings_.dpi() == 0) {
245 DVLOG(1) << "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 std::unique_ptr<CupsPrinter> printer = connection_.GetPrinter(device);
271 if (!printer) {
272 LOG(WARNING) << "Could not initialize device";
273 return OnError();
274 }
275
276 printer_ = std::move(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<CupsOption> cups_options = SettingsToCupsOptions(settings_);
298
299 bool all_supported = true;
300
301 for (const CupsOption& option : cups_options) {
302 bool supported =
303 printer_->CheckOptionSupported(option->name, option->value);
304 all_supported = all_supported && supported;
305 }
306
307 if (!all_supported) {
308 DVLOG(1) << "Unsupported options detected";
309 return OnError();
310 }
311
312 std::vector<cups_option_t> options;
313 for (const CupsOption& option : cups_options) {
314 options.push_back(*(option.get()));
315 }
316
317 ipp_status_t create_status = printer_->CreateJob(&job_id_, title, options);
318
319 if (job_id_ == 0) {
320 DLOG(WARNING) << "Creating cups job failed"
321 << ippErrorString(create_status);
322 return OnError();
323 }
324
325 // we only send one document, so it's always the last one
326 if (!printer_->StartDocument(job_id_, converted_name, true, options)) {
327 LOG(ERROR) << "Starting document failed";
328 return OnError();
329 }
330
331 return OK;
332 }
333
334 PrintingContext::Result PrintingContextChromeos::NewPage() {
335 if (abort_printing_)
336 return CANCEL;
337
338 DCHECK(in_print_job_);
339
340 // Intentional No-op.
341
342 return OK;
343 }
344
345 PrintingContext::Result PrintingContextChromeos::PageDone() {
346 if (abort_printing_)
347 return CANCEL;
348
349 DCHECK(in_print_job_);
350
351 // Intentional No-op.
352
353 return OK;
354 }
355
356 PrintingContext::Result PrintingContextChromeos::DocumentDone() {
357 if (abort_printing_)
358 return CANCEL;
359
360 DCHECK(in_print_job_);
361
362 if (!printer_->FinishDocument()) {
363 LOG(WARNING) << "Finishing document failed";
364 return OnError();
365 }
366
367 ipp_status_t job_status = printer_->CloseJob(job_id_);
368 job_id_ = 0;
369
370 if (job_status != IPP_STATUS_OK) {
371 LOG(WARNING) << "Closing job failed";
372 return OnError();
373 }
374
375 ResetSettings();
376 return OK;
377 }
378
379 void PrintingContextChromeos::Cancel() {
380 abort_printing_ = true;
381 in_print_job_ = false;
382 }
383
384 void PrintingContextChromeos::ReleaseContext() {
385 printer_.reset();
386 }
387
388 gfx::NativeDrawingContext PrintingContextChromeos::context() const {
389 // Intentional No-op.
390 return nullptr;
391 }
392
393 PrintingContext::Result PrintingContextChromeos::StreamData(
394 const std::vector<char>& buffer) {
395 if (abort_printing_)
396 return CANCEL;
397
398 DCHECK(in_print_job_);
399 DCHECK(printer_);
400
401 if (!printer_->StreamData(buffer))
402 return OnError();
403
404 return OK;
405 }
406
407 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698