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

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

Powered by Google App Engine
This is Rietveld 408576698