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

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: 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 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..3490062297b567d6167c953f14b22d7adcfbcb4b
--- /dev/null
+++ b/printing/printing_context_chromeos.cc
@@ -0,0 +1,401 @@
+// 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 <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";
+const char kResolution[] = "printer-resolution";
+
+// PWG 5100.13: JPS3
+const char kColorMode[] = "print-color-mode";
+
+const char kColorAuto[] = "auto";
+const char kPwgColor[] = "color";
+const char kPwgMonochrome[] = "monochrome";
+const char kColorBiLevel[] = "bi-level";
+const char kHighlight[] = "highlight";
+const char kProcessBiLevel[] = "process-bi-level";
+const char kProcessMonochrome[] = "process-monochrome";
+
+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.
+
+// 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) {
+ int value_len = value.size() + 1;
+ *dst = new char[value_len];
+ value.copy(*dst, value_len);
+ (*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 = NULL;
+ 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()) {
+ use_native_cups_ = true;
+ return base::WrapUnique(new PrintingContextChromeos(delegate));
+ }
+
+ use_native_cups_ = false;
+ return base::WrapUnique(new 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()) {
+ LOG(WARNING) << "No printer selected";
+ return OnError();
+ }
+
+ if (settings_.dpi() == 0) {
+ LOG(WARNING) << "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();
+
+ // 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
+ if (settings_.dpi() == 0) {
+ LOG(WARNING) << "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);
+
+ options_ = SettingsToCupsOptions(settings_);
+
+ return OK;
+}
+
+PrintingContext::Result PrintingContextChromeos::InitializeDevice(
+ const std::string& device) {
+ DCHECK(!in_print_job_);
+
+ CupsPrinter* printer = connection_.GetPrinter(device);
+ if (printer == nullptr) {
+ LOG(WARNING) << "Could not initialize device";
+ return OnError();
+ }
+
+ printer_.reset(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());
+
+ bool all_supported = true;
+
+ for (auto option : options_) {
+ bool supported = printer_->CheckOptionSupported(option.name, option.value);
+ all_supported = all_supported && supported;
+ }
+
+ if (!all_supported) {
+ LOG(WARNING) << "Unsupported options detected";
+ return OnError();
+ }
+
+ ipp_status_t create_status = printer_->CreateJob(&job_id_, title, options_);
+
+ if (job_id_ == 0) {
+ LOG(ERROR) << "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, 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(char* buffer,
+ int len) {
+ if (abort_printing_)
+ return CANCEL;
+ DCHECK(in_print_job_);
+ DCHECK(printer_);
+ DCHECK(use_native_cups_);
+
+ if (!printer_->StreamData(buffer, len))
+ 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(nullptr);
+ options_.clear();
+}
+
+gfx::NativeDrawingContext PrintingContextChromeos::context() const {
+ // Intentional No-op.
+ return NULL;
+}
+
+} // namespace printing

Powered by Google App Engine
This is Rietveld 408576698