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

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: Loggin cleaned up 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 bool use_native_cups_ = false;
Lei Zhang 2016/07/08 01:35:26 g_use_native_cups ... but do you really need this?
skau 2016/07/09 00:28:33 Nope. I had it in for debugging.
47
48 // convert from a ColorMode setting to a print-color-mode value from PWG 5100.13
49 const char* GetColorModelForMode(int color_mode) {
50 const char* mode_string;
51 switch (color_mode) {
52 case COLOR:
53 case CMYK:
54 case CMY:
55 case KCMY:
56 case CMY_K:
57 case RGB:
58 case RGB16:
59 case RGBA:
60 case COLORMODE_COLOR:
61 case HP_COLOR_COLOR:
62 case PRINTOUTMODE_NORMAL:
63 case PROCESSCOLORMODEL_CMYK:
64 case PROCESSCOLORMODEL_RGB:
65 mode_string = kPwgColor;
66 break;
67 case GRAY:
68 case BLACK:
69 case GRAYSCALE:
70 case COLORMODE_MONOCHROME:
71 case HP_COLOR_BLACK:
72 case PRINTOUTMODE_NORMAL_GRAY:
73 case PROCESSCOLORMODEL_GREYSCALE:
74 mode_string = kPwgMonochrome;
75 break;
76 default:
77 mode_string = nullptr;
78 LOG(WARNING) << "Unrecognized color mode";
79 break;
80 }
81
82 return mode_string;
83 }
84
85 char* CopyStringToChar(const base::StringPiece value, char** dst) {
86 int value_len = value.size() + 1;
87 *dst = new char[value_len];
88 value.copy(*dst, value_len);
89 (*dst)[value_len - 1] = '\0';
90
91 return *dst;
92 }
93
94 cups_option_t ConstructOption(base::StringPiece name, base::StringPiece value) {
95 cups_option_t opt;
96 opt.name = CopyStringToChar(name, &opt.name);
97 opt.value = CopyStringToChar(value, &opt.value);
98
99 return opt;
100 }
101
102 std::vector<cups_option_t> SettingsToCupsOptions(
103 const PrintSettings& settings) {
104 const char* sides = NULL;
105 switch (settings.duplex_mode()) {
106 case SIMPLEX:
107 sides = CUPS_SIDES_ONE_SIDED;
108 break;
109 case LONG_EDGE:
110 sides = CUPS_SIDES_TWO_SIDED_PORTRAIT;
111 break;
112 case SHORT_EDGE:
113 sides = CUPS_SIDES_TWO_SIDED_LANDSCAPE;
114 break;
115 default:
116 NOTREACHED();
117 }
118
119 std::vector<cups_option_t> cups_options = {
120 ConstructOption(kColorMode,
121 GetColorModelForMode(settings.color())), // color
122 ConstructOption(CUPS_SIDES, sides), // duplexing
123 ConstructOption(kPageSize,
124 settings.requested_media().vendor_id) // paper size
125 };
126
127 return cups_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 use_native_cups_ = true;
151 return base::WrapUnique(new PrintingContextChromeos(delegate));
152 }
153
154 use_native_cups_ = false;
155 return base::WrapUnique(new PrintingContextNoSystemDialog(delegate));
156 }
157
158 PrintingContextChromeos::PrintingContextChromeos(Delegate* delegate)
159 : PrintingContext(delegate),
160 connection_(GURL(), HTTP_ENCRYPT_NEVER, true) {}
161
162 PrintingContextChromeos::~PrintingContextChromeos() {
163 ReleaseContext();
164 }
165
166 void PrintingContextChromeos::AskUserForSettings(
167 int max_pages,
168 bool has_selection,
169 bool is_scripted,
170 const PrintSettingsCallback& callback) {
171 // We don't want to bring up a dialog here. Ever. Just signal the callback.
172 callback.Run(OK);
173 }
174
175 PrintingContext::Result PrintingContextChromeos::UseDefaultSettings() {
176 DCHECK(!in_print_job_);
177
178 ResetSettings();
179
180 std::string device_name = base::UTF16ToUTF8(settings_.device_name());
181 if (device_name.empty()) {
182 LOG(WARNING) << "No printer selected";
183 return OnError();
184 }
185
186 if (settings_.dpi() == 0) {
187 LOG(WARNING) << "Using Default DPI";
188 settings_.set_dpi(kDefaultPdfDpi);
189 }
190
191 // Retrieve device information and set it
192 if (InitializeDevice(device_name) != OK) {
193 LOG(ERROR) << "Could not initialize printer";
194 return OnError();
195 }
196
197 // Set printable area
198 DCHECK(printer_);
199 PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
200
201 PrintSettings::RequestedMedia media;
202 media.vendor_id = paper.vendor_id;
203 media.size_microns = paper.size_um;
204 settings_.set_requested_media(media);
205
206 SetPrintableArea(&settings_, media, true /* flip landscape */);
207
208 return OK;
209 }
210
211 gfx::Size PrintingContextChromeos::GetPdfPaperSizeDeviceUnits() {
212 int32_t width = 0;
213 int32_t height = 0;
214 UErrorCode error = U_ZERO_ERROR;
215 ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
216 &error);
217 if (error > U_ZERO_ERROR) {
218 // If the call failed, assume a paper size of 8.5 x 11 inches.
219 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
220 << error;
221 width =
222 static_cast<int>(kLetterWidthInch * settings_.device_units_per_inch());
223 height =
224 static_cast<int>(kLetterHeightInch * settings_.device_units_per_inch());
225 } else {
226 // ulocdata_getPaperSize returns the width and height in mm.
227 // Convert this to pixels based on the dpi.
228 float multiplier = 100 * settings_.device_units_per_inch();
229 multiplier /= kHundrethsMMPerInch;
230 width *= multiplier;
231 height *= multiplier;
232 }
233 return gfx::Size(width, height);
234 }
235
236 PrintingContext::Result PrintingContextChromeos::UpdatePrinterSettings(
237 bool external_preview,
238 bool show_system_dialog,
239 int page_count) {
240 DCHECK(!show_system_dialog);
241
242 if (InitializeDevice(base::UTF16ToUTF8(settings_.device_name())) != OK)
243 return OnError();
244
245 // HACK We should get this from the device driver
Lei Zhang 2016/07/08 01:35:26 What's going on here?
skau 2016/07/09 00:28:33 Setting the dpi using printer the reported printer
246 if (settings_.dpi() == 0) {
247 LOG(WARNING) << "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 options_ = SettingsToCupsOptions(settings_);
266
267 return OK;
268 }
269
270 PrintingContext::Result PrintingContextChromeos::InitializeDevice(
271 const std::string& device) {
272 DCHECK(!in_print_job_);
273
274 CupsPrinter* printer = connection_.GetPrinter(device);
275 if (printer == nullptr) {
276 LOG(WARNING) << "Could not initialize device";
277 return OnError();
278 }
279
280 printer_.reset(printer);
281
282 return OK;
283 }
284
285 PrintingContext::Result PrintingContextChromeos::InitWithSettings(
286 const PrintSettings& settings) {
287 DCHECK(!in_print_job_);
288
289 settings_ = settings;
290
291 return OK;
292 }
293
294 PrintingContext::Result PrintingContextChromeos::NewDocument(
295 const base::string16& document_name) {
296 DCHECK(!in_print_job_);
297 in_print_job_ = true;
298
299 std::string converted_name = base::UTF16ToUTF8(document_name);
300 std::string title = base::UTF16ToUTF8(settings_.title());
301
302 bool all_supported = true;
303
304 for (auto option : options_) {
305 bool supported = printer_->CheckOptionSupported(option.name, option.value);
306 all_supported = all_supported && supported;
307 }
308
309 if (!all_supported) {
310 LOG(WARNING) << "Unsupported options detected";
311 return OnError();
312 }
313
314 ipp_status_t create_status = printer_->CreateJob(&job_id_, title, options_);
315
316 if (job_id_ == 0) {
317 LOG(ERROR) << "Creating cups job failed" << ippErrorString(create_status);
318 return OnError();
319 }
320
321 // we only send one document, so it's always the last one
322 if (!printer_->StartDocument(job_id_, converted_name, true, options_)) {
323 LOG(ERROR) << "Starting document failed";
324 return OnError();
325 }
326
327 return OK;
328 }
329
330 PrintingContext::Result PrintingContextChromeos::NewPage() {
331 if (abort_printing_)
332 return CANCEL;
333 DCHECK(in_print_job_);
334
335 // Intentional No-op.
336
337 return OK;
338 }
339
340 PrintingContext::Result PrintingContextChromeos::StreamData(char* buffer,
341 int len) {
342 if (abort_printing_)
343 return CANCEL;
344 DCHECK(in_print_job_);
345 DCHECK(printer_);
346 DCHECK(use_native_cups_);
347
348 if (!printer_->StreamData(buffer, len))
349 return OnError();
350
351 return OK;
352 }
353
354 PrintingContext::Result PrintingContextChromeos::PageDone() {
355 if (abort_printing_)
356 return CANCEL;
357 DCHECK(in_print_job_);
358
359 // Intentional No-op.
360
361 return OK;
362 }
363
364 PrintingContext::Result PrintingContextChromeos::DocumentDone() {
365 if (abort_printing_)
366 return CANCEL;
367 DCHECK(in_print_job_);
368
369 if (!printer_->FinishDocument()) {
370 LOG(WARNING) << "Finishing document failed";
371 return OnError();
372 }
373
374 ipp_status_t job_status = printer_->CloseJob(job_id_);
375 job_id_ = 0;
376
377 if (job_status != IPP_STATUS_OK) {
378 LOG(WARNING) << "Closing job failed";
379 return OnError();
380 }
381
382 ResetSettings();
383 return OK;
384 }
385
386 void PrintingContextChromeos::Cancel() {
387 abort_printing_ = true;
388 in_print_job_ = false;
389 }
390
391 void PrintingContextChromeos::ReleaseContext() {
392 printer_.reset(nullptr);
393 options_.clear();
394 }
395
396 gfx::NativeDrawingContext PrintingContextChromeos::context() const {
397 // Intentional No-op.
398 return NULL;
399 }
400
401 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698