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

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: format and merge 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
« no previous file with comments | « printing/printing_context_chromeos.h ('k') | printing/printing_context_no_system_dialog.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 ScopedCupsOption = std::unique_ptr<cups_option_t, OptionDeleter>;
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 // Returns a new char buffer which is a null-terminated copy of |value|. The
74 // caller owns the returned string.
75 char* DuplicateString(const base::StringPiece value) {
76 char* dst = new char[value.size() + 1];
77 value.copy(dst, value.size());
78 dst[value.size()] = '\0';
79 return dst;
80 }
81
82 ScopedCupsOption ConstructOption(const base::StringPiece name,
83 const base::StringPiece value) {
84 // ScopedCupsOption frees the name and value buffers on deletion
85 ScopedCupsOption option = ScopedCupsOption(new cups_option_t);
86 option->name = DuplicateString(name);
87 option->value = DuplicateString(value);
88 return option;
89 }
90
91 base::StringPiece GetCollateString(bool collate) {
92 return collate ? kCollated : kUncollated;
93 }
94
95 std::vector<ScopedCupsOption> 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<ScopedCupsOption> options;
113 options.push_back(
114 ConstructOption(kIppColor,
115 GetColorModelForMode(settings.color()))); // color
116 options.push_back(ConstructOption(kIppDuplex, sides)); // duplexing
117 options.push_back(
118 ConstructOption(kIppMedia,
119 settings.requested_media().vendor_id)); // paper size
120 options.push_back(
121 ConstructOption(kIppCopies,
122 base::IntToString(settings.copies()))); // copies
123 options.push_back(
124 ConstructOption(kIppCollate,
125 GetCollateString(settings.collate()))); // collate
126
127 return options;
128 }
129
130 void SetPrintableArea(PrintSettings* settings,
131 const PrintSettings::RequestedMedia& media,
132 bool flip) {
133 if (!media.size_microns.IsEmpty()) {
134 float deviceMicronsPerDeviceUnit =
135 (kHundrethsMMPerInch * 10.0f) / settings->device_units_per_inch();
136 gfx::Size paper_size =
137 gfx::Size(media.size_microns.width() / deviceMicronsPerDeviceUnit,
138 media.size_microns.height() / deviceMicronsPerDeviceUnit);
139
140 gfx::Rect paper_rect(0, 0, paper_size.width(), paper_size.height());
141 settings->SetPrinterPrintableArea(paper_size, paper_rect, flip);
142 }
143 }
144
145 } // namespace
146
147 // static
148 std::unique_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
149 if (PrintBackend::GetNativeCupsEnabled())
150 return base::MakeUnique<PrintingContextChromeos>(delegate);
151
152 return base::MakeUnique<PrintingContextNoSystemDialog>(delegate);
153 }
154
155 PrintingContextChromeos::PrintingContextChromeos(Delegate* delegate)
156 : PrintingContext(delegate),
157 connection_(GURL(), HTTP_ENCRYPT_NEVER, true) {}
158
159 PrintingContextChromeos::~PrintingContextChromeos() {
160 ReleaseContext();
161 }
162
163 void PrintingContextChromeos::AskUserForSettings(
164 int max_pages,
165 bool has_selection,
166 bool is_scripted,
167 const PrintSettingsCallback& callback) {
168 // We don't want to bring up a dialog here. Ever. Just signal the callback.
169 callback.Run(OK);
170 }
171
172 PrintingContext::Result PrintingContextChromeos::UseDefaultSettings() {
173 DCHECK(!in_print_job_);
174
175 ResetSettings();
176
177 std::string device_name = base::UTF16ToUTF8(settings_.device_name());
178 if (device_name.empty())
179 return OnError();
180
181 // TODO(skau): https://crbug.com/613779. See UpdatePrinterSettings for more
182 // info.
183 if (settings_.dpi() == 0) {
184 DVLOG(1) << "Using Default DPI";
185 settings_.set_dpi(kDefaultPdfDpi);
186 }
187
188 // Retrieve device information and set it
189 if (InitializeDevice(device_name) != OK) {
190 LOG(ERROR) << "Could not initialize printer";
191 return OnError();
192 }
193
194 // Set printable area
195 DCHECK(printer_);
196 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
197
198 PrintSettings::RequestedMedia media;
199 media.vendor_id = paper.vendor_id;
200 media.size_microns = paper.size_um;
201 settings_.set_requested_media(media);
202
203 SetPrintableArea(&settings_, media, true /* flip landscape */);
204
205 return OK;
206 }
207
208 gfx::Size PrintingContextChromeos::GetPdfPaperSizeDeviceUnits() {
209 int32_t width = 0;
210 int32_t height = 0;
211 UErrorCode error = U_ZERO_ERROR;
212 ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
213 &error);
214 if (error > U_ZERO_ERROR) {
215 // If the call failed, assume a paper size of 8.5 x 11 inches.
216 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
217 << error;
218 width =
219 static_cast<int>(kLetterWidthInch * settings_.device_units_per_inch());
220 height =
221 static_cast<int>(kLetterHeightInch * settings_.device_units_per_inch());
222 } else {
223 // ulocdata_getPaperSize returns the width and height in mm.
224 // Convert this to pixels based on the dpi.
225 float multiplier = 100 * settings_.device_units_per_inch();
226 multiplier /= kHundrethsMMPerInch;
227 width *= multiplier;
228 height *= multiplier;
229 }
230 return gfx::Size(width, height);
231 }
232
233 PrintingContext::Result PrintingContextChromeos::UpdatePrinterSettings(
234 bool external_preview,
235 bool show_system_dialog,
236 int page_count) {
237 DCHECK(!show_system_dialog);
238
239 if (InitializeDevice(base::UTF16ToUTF8(settings_.device_name())) != OK)
240 return OnError();
241
242 // TODO(skau): Convert to DCHECK when https://crbug.com/613779 is resolved
243 // Print quality suffers when this is set to the resolution reported by the
244 // printer but print quality is fine at this resolution. UseDefaultSettings
245 // exhibits the same problem.
246 if (settings_.dpi() == 0) {
247 DVLOG(1) << "Using Default DPI";
248 settings_.set_dpi(kDefaultPdfDpi);
249 }
250
251 // compute paper size
252 PrintSettings::RequestedMedia media = settings_.requested_media();
253
254 if (media.IsDefault()) {
255 DCHECK(printer_);
256 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
257
258 media.vendor_id = paper.vendor_id;
259 media.size_microns = paper.size_um;
260 settings_.set_requested_media(media);
261 }
262
263 SetPrintableArea(&settings_, media, true);
264
265 return OK;
266 }
267
268 PrintingContext::Result PrintingContextChromeos::InitializeDevice(
269 const std::string& device) {
270 DCHECK(!in_print_job_);
271
272 std::unique_ptr<CupsPrinter> printer = connection_.GetPrinter(device);
273 if (!printer) {
274 LOG(WARNING) << "Could not initialize device";
275 return OnError();
276 }
277
278 printer_ = std::move(printer);
279
280 return OK;
281 }
282
283 PrintingContext::Result PrintingContextChromeos::InitWithSettings(
284 const PrintSettings& settings) {
285 DCHECK(!in_print_job_);
286
287 settings_ = settings;
288
289 return OK;
290 }
291
292 PrintingContext::Result PrintingContextChromeos::NewDocument(
293 const base::string16& document_name) {
294 DCHECK(!in_print_job_);
295 in_print_job_ = true;
296
297 std::string converted_name = base::UTF16ToUTF8(document_name);
298 std::string title = base::UTF16ToUTF8(settings_.title());
299 std::vector<ScopedCupsOption> cups_options = SettingsToCupsOptions(settings_);
300
301 std::vector<cups_option_t> options;
302 for (const ScopedCupsOption& option : cups_options) {
303 if (printer_->CheckOptionSupported(option->name, option->value)) {
304 options.push_back(*(option.get()));
305 } else {
306 DVLOG(1) << "Unsupported option skipped " << option->name << ", "
307 << option->value;
308 }
309 }
310
311 ipp_status_t create_status = printer_->CreateJob(&job_id_, title, options);
312
313 if (job_id_ == 0) {
314 DLOG(WARNING) << "Creating cups job failed"
315 << 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, 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;
331
332 DCHECK(in_print_job_);
333
334 // Intentional No-op.
335
336 return OK;
337 }
338
339 PrintingContext::Result PrintingContextChromeos::PageDone() {
340 if (abort_printing_)
341 return CANCEL;
342
343 DCHECK(in_print_job_);
344
345 // Intentional No-op.
346
347 return OK;
348 }
349
350 PrintingContext::Result PrintingContextChromeos::DocumentDone() {
351 if (abort_printing_)
352 return CANCEL;
353
354 DCHECK(in_print_job_);
355
356 if (!printer_->FinishDocument()) {
357 LOG(WARNING) << "Finishing document failed";
358 return OnError();
359 }
360
361 ipp_status_t job_status = printer_->CloseJob(job_id_);
362 job_id_ = 0;
363
364 if (job_status != IPP_STATUS_OK) {
365 LOG(WARNING) << "Closing job failed";
366 return OnError();
367 }
368
369 ResetSettings();
370 return OK;
371 }
372
373 void PrintingContextChromeos::Cancel() {
374 abort_printing_ = true;
375 in_print_job_ = false;
376 }
377
378 void PrintingContextChromeos::ReleaseContext() {
379 printer_.reset();
380 }
381
382 gfx::NativeDrawingContext PrintingContextChromeos::context() const {
383 // Intentional No-op.
384 return nullptr;
385 }
386
387 PrintingContext::Result PrintingContextChromeos::StreamData(
388 const std::vector<char>& buffer) {
389 if (abort_printing_)
390 return CANCEL;
391
392 DCHECK(in_print_job_);
393 DCHECK(printer_);
394
395 if (!printer_->StreamData(buffer))
396 return OnError();
397
398 return OK;
399 }
400
401 } // namespace printing
OLDNEW
« no previous file with comments | « printing/printing_context_chromeos.h ('k') | printing/printing_context_no_system_dialog.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698