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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: printing/printing_context_chromeos.cc
diff --git a/printing/printing_context_chromeos.cc b/printing/printing_context_chromeos.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d2b42c54ccba8717a056c5eb9875fdea1c9a1dd4
--- /dev/null
+++ b/printing/printing_context_chromeos.cc
@@ -0,0 +1,399 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/printing_context_chromeos.h"
+
+#include <cups/cups.h>
+#include <stdint.h>
+#include <unicode/ulocdata.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "printing/backend/cups_connection.h"
+#include "printing/backend/cups_ipp_util.h"
+#include "printing/backend/cups_printer.h"
+#include "printing/metafile.h"
+#include "printing/print_job_constants.h"
+#include "printing/print_settings.h"
+#include "printing/printing_context_no_system_dialog.h"
+#include "printing/units.h"
+
+namespace printing {
+
+namespace {
+
+const char kPageSize[] = "media";
+
+// PWG 5100.13: JPS3
+const char kColorMode[] = "print-color-mode";
+
+const char kPwgColor[] = "color";
+const char kPwgMonochrome[] = "monochrome";
+
+// convert from a ColorMode setting to a print-color-mode value from PWG 5100.13
+const char* GetColorModelForMode(int color_mode) {
+ const char* mode_string;
+ switch (color_mode) {
+ case COLOR:
+ case CMYK:
+ case CMY:
+ case KCMY:
+ case CMY_K:
+ case RGB:
+ case RGB16:
+ case RGBA:
+ case COLORMODE_COLOR:
+ case HP_COLOR_COLOR:
+ case PRINTOUTMODE_NORMAL:
+ case PROCESSCOLORMODEL_CMYK:
+ case PROCESSCOLORMODEL_RGB:
+ mode_string = kPwgColor;
+ break;
+ case GRAY:
+ case BLACK:
+ case GRAYSCALE:
+ case COLORMODE_MONOCHROME:
+ case HP_COLOR_BLACK:
+ case PRINTOUTMODE_NORMAL_GRAY:
+ case PROCESSCOLORMODEL_GREYSCALE:
+ mode_string = kPwgMonochrome;
+ break;
+ default:
+ mode_string = nullptr;
+ LOG(WARNING) << "Unrecognized color mode";
+ break;
+ }
+
+ return mode_string;
+}
+
+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.
+ 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.
+ *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
+ 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.
+ (*dst)[value_len - 1] = '\0';
+
+ return *dst;
+}
+
+cups_option_t ConstructOption(base::StringPiece name, base::StringPiece value) {
+ cups_option_t opt;
+ opt.name = CopyStringToChar(name, &opt.name);
+ opt.value = CopyStringToChar(value, &opt.value);
+
+ return opt;
+}
+
+std::vector<cups_option_t> SettingsToCupsOptions(
+ const PrintSettings& settings) {
+ const char* sides = nullptr;
+ switch (settings.duplex_mode()) {
+ case SIMPLEX:
+ sides = CUPS_SIDES_ONE_SIDED;
+ break;
+ case LONG_EDGE:
+ sides = CUPS_SIDES_TWO_SIDED_PORTRAIT;
+ break;
+ case SHORT_EDGE:
+ sides = CUPS_SIDES_TWO_SIDED_LANDSCAPE;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ std::vector<cups_option_t> cups_options = {
+ ConstructOption(kColorMode,
+ GetColorModelForMode(settings.color())), // color
+ ConstructOption(CUPS_SIDES, sides), // duplexing
+ ConstructOption(kPageSize,
+ settings.requested_media().vendor_id) // paper size
+ };
+
+ return cups_options;
+}
+
+void SetPrintableArea(PrintSettings* settings,
+ const PrintSettings::RequestedMedia& media,
+ bool flip) {
+ if (!media.size_microns.IsEmpty()) {
+ float deviceMicronsPerDeviceUnit =
+ (kHundrethsMMPerInch * 10.0f) / settings->device_units_per_inch();
+ gfx::Size paper_size =
+ gfx::Size(media.size_microns.width() / deviceMicronsPerDeviceUnit,
+ media.size_microns.height() / deviceMicronsPerDeviceUnit);
+
+ gfx::Rect paper_rect(0, 0, paper_size.width(), paper_size.height());
+ settings->SetPrinterPrintableArea(paper_size, paper_rect, flip);
+ }
+}
+
+} // namespace
+
+// static
+std::unique_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
+ 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.
+ return base::MakeUnique<PrintingContextChromeos>(delegate);
+ }
+
+ return base::MakeUnique<PrintingContextNoSystemDialog>(delegate);
+}
+
+PrintingContextChromeos::PrintingContextChromeos(Delegate* delegate)
+ : PrintingContext(delegate),
+ connection_(GURL(), HTTP_ENCRYPT_NEVER, true) {}
+
+PrintingContextChromeos::~PrintingContextChromeos() {
+ ReleaseContext();
+}
+
+void PrintingContextChromeos::AskUserForSettings(
+ int max_pages,
+ bool has_selection,
+ bool is_scripted,
+ const PrintSettingsCallback& callback) {
+ // We don't want to bring up a dialog here. Ever. Just signal the callback.
+ callback.Run(OK);
+}
+
+PrintingContext::Result PrintingContextChromeos::UseDefaultSettings() {
+ DCHECK(!in_print_job_);
+
+ ResetSettings();
+
+ std::string device_name = base::UTF16ToUTF8(settings_.device_name());
+ if (device_name.empty()) {
+ return OnError();
+ }
+
+ // TODO(skau): https://crbug.com/613779. See UpdatePrinterSettings for more
+ // info.
+ if (settings_.dpi() == 0) {
+ DVLOG(1) << "Using Default DPI";
+ settings_.set_dpi(kDefaultPdfDpi);
+ }
+
+ // Retrieve device information and set it
+ if (InitializeDevice(device_name) != OK) {
+ LOG(ERROR) << "Could not initialize printer";
+ return OnError();
+ }
+
+ // Set printable area
+ DCHECK(printer_);
+ PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
+
+ PrintSettings::RequestedMedia media;
+ media.vendor_id = paper.vendor_id;
+ media.size_microns = paper.size_um;
+ settings_.set_requested_media(media);
+
+ SetPrintableArea(&settings_, media, true /* flip landscape */);
+
+ return OK;
+}
+
+gfx::Size PrintingContextChromeos::GetPdfPaperSizeDeviceUnits() {
+ int32_t width = 0;
+ int32_t height = 0;
+ UErrorCode error = U_ZERO_ERROR;
+ ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
+ &error);
+ if (error > U_ZERO_ERROR) {
+ // If the call failed, assume a paper size of 8.5 x 11 inches.
+ LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
+ << error;
+ width =
+ static_cast<int>(kLetterWidthInch * settings_.device_units_per_inch());
+ height =
+ static_cast<int>(kLetterHeightInch * settings_.device_units_per_inch());
+ } else {
+ // ulocdata_getPaperSize returns the width and height in mm.
+ // Convert this to pixels based on the dpi.
+ float multiplier = 100 * settings_.device_units_per_inch();
+ multiplier /= kHundrethsMMPerInch;
+ width *= multiplier;
+ height *= multiplier;
+ }
+ return gfx::Size(width, height);
+}
+
+PrintingContext::Result PrintingContextChromeos::UpdatePrinterSettings(
+ bool external_preview,
+ bool show_system_dialog,
+ int page_count) {
+ DCHECK(!show_system_dialog);
+
+ if (InitializeDevice(base::UTF16ToUTF8(settings_.device_name())) != OK)
+ return OnError();
+
+ // TODO(skau): Convert to DCHECK when https://crbug.com/613779 is resolved
+ // Print quality suffers when this is set to the resolution reported by the
+ // printer but print quality is fine at this resolution. UseDefaultSettings
+ // exhibits the same problem.
+ if (settings_.dpi() == 0) {
+ DVLOG(1) << "Using Default DPI";
+ settings_.set_dpi(kDefaultPdfDpi);
+ }
+
+ // compute paper size
+ PrintSettings::RequestedMedia media = settings_.requested_media();
+
+ if (media.IsDefault()) {
+ DCHECK(printer_);
+ PrinterSemanticCapsAndDefaults::Paper paper = DefaultPaper(*printer_);
+
+ media.vendor_id = paper.vendor_id;
+ media.size_microns = paper.size_um;
+ settings_.set_requested_media(media);
+ }
+
+ SetPrintableArea(&settings_, media, true);
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::InitializeDevice(
+ const std::string& device) {
+ DCHECK(!in_print_job_);
+
+ std::unique_ptr<CupsPrinter> printer = connection_.GetPrinter(device);
+ if (!printer) {
+ LOG(WARNING) << "Could not initialize device";
+ return OnError();
+ }
+
+ printer_ = std::move(printer);
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::InitWithSettings(
+ const PrintSettings& settings) {
+ DCHECK(!in_print_job_);
+
+ settings_ = settings;
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::NewDocument(
+ const base::string16& document_name) {
+ DCHECK(!in_print_job_);
+ in_print_job_ = true;
+
+ std::string converted_name = base::UTF16ToUTF8(document_name);
+ std::string title = base::UTF16ToUTF8(settings_.title());
+ std::vector<cups_option_t> cups_options = SettingsToCupsOptions(settings_);
+
+ bool all_supported = true;
+
+ for (auto option : cups_options) {
+ bool supported = printer_->CheckOptionSupported(option.name, option.value);
+ all_supported = all_supported && supported;
+ }
+
+ if (!all_supported) {
+ DVLOG(1) << "Unsupported options detected";
+ return OnError();
+ }
+
+ ipp_status_t create_status =
+ printer_->CreateJob(&job_id_, title, cups_options);
+
+ if (job_id_ == 0) {
+ DLOG(WARNING) << "Creating cups job failed"
+ << ippErrorString(create_status);
+ return OnError();
+ }
+
+ // we only send one document, so it's always the last one
+ if (!printer_->StartDocument(job_id_, converted_name, true, cups_options)) {
+ LOG(ERROR) << "Starting document failed";
+ return OnError();
+ }
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::NewPage() {
+ if (abort_printing_)
+ return CANCEL;
+
+ DCHECK(in_print_job_);
+
+ // Intentional No-op.
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::StreamData(
+ const std::vector<char>& buffer) {
+ if (abort_printing_)
+ return CANCEL;
+
+ DCHECK(in_print_job_);
+ DCHECK(printer_);
+
+ if (!printer_->StreamData(buffer))
+ return OnError();
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::PageDone() {
+ if (abort_printing_)
+ return CANCEL;
+
+ DCHECK(in_print_job_);
+
+ // Intentional No-op.
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::DocumentDone() {
+ if (abort_printing_)
+ return CANCEL;
+
+ DCHECK(in_print_job_);
+
+ if (!printer_->FinishDocument()) {
+ LOG(WARNING) << "Finishing document failed";
+ return OnError();
+ }
+
+ ipp_status_t job_status = printer_->CloseJob(job_id_);
+ job_id_ = 0;
+
+ if (job_status != IPP_STATUS_OK) {
+ LOG(WARNING) << "Closing job failed";
+ return OnError();
+ }
+
+ ResetSettings();
+ return OK;
+}
+
+void PrintingContextChromeos::Cancel() {
+ abort_printing_ = true;
+ in_print_job_ = false;
+}
+
+void PrintingContextChromeos::ReleaseContext() {
+ printer_.reset();
+}
+
+gfx::NativeDrawingContext PrintingContextChromeos::context() const {
+ // Intentional No-op.
+ return nullptr;
+}
+
+} // namespace printing

Powered by Google App Engine
This is Rietveld 408576698