Commit 53ccd0b5 authored by Vladislav Kuzkokov's avatar Vladislav Kuzkokov Committed by Commit Bot

ARC Print

This allows container to use native printers.

Bug: 625126
Change-Id: Idb1b1de9a11877fdfa9e9eb4e9ec87d4bf089ef7
Reviewed-on: https://chromium-review.googlesource.com/648979
Commit-Queue: Vladislav Kuzkokov <vkuzkokov@chromium.org>
Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarMattias Nissler <mnissler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536784}
parent be1d327b
per-file *_struct_traits*.*=set noparent
per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
......@@ -5,13 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_ARC_PRINT_ARC_PRINT_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_ARC_PRINT_ARC_PRINT_SERVICE_H_
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "components/arc/common/print.mojom.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
class BrowserContext;
......@@ -19,33 +13,17 @@ class BrowserContext;
namespace arc {
class ArcBridgeService;
class ArcPrintService : public KeyedService,
public mojom::PrintHost {
class ArcPrintService : public mojom::PrintHost {
public:
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
static ArcPrintService* GetForBrowserContext(
content::BrowserContext* context);
ArcPrintService(content::BrowserContext* context,
ArcBridgeService* bridge_service);
~ArcPrintService() override;
// mojom::PrintHost override:
void Print(mojo::ScopedHandle pdf_data) override;
protected:
ArcPrintService();
private:
// Opens the pdf file at |file_path|.
// If given |file_path| is nullopt, do nothing.
void OpenPdf(base::Optional<base::FilePath> file_path) const;
THREAD_CHECKER(thread_checker_);
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
base::WeakPtrFactory<ArcPrintService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ArcPrintService);
};
......
// Copyright 2018 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 "chrome/browser/chromeos/arc/print/print_struct_traits.h"
#include "base/strings/stringprintf.h"
#include "printing/units.h"
namespace mojo {
namespace {
// Transform paper size to Mojo type.
arc::mojom::PrintMediaSizePtr ToMediaSize(
const printing::PrinterSemanticCapsAndDefaults::Paper& paper) {
gfx::Size size_mil =
gfx::ScaleToRoundedSize(paper.size_um, 1.0f / printing::kMicronsPerMil);
return arc::mojom::PrintMediaSize::New(paper.vendor_id, paper.display_name,
size_mil.width(), size_mil.height());
}
} // namespace
std::string StructTraits<arc::mojom::PrintResolutionDataView, gfx::Size>::id(
const gfx::Size& size) {
return base::StringPrintf("%dx%d", size.width(), size.height());
}
std::vector<arc::mojom::PrintMediaSizePtr>
StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults>::
media_sizes(const printing::PrinterSemanticCapsAndDefaults& caps) {
std::vector<arc::mojom::PrintMediaSizePtr> sizes;
sizes.reserve(caps.papers.size());
for (const auto& paper : caps.papers)
sizes.emplace_back(ToMediaSize(paper));
return sizes;
}
arc::mojom::PrintMarginsPtr
StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults>::
min_margins(const printing::PrinterSemanticCapsAndDefaults& caps) {
return arc::mojom::PrintMargins::New(0, 0, 0, 0);
}
arc::mojom::PrintColorMode
StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults>::
color_modes(const printing::PrinterSemanticCapsAndDefaults& caps) {
auto color_modes = static_cast<arc::mojom::PrintColorMode>(0);
if (caps.bw_model != printing::UNKNOWN_COLOR_MODEL) {
color_modes = static_cast<arc::mojom::PrintColorMode>(
static_cast<uint32_t>(color_modes) |
static_cast<uint32_t>(arc::mojom::PrintColorMode::MONOCHROME));
}
if (caps.color_model != printing::UNKNOWN_COLOR_MODEL) {
color_modes = static_cast<arc::mojom::PrintColorMode>(
static_cast<uint32_t>(color_modes) |
static_cast<uint32_t>(arc::mojom::PrintColorMode::COLOR));
}
return color_modes;
}
arc::mojom::PrintDuplexMode
StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults>::
duplex_modes(const printing::PrinterSemanticCapsAndDefaults& caps) {
arc::mojom::PrintDuplexMode duplex_modes = arc::mojom::PrintDuplexMode::NONE;
if (caps.duplex_capable) {
duplex_modes = static_cast<arc::mojom::PrintDuplexMode>(
static_cast<uint32_t>(duplex_modes) |
static_cast<uint32_t>(arc::mojom::PrintDuplexMode::LONG_EDGE) |
static_cast<uint32_t>(arc::mojom::PrintDuplexMode::SHORT_EDGE));
}
return duplex_modes;
}
arc::mojom::PrintAttributesPtr
StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults>::
defaults(const printing::PrinterSemanticCapsAndDefaults& caps) {
arc::mojom::PrintDuplexMode default_duplex_mode;
switch (caps.duplex_default) {
case printing::LONG_EDGE:
default_duplex_mode = arc::mojom::PrintDuplexMode::LONG_EDGE;
break;
case printing::SHORT_EDGE:
default_duplex_mode = arc::mojom::PrintDuplexMode::SHORT_EDGE;
break;
default:
default_duplex_mode = arc::mojom::PrintDuplexMode::NONE;
}
return arc::mojom::PrintAttributes::New(
ToMediaSize(caps.default_paper), caps.default_dpi,
arc::mojom::PrintMargins::New(0, 0, 0, 0),
caps.color_default ? arc::mojom::PrintColorMode::COLOR
: arc::mojom::PrintColorMode::MONOCHROME,
default_duplex_mode);
}
} // namespace mojo
// Copyright 2018 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.
#ifndef CHROME_BROWSER_CHROMEOS_ARC_PRINT_PRINT_STRUCT_TRAITS_H_
#define CHROME_BROWSER_CHROMEOS_ARC_PRINT_PRINT_STRUCT_TRAITS_H_
#include <string>
#include <vector>
#include "components/arc/common/print.mojom.h"
#include "printing/backend/print_backend.h"
#include "printing/page_range.h"
#include "ui/gfx/geometry/size.h"
namespace mojo {
template <>
struct StructTraits<arc::mojom::PrintPageRangeDataView, printing::PageRange> {
static uint32_t start(const printing::PageRange& r) { return r.from; }
static uint32_t end(const printing::PageRange& r) { return r.to; }
static bool Read(arc::mojom::PrintPageRangeDataView data,
printing::PageRange* out) {
out->from = data.start();
out->to = data.end();
return true;
}
};
template <>
struct StructTraits<arc::mojom::PrintResolutionDataView, gfx::Size> {
static uint32_t horizontal_dpi(const gfx::Size& size) { return size.width(); }
static uint32_t vertical_dpi(const gfx::Size& size) { return size.width(); }
static std::string id(const gfx::Size& size);
static std::string label(const gfx::Size& size) { return id(size); }
static bool Read(arc::mojom::PrintResolutionDataView data, gfx::Size* out) {
*out = gfx::Size(data.horizontal_dpi(), data.vertical_dpi());
return true;
}
};
// TODO(vkuzkokov): PrinterSemanticCapsAndDefaults has no margins, boolean
// duplex_capable, and unlabeled resolutions.
template <>
struct StructTraits<arc::mojom::PrinterCapabilitiesDataView,
printing::PrinterSemanticCapsAndDefaults> {
static std::vector<arc::mojom::PrintMediaSizePtr> media_sizes(
const printing::PrinterSemanticCapsAndDefaults& caps);
static const std::vector<gfx::Size>& resolutions(
const printing::PrinterSemanticCapsAndDefaults& caps) {
return caps.dpis;
}
static arc::mojom::PrintMarginsPtr min_margins(
const printing::PrinterSemanticCapsAndDefaults& caps);
static arc::mojom::PrintColorMode color_modes(
const printing::PrinterSemanticCapsAndDefaults& caps);
static arc::mojom::PrintDuplexMode duplex_modes(
const printing::PrinterSemanticCapsAndDefaults& caps);
static arc::mojom::PrintAttributesPtr defaults(
const printing::PrinterSemanticCapsAndDefaults& caps);
static bool Read(arc::mojom::PrinterCapabilitiesDataView data,
printing::PrinterSemanticCapsAndDefaults* out) {
// This is never used.
NOTREACHED();
return false;
}
};
} // namespace mojo
#endif // CHROME_BROWSER_CHROMEOS_ARC_PRINT_PRINT_STRUCT_TRAITS_H_
......@@ -306,18 +306,10 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
// Must be run from the UI thread.
void CancelPrintJob(CupsPrintJob* job) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Copy job_id and printer_id. |job| is about to be freed.
const int job_id = job->job_id();
const std::string printer_id = job->printer().id();
// Stop montioring jobs after we cancel them. The user no longer cares.
jobs_.erase(job->GetUniqueId());
query_runner_->PostTask(
FROM_HERE,
base::Bind(&CupsWrapper::CancelJobImpl,
base::Unretained(cups_wrapper_.get()), printer_id, job_id));
job->set_state(CupsPrintJob::State::STATE_CANCELLED);
NotifyJobCanceled(job);
// Ideally we should wait for IPP response.
FinishPrintJob(job);
}
bool SuspendPrintJob(CupsPrintJob* job) override {
......@@ -396,6 +388,20 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
return true;
}
void FinishPrintJob(CupsPrintJob* job) {
// Copy job_id and printer_id. |job| is about to be freed.
const int job_id = job->job_id();
const std::string printer_id = job->printer().id();
// Stop montioring jobs after we cancel them. The user no longer cares.
jobs_.erase(job->GetUniqueId());
query_runner_->PostTask(
FROM_HERE, base::BindOnce(&CupsWrapper::CancelJobImpl,
base::Unretained(cups_wrapper_.get()),
printer_id, job_id));
}
// Schedule a query of CUPS for print job status with a delay of |delay|.
void ScheduleQuery(int attempt_count = 1) {
const int delay_ms = kPollRate * attempt_count;
......@@ -473,11 +479,11 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
if (print_job->expired()) {
// Job needs to be forcibly cancelled.
RecordJobResult(TIMEOUT_CANCEL);
CancelPrintJob(print_job);
FinishPrintJob(print_job);
// Beware, print_job was removed from jobs_ and deleted.
} else if (print_job->PipelineDead()) {
RecordJobResult(FILTER_FAILED);
CancelPrintJob(print_job);
FinishPrintJob(print_job);
} else if (print_job->IsJobFinished()) {
// Cleanup completed jobs.
VLOG(1) << "Removing Job " << print_job->document_title();
......
......@@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
......@@ -205,6 +206,20 @@ void PrintJobWorker::SetSettings(
base::Unretained(this), std::move(new_settings))));
}
#if defined(OS_CHROMEOS)
void PrintJobWorker::SetSettingsFromPOD(
std::unique_ptr<printing::PrintSettings> new_settings) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(
&HoldRefCallback, base::WrapRefCounted(owner_),
base::BindOnce(&PrintJobWorker::UpdatePrintSettingsFromPOD,
base::Unretained(this), std::move(new_settings))));
}
#endif
void PrintJobWorker::UpdatePrintSettings(
std::unique_ptr<base::DictionaryValue> new_settings) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
......@@ -213,6 +228,16 @@ void PrintJobWorker::UpdatePrintSettings(
GetSettingsDone(result);
}
#if defined(OS_CHROMEOS)
void PrintJobWorker::UpdatePrintSettingsFromPOD(
std::unique_ptr<printing::PrintSettings> new_settings) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PrintingContext::Result result =
printing_context_->UpdatePrintSettingsFromPOD(std::move(new_settings));
GetSettingsDone(result);
}
#endif
void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
// Most PrintingContext functions may start a message loop and process
// message recursively, so disable recursive task processing.
......
......@@ -54,9 +54,15 @@ class PrintJobWorker {
bool is_scripted,
bool is_modifiable);
// Set the new print settings.
// Set the new print settings from a dictionary value.
void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings);
#if defined(OS_CHROMEOS)
// Set the new print settings from a POD type.
void SetSettingsFromPOD(
std::unique_ptr<printing::PrintSettings> new_settings);
#endif
// Starts the printing loop. Every pages are printed as soon as the data is
// available. Makes sure the new_document is the right one.
void StartPrinting(PrintedDocument* new_document);
......@@ -129,6 +135,12 @@ class PrintJobWorker {
// Called on the UI thread to update the print settings.
void UpdatePrintSettings(std::unique_ptr<base::DictionaryValue> new_settings);
#if defined(OS_CHROMEOS)
// Called on the UI thread to update the print settings.
void UpdatePrintSettingsFromPOD(
std::unique_ptr<printing::PrintSettings> new_settings);
#endif
// Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result);
......
......@@ -99,6 +99,19 @@ void PrinterQuery::SetSettings(
std::move(new_settings)));
}
#if defined(OS_CHROMEOS)
void PrinterQuery::SetSettingsFromPOD(
std::unique_ptr<printing::PrintSettings> new_settings,
base::OnceClosure callback) {
StartWorker(std::move(callback));
worker_->PostTask(
FROM_HERE,
base::BindOnce(&PrintJobWorker::SetSettingsFromPOD,
base::Unretained(worker_.get()), std::move(new_settings)));
}
#endif
void PrinterQuery::StartWorker(base::OnceClosure callback) {
DCHECK(!callback_);
DCHECK(worker_);
......
......@@ -55,6 +55,12 @@ class PrinterQuery : public PrintJobWorkerOwner {
void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings,
base::OnceClosure callback);
#if defined(OS_CHROMEOS)
// Updates the current settings with |new_settings|.
void SetSettingsFromPOD(std::unique_ptr<printing::PrintSettings> new_settings,
base::OnceClosure callback);
#endif
// Stops the worker thread since the client is done with this object.
void StopWorker();
......
......@@ -6,12 +6,193 @@
module arc.mojom;
// android.print.PageRange
struct PrintPageRange {
// First page inclusive.
int32 start;
// Last page inclusive.
int32 end;
};
// android.print.PrintAttributes.MediaSize
struct PrintMediaSize {
// Id unique among media sizes.
string id;
// Localized label.
string label;
int32 width_mils;
int32 height_mils;
};
// android.print.PrintAttributes.Resolution
struct PrintResolution {
// Id unique among resolutions.
string id;
// Localized label.
string label;
int32 horizontal_dpi;
int32 vertical_dpi;
};
// android.print.PrintAttributes.Margins
struct PrintMargins {
int32 left_mils;
int32 top_mils;
int32 right_mils;
int32 bottom_mils;
};
// android.print.PrintAttributes.COLOR_MODE_*
[Extensible]
enum PrintColorMode {
MONOCHROME = 1,
COLOR = 2,
};
// android.print.PrintAttributes.DUPLEX_MODE_*
[Extensible]
enum PrintDuplexMode {
NONE = 1,
LONG_EDGE = 2,
SHORT_EDGE = 4,
};
// android.print.PrintDocumentInfo.CONTENT_TYPE_*
[Extensible]
enum PrintContentType {
UNKNOWN = -1,
DOCUMENT = 0,
PHOTO = 1,
};
// android.print.PrintAttributes
struct PrintAttributes {
PrintMediaSize? media_size;
PrintResolution? resolution;
PrintMargins? min_margins;
PrintColorMode color_mode;
PrintDuplexMode duplex_mode;
};
struct PrintJobRequest {
// android.printservice.PrintJob fields:
array<int8> id;
string label;
string? printer_id;
int64 creation_time;
int32 copies;
array<PrintPageRange> pages;
PrintAttributes attributes;
// android.print.PrintDocumentInfo fields:
string document_name;
int32 document_page_count;
PrintContentType content_type;
int64 data_size;
// android.printservice.PrintDocument fields:
handle? data;
};
// android.print.PrinterInfo.STATUS_*
[Extensible]
enum PrinterStatus {
IDLE = 1,
BUSY = 2,
UNAVAILABLE = 3,
};
// android.print.PrinterCapabilitiesInfo
struct PrinterCapabilities {
array<PrintMediaSize> media_sizes;
array<PrintResolution> resolutions;
PrintMargins min_margins;
PrintColorMode color_modes;
PrintDuplexMode duplex_modes;
PrintAttributes defaults;
};
// android.print.PrinterInfo
struct PrinterInfo {
// Id unique among printers.
string id;
// Localized name.
string name;
PrinterStatus status;
// Localized description.
string? description;
// Intent for provider-specific settings.
string? info_intent;
PrinterCapabilities? capabilities;
};
// android.printservice.PrinterDiscoverySession implementation.
// This is called by container when printing is requested and printer discovery
// has to start. Implemented in embedder.
// The normal order this is called is:
// StartPrinterDiscovery
// StartPrinterStateTracking
// StopPrinterStateTracking
// StopPrinterDiscovery
// DestroyDiscoverySession
// (ValidatePrinters is not used in practice)
//
// Next method ID: 6
interface PrinterDiscoverySessionHost {
StartPrinterDiscovery@0(array<string> printer_ids);
StopPrinterDiscovery@1();
ValidatePrinters@2(array<string> printer_ids);
StartPrinterStateTracking@3(string printer_id);
StopPrinterStateTracking@4(string printer_id);
DestroyDiscoverySession@5();
};
// android.printservice.PrinterDiscoverySession final methods proxy.
// This is called by embedder when printer discovery is active.
// Implemented in container.
// Next method ID: 2
interface PrinterDiscoverySessionInstance {
AddPrinters@0(array<PrinterInfo> printers);
RemovePrinters@1(array<string> printers);
};
// android.printservice.PrintService.onRequestCancelPrintJob implementation.
// This is called by container when job cancellation was requested.
// Implemented in embedder.
// Next method ID: 1
interface PrintJobHost {
Cancel@0();
};
// android.printservice.PrintJob proxy.
// This is called by embedder when print job status changes.
// Implemented in container.
// See https://developer.android.com/reference/android/printservice/PrintJob.html
// Next method ID: 7
interface PrintJobInstance {
Start@0();
Block@1(string? reason);
Complete@2();
Fail@3(string? reason);
Cancel@4();
SetProgress@5(float progress);
SetStatus@6(string? status);
};
// android.printservice.PrintService implementation.
// This is called by container to create new discovery sessions and print jobs.
// Implemented in embedder.
// Next method ID: 2
// Deprecated method ID: 0
interface PrintHost {
Print@0(handle file);
PrintDeprecated@0(handle file);
[MinVersion=1] Print@1(PrintJobInstance instance, PrintJobRequest request) => (PrintJobHost host);
[MinVersion=1] CreateDiscoverySession@2(PrinterDiscoverySessionInstance instance) =>
(PrinterDiscoverySessionHost host);
};
// This is called by embedder to indicate that it's ready to accept print jobs.
// Implemented in container.
// Next method ID: 2
// Deprecated method ID: 0
interface PrintInstance {
// DEPRECATED: Please use Init@1 instead.
InitDeprecated@0(PrintHost host_ptr);
......
mojom = "//components/arc/common/print.mojom"
public_headers = [
"//printing/backend/print_backend.h",
"//printing/page_range.h",
"//ui/gfx/geometry/size.h",
]
traits_headers = [ "//chrome/browser/chromeos/arc/print/print_struct_traits.h" ]
sources = [
"//chrome/browser/chromeos/arc/print/print_struct_traits.cc",
]
deps = []
public_deps = [
"//printing:printing",
]
type_mappings = [
"arc.mojom.PrintPageRange=printing::PageRange",
"arc.mojom.PrintResolution=gfx::Size",
"arc.mojom.PrinterCapabilities=printing::PrinterSemanticCapsAndDefaults",
]
......@@ -9,6 +9,7 @@ typemaps = [
"//components/arc/common/file_system.typemap",
"//components/arc/common/gfx.typemap",
"//components/arc/common/intent_helper.typemap",
"//components/arc/common/print.typemap",
"//components/arc/common/timer.typemap",
"//components/arc/common/video_common.typemap",
"//components/arc/common/video_encode_accelerator.typemap",
......
......@@ -141,4 +141,16 @@ PrintingContext::Result PrintingContext::UpdatePrintSettings(
page_count);
}
#if defined(OS_CHROMEOS)
PrintingContext::Result PrintingContext::UpdatePrintSettingsFromPOD(
std::unique_ptr<PrintSettings> job_settings) {
ResetSettings();
settings_ = *job_settings;
return UpdatePrinterSettings(false /* external_preview */,
false /* show_system_dialog */,
0 /* page_count is only used on Android */);
}
#endif
} // namespace printing
......@@ -86,6 +86,12 @@ class PRINTING_EXPORT PrintingContext {
// settings information. |ranges| has the new page range settings.
Result UpdatePrintSettings(const base::DictionaryValue& job_settings);
#if defined(OS_CHROMEOS)
// Updates Print Settings.
Result UpdatePrintSettingsFromPOD(
std::unique_ptr<PrintSettings> job_settings);
#endif
// Does platform specific setup of the printer before the printing. Signal the
// printer that a document is about to be spooled.
// Warning: This function enters a message loop. That may cause side effects
......
......@@ -12,6 +12,10 @@ namespace printing {
// Length of a thousandth of inches in 0.01mm unit.
const int kHundrethsMMPerInch = 2540;
// Mil is a thousandth of an inch.
constexpr float kMicronsPerMil = 25.4f;
constexpr int kMilsPerInch = 1000;
// Length of an inch in CSS's 1pt unit.
// http://dev.w3.org/csswg/css3-values/#absolute-length-units-cm-mm.-in-pt-pc
const int kPointsPerInch = 72;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment