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

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: format and merge 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
« no previous file with comments | « printing/printing_context_chromeos.h ('k') | printing/printing_context_no_system_dialog.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..35f1587f30be727300aac8cd9a43eaf027c8fe3a
--- /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 <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.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 {
+
+using ScopedCupsOption = std::unique_ptr<cups_option_t, OptionDeleter>;
+
+// 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 = CUPS_PRINT_COLOR_MODE_COLOR;
+ break;
+ case GRAY:
+ case BLACK:
+ case GRAYSCALE:
+ case COLORMODE_MONOCHROME:
+ case HP_COLOR_BLACK:
+ case PRINTOUTMODE_NORMAL_GRAY:
+ case PROCESSCOLORMODEL_GREYSCALE:
+ mode_string = CUPS_PRINT_COLOR_MODE_MONOCHROME;
+ break;
+ default:
+ mode_string = nullptr;
+ LOG(WARNING) << "Unrecognized color mode";
+ break;
+ }
+
+ return mode_string;
+}
+
+// Returns a new char buffer which is a null-terminated copy of |value|. The
+// caller owns the returned string.
+char* DuplicateString(const base::StringPiece value) {
+ char* dst = new char[value.size() + 1];
+ value.copy(dst, value.size());
+ dst[value.size()] = '\0';
+ return dst;
+}
+
+ScopedCupsOption ConstructOption(const base::StringPiece name,
+ const base::StringPiece value) {
+ // ScopedCupsOption frees the name and value buffers on deletion
+ ScopedCupsOption option = ScopedCupsOption(new cups_option_t);
+ option->name = DuplicateString(name);
+ option->value = DuplicateString(value);
+ return option;
+}
+
+base::StringPiece GetCollateString(bool collate) {
+ return collate ? kCollated : kUncollated;
+}
+
+std::vector<ScopedCupsOption> 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<ScopedCupsOption> options;
+ options.push_back(
+ ConstructOption(kIppColor,
+ GetColorModelForMode(settings.color()))); // color
+ options.push_back(ConstructOption(kIppDuplex, sides)); // duplexing
+ options.push_back(
+ ConstructOption(kIppMedia,
+ settings.requested_media().vendor_id)); // paper size
+ options.push_back(
+ ConstructOption(kIppCopies,
+ base::IntToString(settings.copies()))); // copies
+ options.push_back(
+ ConstructOption(kIppCollate,
+ GetCollateString(settings.collate()))); // collate
+
+ return 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())
+ 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<ScopedCupsOption> cups_options = SettingsToCupsOptions(settings_);
+
+ std::vector<cups_option_t> options;
+ for (const ScopedCupsOption& option : cups_options) {
+ if (printer_->CheckOptionSupported(option->name, option->value)) {
+ options.push_back(*(option.get()));
+ } else {
+ DVLOG(1) << "Unsupported option skipped " << option->name << ", "
+ << option->value;
+ }
+ }
+
+ ipp_status_t create_status = printer_->CreateJob(&job_id_, title, 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, 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::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;
+}
+
+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;
+}
+
+} // namespace printing
« 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