Commit e2199101 authored by Vladislav Kuzkokov's avatar Vladislav Kuzkokov Committed by Commit Bot

Reland "ARC Print"

This is a reland of 53ccd0b5.
TBR=thestig@chromium.org,mnissler@chromium.org

Original change's description:
> 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: Luis Hector Chavez <lhchavez@chromium.org>
> Reviewed-by: Lei Zhang <thestig@chromium.org>
> Reviewed-by: Mattias Nissler <mnissler@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#536784}

Bug: 625126
Change-Id: I569a36ee57e6495525efcc44820b65f03146dc26
Reviewed-on: https://chromium-review.googlesource.com/925481Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Commit-Queue: Vladislav Kuzkokov <vkuzkokov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537791}
parent 3520fb17
per-file *_struct_traits*.*=set noparent
per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
...@@ -4,55 +4,94 @@ ...@@ -4,55 +4,94 @@
#include "chrome/browser/chromeos/arc/print/arc_print_service.h" #include "chrome/browser/chromeos/arc/print/arc_print_service.h"
#include <limits>
#include <memory>
#include <string>
#include <utility> #include <utility>
#include <vector>
#include "ash/shell.h" #include "base/bind_helpers.h"
#include "ash/shell_delegate.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h" #include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h" #include "chrome/browser/chrome_notification_types.h"
#include "base/threading/thread_restrictions.h" #include "chrome/browser/chromeos/printing/cups_print_job.h"
#include "chrome/browser/chromeos/printing/cups_print_job_manager.h"
#include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h"
#include "chrome/browser/chromeos/printing/cups_printers_manager.h"
#include "chrome/browser/chromeos/printing/printer_configurer.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/browser/profiles/profile.h"
#include "components/arc/arc_bridge_service.h" #include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/common/child_process_host.h"
#include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/embedder.h"
#include "net/base/filename_util.h" #include "mojo/public/cpp/bindings/strong_binding.h"
#include "url/gurl.h" #include "printing/backend/print_backend.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/pdf_metafile_skia.h"
#include "printing/print_job_constants.h"
#include "printing/printed_document.h"
#include "printing/units.h"
namespace arc {
namespace { namespace {
base::Optional<base::FilePath> SavePdf(base::File file) { class PrintJobHostImpl;
base::AssertBlockingAllowed(); class PrinterDiscoverySessionHostImpl;
base::FilePath file_path; class ArcPrintServiceImpl : public ArcPrintService,
base::CreateTemporaryFile(&file_path); public chromeos::CupsPrintJobManager::Observer,
base::File out(file_path, public KeyedService {
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); public:
ArcPrintServiceImpl(content::BrowserContext* context,
ArcBridgeService* bridge_service);
~ArcPrintServiceImpl() override;
char buf[8192]; // KeyedService:
ssize_t bytes; void Shutdown() override;
while ((bytes = file.ReadAtCurrentPos(buf, sizeof(buf))) > 0) {
int written = out.WriteAtCurrentPos(buf, bytes);
if (written < 0) {
LOG(ERROR) << "Error while saving PDF to a disk";
return base::nullopt;
}
}
return file_path; // mojom::PrintHost:
} void PrintDeprecated(mojo::ScopedHandle pdf_data) override;
void Print(mojom::PrintJobInstancePtr instance,
mojom::PrintJobRequestPtr print_job,
PrintCallback callback) override;
void CreateDiscoverySession(
mojom::PrinterDiscoverySessionInstancePtr instance,
CreateDiscoverySessionCallback callback) override;
} // namespace void DeleteJob(PrintJobHostImpl* job);
void DeleteSession(PrinterDiscoverySessionHostImpl* session);
void JobIdGenerated(PrintJobHostImpl* job, const std::string& job_id);
namespace arc { protected:
namespace { // chromeos::CupsPrintJobManager::Observer:
void OnPrintJobCreated(chromeos::CupsPrintJob* job) override;
void OnPrintJobCancelled(chromeos::CupsPrintJob* job) override;
void OnPrintJobError(chromeos::CupsPrintJob* job) override;
void OnPrintJobDone(chromeos::CupsPrintJob* job) override;
private:
Profile* const profile_; // Owned by ProfileManager.
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
std::map<PrintJobHostImpl*, std::unique_ptr<PrintJobHostImpl>> jobs_;
std::map<PrinterDiscoverySessionHostImpl*,
std::unique_ptr<PrinterDiscoverySessionHostImpl>>
sessions_;
// Managed by PrintJobHostImpl instances.
std::map<std::string, PrintJobHostImpl*> jobs_by_id_;
};
// Singleton factory for ArcPrintService. // Singleton factory for ArcPrintService.
class ArcPrintServiceFactory class ArcPrintServiceFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase< : public internal::ArcBrowserContextKeyedServiceFactoryBase<
ArcPrintService, ArcPrintServiceImpl,
ArcPrintServiceFactory> { ArcPrintServiceFactory> {
public: public:
// Factory name used by ArcBrowserContextKeyedServiceFactoryBase. // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
...@@ -68,56 +107,531 @@ class ArcPrintServiceFactory ...@@ -68,56 +107,531 @@ class ArcPrintServiceFactory
~ArcPrintServiceFactory() override = default; ~ArcPrintServiceFactory() override = default;
}; };
} // namespace // This creates a Metafile instance which is a wrapper around a byte buffer at
// this point.
std::unique_ptr<printing::PdfMetafileSkia> ReadFileOnBlockingTaskRunner(
base::File file,
size_t data_size) {
// TODO(vkuzkokov) Can we make give pipe to CUPS directly?
std::vector<char> buf(data_size);
int bytes = file.ReadAtCurrentPos(buf.data(), data_size);
if (bytes < 0) {
PLOG(ERROR) << "Error reading PDF";
return nullptr;
}
if (static_cast<size_t>(bytes) != data_size)
return nullptr;
// static file.Close();
ArcPrintService* ArcPrintService::GetForBrowserContext(
content::BrowserContext* context) { auto metafile = std::make_unique<printing::PdfMetafileSkia>();
return ArcPrintServiceFactory::GetForBrowserContext(context); if (!metafile->InitFromData(buf.data(), buf.size())) {
LOG(ERROR) << "Failed to initialize PDF metafile";
return nullptr;
}
return metafile;
} }
ArcPrintService::ArcPrintService(content::BrowserContext* context, using PrinterQueryCallback =
ArcBridgeService* bridge_service) base::OnceCallback<void(scoped_refptr<printing::PrinterQuery>)>;
: arc_bridge_service_(bridge_service),
weak_ptr_factory_(this) { void OnSetSettingsDoneOnIOThread(scoped_refptr<printing::PrinterQuery> query,
arc_bridge_service_->print()->SetHost(this); PrinterQueryCallback callback);
void CreateQueryOnIOThread(std::unique_ptr<printing::PrintSettings> settings,
PrinterQueryCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
auto query = base::MakeRefCounted<printing::PrinterQuery>(
content::ChildProcessHost::kInvalidUniqueID,
content::ChildProcessHost::kInvalidUniqueID);
query->SetSettingsFromPOD(
std::move(settings),
base::BindOnce(&OnSetSettingsDoneOnIOThread, query, std::move(callback)));
} }
ArcPrintService::~ArcPrintService() { // Send initialized PrinterQuery to UI thread.
arc_bridge_service_->print()->SetHost(nullptr); void OnSetSettingsDoneOnIOThread(scoped_refptr<printing::PrinterQuery> query,
PrinterQueryCallback callback) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::BindOnce(std::move(callback), query));
} }
void ArcPrintService::Print(mojo::ScopedHandle pdf_data) { std::unique_ptr<printing::PrinterSemanticCapsAndDefaults>
if (!pdf_data.is_valid()) { FetchCapabilitiesOnBlockingTaskRunner(const std::string& printer_id) {
LOG(ERROR) << "handle is invalid"; scoped_refptr<printing::PrintBackend> backend(
printing::PrintBackend::CreateInstance(nullptr));
auto caps = std::make_unique<printing::PrinterSemanticCapsAndDefaults>();
if (!backend->GetPrinterSemanticCapsAndDefaults(printer_id, caps.get())) {
LOG(ERROR) << "Failed to get caps for " << printer_id;
return nullptr;
}
return caps;
}
// Transform printer info to Mojo type and add capabilities, if present.
mojom::PrinterInfoPtr ToArcPrinter(
const chromeos::Printer& printer,
std::unique_ptr<printing::PrinterSemanticCapsAndDefaults> caps) {
return mojom::PrinterInfo::New(
printer.id(), printer.display_name(), mojom::PrinterStatus::IDLE,
printer.description(), base::nullopt,
caps ? base::make_optional<printing::PrinterSemanticCapsAndDefaults>(
std::move(*caps))
: base::nullopt);
}
// PrinterDiscoverySessionHost implementation.
class PrinterDiscoverySessionHostImpl
: public mojom::PrinterDiscoverySessionHost,
public chromeos::CupsPrintersManager::Observer {
public:
PrinterDiscoverySessionHostImpl(
mojo::InterfaceRequest<mojom::PrinterDiscoverySessionHost> request,
mojom::PrinterDiscoverySessionInstancePtr instance,
ArcPrintServiceImpl* service,
Profile* profile)
: binding_(this, std::move(request)),
instance_(std::move(instance)),
service_(service),
printers_manager_(chromeos::CupsPrintersManager::Create(profile)),
configurer_(chromeos::PrinterConfigurer::Create(profile)),
weak_ptr_factory_(this) {
printers_manager_->AddObserver(this);
binding_.set_connection_error_handler(MakeErrorHandler());
instance_.set_connection_error_handler(MakeErrorHandler());
}
~PrinterDiscoverySessionHostImpl() override {
printers_manager_->RemoveObserver(this);
}
// mojom::PrinterDiscoverySessionHost:
void StartPrinterDiscovery(
const std::vector<std::string>& printer_ids) override {
std::vector<mojom::PrinterInfoPtr> arc_printers;
for (size_t i = 0; i < chromeos::CupsPrintersManager::kNumPrinterClasses;
i++) {
std::vector<chromeos::Printer> printers = printers_manager_->GetPrinters(
static_cast<chromeos::CupsPrintersManager::PrinterClass>(i));
for (const auto& printer : printers)
arc_printers.emplace_back(ToArcPrinter(printer, nullptr));
}
if (!arc_printers.empty())
instance_->AddPrinters(std::move(arc_printers));
}
void StopPrinterDiscovery() override {
// Do nothing
}
void ValidatePrinters(const std::vector<std::string>& printer_ids) override {
// TODO(vkuzkokov) implement or determine that we don't need to.
}
void StartPrinterStateTracking(const std::string& printer_id) override {
std::unique_ptr<chromeos::Printer> printer =
printers_manager_->GetPrinter(printer_id);
if (!printer) {
RemovePrinter(printer_id);
return;
}
if (printers_manager_->IsPrinterInstalled(*printer)) {
PrinterInstalled(std::move(printer), chromeos::kSuccess);
return;
}
const chromeos::Printer& printer_ref = *printer;
configurer_->SetUpPrinter(
printer_ref,
base::BindOnce(&PrinterDiscoverySessionHostImpl::PrinterInstalled,
weak_ptr_factory_.GetWeakPtr(), std::move(printer)));
}
void StopPrinterStateTracking(const std::string& printer_id) override {
// Do nothing
}
void DestroyDiscoverySession() override { service_->DeleteSession(this); }
// chromeos::CupsPrintersManager::Observer:
void OnPrintersChanged(
chromeos::CupsPrintersManager::PrinterClass printer_class,
const std::vector<chromeos::Printer>& printers) override {
// TODO(vkuzkokov) remove missing printers and only add new ones.
std::vector<mojom::PrinterInfoPtr> arc_printers;
for (const auto& printer : printers)
arc_printers.emplace_back(ToArcPrinter(printer, nullptr));
instance_->AddPrinters(std::move(arc_printers));
}
private:
base::OnceClosure MakeErrorHandler() {
return base::BindOnce(
&PrinterDiscoverySessionHostImpl::DestroyDiscoverySession,
weak_ptr_factory_.GetWeakPtr());
}
// Fetch capabilities for newly installed printer.
void PrinterInstalled(std::unique_ptr<chromeos::Printer> printer,
chromeos::PrinterSetupResult result) {
if (result != chromeos::kSuccess) {
RemovePrinter(printer->id());
return; return;
} }
printers_manager_->PrinterInstalled(*printer);
const std::string& printer_id = printer->id();
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&FetchCapabilitiesOnBlockingTaskRunner, printer_id),
base::BindOnce(&PrinterDiscoverySessionHostImpl::CapabilitiesReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(printer)));
}
// Remove from the list of available printers.
void RemovePrinter(const std::string& printer_id) {
instance_->RemovePrinters(std::vector<std::string>{printer_id});
}
mojo::edk::ScopedPlatformHandle scoped_platform_handle; // Transform printer capabilities to mojo type and send to container.
MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( void CapabilitiesReceived(
pdf_data.release().value(), &scoped_platform_handle); std::unique_ptr<chromeos::Printer> printer,
if (mojo_result != MOJO_RESULT_OK) { std::unique_ptr<printing::PrinterSemanticCapsAndDefaults> caps) {
LOG(ERROR) << "PassWrappedPlatformHandle failed: " << mojo_result; if (!caps) {
RemovePrinter(printer->id());
return; return;
} }
std::vector<mojom::PrinterInfoPtr> arc_printers;
arc_printers.emplace_back(ToArcPrinter(*printer, std::move(caps)));
instance_->AddPrinters(std::move(arc_printers));
}
// Binds |this|.
mojo::Binding<mojom::PrinterDiscoverySessionHost> binding_;
base::File file(scoped_platform_handle.release().handle); mojom::PrinterDiscoverySessionInstancePtr instance_;
ArcPrintServiceImpl* const service_;
std::unique_ptr<chromeos::CupsPrintersManager> printers_manager_;
std::unique_ptr<chromeos::PrinterConfigurer> configurer_;
base::WeakPtrFactory<PrinterDiscoverySessionHostImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PrinterDiscoverySessionHostImpl);
};
// Get requested color mode from Mojo type.
// |mode| is a bitfield but must have exactly one mode set here.
printing::ColorModel FromArcColorMode(mojom::PrintColorMode mode) {
switch (mode) {
case mojom::PrintColorMode::MONOCHROME:
return printing::GRAY;
case mojom::PrintColorMode::COLOR:
return printing::COLOR;
}
NOTREACHED();
}
// Get requested duplex mode from Mojo type.
// |mode| is a bitfield but must have exactly one mode set here.
printing::DuplexMode FromArcDuplexMode(mojom::PrintDuplexMode mode) {
switch (mode) {
case mojom::PrintDuplexMode::NONE:
return printing::SIMPLEX;
case mojom::PrintDuplexMode::LONG_EDGE:
return printing::LONG_EDGE;
case mojom::PrintDuplexMode::SHORT_EDGE:
return printing::SHORT_EDGE;
}
NOTREACHED();
}
// This represents a single request from container. Object of this class
// self-destructs when the request is completed, successfully or otherwise.
class PrintJobHostImpl : public mojom::PrintJobHost,
public content::NotificationObserver {
public:
PrintJobHostImpl(mojo::InterfaceRequest<mojom::PrintJobHost> request,
mojom::PrintJobInstancePtr instance,
ArcPrintServiceImpl* service,
chromeos::CupsPrintJobManager* job_manager,
std::unique_ptr<printing::PrintSettings> settings,
base::File file,
size_t data_size)
: binding_(this, std::move(request)),
instance_(std::move(instance)),
service_(service),
job_manager_(job_manager),
weak_ptr_factory_(this) {
// We read printing data from pipe on working thread in parallel with
// initializing PrinterQuery on IO thread. When both tasks are complete we
// start printing.
base::PostTaskWithTraitsAndReplyWithResult( base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()}, FROM_HERE, {base::MayBlock()},
base::BindOnce(&SavePdf, base::Passed(&file)), base::BindOnce(&ReadFileOnBlockingTaskRunner, std::move(file),
base::BindOnce(&ArcPrintService::OpenPdf, data_size),
base::BindOnce(&PrintJobHostImpl::OnFileRead,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&CreateQueryOnIOThread, std::move(settings),
base::BindOnce(&PrintJobHostImpl::OnSetSettingsDone,
weak_ptr_factory_.GetWeakPtr())));
binding_.set_connection_error_handler(MakeErrorHandler());
instance_.set_connection_error_handler(MakeErrorHandler());
}
void CupsJobCreated(chromeos::CupsPrintJob* cups_job) {
cups_job_ = cups_job;
}
void JobCanceled() {
instance_->Cancel();
service_->DeleteJob(this);
}
void JobError() {
// TODO(vkuzkokov) transform cups_job_->error_code() into localized string.
instance_->Fail({});
service_->DeleteJob(this);
}
void JobDone() {
instance_->Complete();
service_->DeleteJob(this);
}
// mojom::PrintJobHost:
void Cancel() override {
if (cups_job_) {
// Job already spooled.
job_manager_->CancelPrintJob(cups_job_);
} else {
JobCanceled();
}
}
// content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override {
DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_EVENT, type);
const printing::JobEventDetails& event_details =
*content::Details<printing::JobEventDetails>(details).ptr();
switch (event_details.type()) {
case printing::JobEventDetails::DOC_DONE:
DCHECK(event_details.document());
service_->JobIdGenerated(
this, chromeos::CupsPrintJob::GetUniqueId(
base::UTF16ToUTF8(
event_details.document()->settings().device_name()),
event_details.job_id()));
break;
case printing::JobEventDetails::FAILED:
// TODO(vkuzkokov) see if we can extract an error message.
JobError();
break;
default:
// TODO(vkuzkokov) consider updating container on other events.
break;
}
}
private:
void Destroy() { service_->DeleteJob(this); }
base::OnceClosure MakeErrorHandler() {
return base::BindOnce(&PrintJobHostImpl::Destroy,
weak_ptr_factory_.GetWeakPtr());
}
// Store Metafile and start printing if PrintJob is created as well.
void OnFileRead(std::unique_ptr<printing::PdfMetafileSkia> metafile) {
metafile_ = std::move(metafile);
StartPrintingIfReady();
}
// Create PrintJob and start printing if Metafile is created as well.
void OnSetSettingsDone(scoped_refptr<printing::PrinterQuery> query) {
job_ = base::MakeRefCounted<printing::PrintJob>();
job_->Initialize(query.get(), base::string16() /* name */,
1 /* page_count */);
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<printing::PrintJob>(job_.get()));
StartPrintingIfReady();
}
// If both PrintJob and Metafile are available start printing.
void StartPrintingIfReady() {
if (!job_ || !metafile_)
return;
printing::PrintedDocument* document = job_->document();
document->SetDocument(std::move(metafile_) /* metafile */,
gfx::Size() /* paper_size */,
gfx::Rect() /* page_rect */);
job_->StartPrinting();
}
// Binds the lifetime of |this| to the Mojo connection.
mojo::Binding<mojom::PrintJobHost> binding_;
mojom::PrintJobInstancePtr instance_;
ArcPrintServiceImpl* const service_;
chromeos::CupsPrintJobManager* const job_manager_;
std::unique_ptr<printing::PdfMetafileSkia> metafile_;
scoped_refptr<printing::PrintJob> job_;
chromeos::CupsPrintJob* cups_job_;
content::NotificationRegistrar registrar_;
base::WeakPtrFactory<PrintJobHostImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintJobHostImpl);
};
ArcPrintServiceImpl::ArcPrintServiceImpl(content::BrowserContext* context,
ArcBridgeService* bridge_service)
: profile_(Profile::FromBrowserContext(context)),
arc_bridge_service_(bridge_service) {
arc_bridge_service_->print()->SetHost(this);
chromeos::CupsPrintJobManagerFactory::GetForBrowserContext(profile_)
->AddObserver(this);
}
ArcPrintServiceImpl::~ArcPrintServiceImpl() {
arc_bridge_service_->print()->SetHost(nullptr);
} }
void ArcPrintService::OpenPdf(base::Optional<base::FilePath> file_path) const { void ArcPrintServiceImpl::Shutdown() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); chromeos::CupsPrintJobManagerFactory::GetForBrowserContext(profile_)
if (!file_path) ->RemoveObserver(this);
}
void ArcPrintServiceImpl::OnPrintJobCreated(chromeos::CupsPrintJob* job) {
auto it = jobs_by_id_.find(job->GetUniqueId());
if (it != jobs_by_id_.end())
it->second->CupsJobCreated(job);
}
void ArcPrintServiceImpl::OnPrintJobCancelled(chromeos::CupsPrintJob* job) {
auto it = jobs_by_id_.find(job->GetUniqueId());
if (it != jobs_by_id_.end())
it->second->JobCanceled();
}
void ArcPrintServiceImpl::OnPrintJobError(chromeos::CupsPrintJob* job) {
auto it = jobs_by_id_.find(job->GetUniqueId());
if (it != jobs_by_id_.end())
it->second->JobError();
}
void ArcPrintServiceImpl::OnPrintJobDone(chromeos::CupsPrintJob* job) {
auto it = jobs_by_id_.find(job->GetUniqueId());
if (it != jobs_by_id_.end())
it->second->JobDone();
}
void ArcPrintServiceImpl::PrintDeprecated(mojo::ScopedHandle pdf_data) {
LOG(ERROR) << "ArcPrintService::Print(ScopedHandle) is deprecated.";
}
void ArcPrintServiceImpl::Print(mojom::PrintJobInstancePtr instance,
mojom::PrintJobRequestPtr print_job,
PrintCallback callback) {
instance->Start();
const mojom::PrintAttributesPtr& attr = print_job->attributes;
const mojom::PrintMediaSizePtr& arc_media = attr->media_size;
const base::Optional<gfx::Size> resolution = attr->resolution;
if (!arc_media || !resolution) {
// TODO(vkuzkokov): localize
instance->Fail(base::Optional<std::string>(
base::in_place,
"Print request must contain media size and resolution"));
return; return;
}
const mojom::PrintMarginsPtr& margins = attr->min_margins;
auto settings = std::make_unique<printing::PrintSettings>();
gfx::Size size_mils(arc_media->width_mils, arc_media->height_mils);
printing::PrintSettings::RequestedMedia media;
media.size_microns =
gfx::ScaleToRoundedSize(size_mils, printing::kMicronsPerMil);
settings->set_requested_media(media);
// TODO(vkuzkokov) Is it just max(dpm_hor, dpm_ver) as per
// print_settings_conversion?
float x_scale =
static_cast<float>(resolution->width()) / printing::kMilsPerInch;
float y_scale =
static_cast<float>(resolution->height()) / printing::kMilsPerInch;
settings->set_dpi_xy(resolution->width(), resolution->height());
gfx::Rect area_mils(size_mils);
if (margins) {
area_mils.Inset(margins->left_mils, margins->top_mils, margins->right_mils,
margins->bottom_mils);
}
settings->SetPrinterPrintableArea(
gfx::ScaleToRoundedSize(size_mils, x_scale, y_scale),
gfx::ScaleToRoundedRect(area_mils, x_scale, y_scale), false);
if (print_job->printer_id)
settings->set_device_name(base::UTF8ToUTF16(print_job->printer_id.value()));
GURL gurl = net::FilePathToFileURL(file_path.value()); // Chrome expects empty set of pages to mean "all".
ash::Shell::Get()->shell_delegate()->OpenUrlFromArc(gurl); // Android uses a single range from 0 to 2^31-1 for that purpose.
// TODO(poromov) Delete file after printing. (http://crbug.com/629843) const printing::PageRanges& pages = print_job->pages;
if (!pages.empty() && pages.back().to != std::numeric_limits<int>::max())
settings->set_ranges(pages);
settings->set_title(base::UTF8ToUTF16(print_job->document_name));
settings->set_color(FromArcColorMode(attr->color_mode));
settings->set_copies(print_job->copies);
settings->set_duplex_mode(FromArcDuplexMode(attr->duplex_mode));
mojo::edk::ScopedPlatformHandle scoped_handle;
PassWrappedPlatformHandle(print_job->data.release().value(), &scoped_handle);
mojom::PrintJobHostPtr host_proxy;
auto job = std::make_unique<PrintJobHostImpl>(
mojo::MakeRequest(&host_proxy), std::move(instance), this,
chromeos::CupsPrintJobManagerFactory::GetForBrowserContext(profile_),
std::move(settings), base::File(scoped_handle.release().handle),
print_job->data_size);
PrintJobHostImpl* job_raw = job.get();
jobs_.emplace(job_raw, std::move(job));
std::move(callback).Run(std::move(host_proxy));
}
void ArcPrintServiceImpl::CreateDiscoverySession(
mojom::PrinterDiscoverySessionInstancePtr instance,
CreateDiscoverySessionCallback callback) {
mojom::PrinterDiscoverySessionHostPtr host_proxy;
auto session = std::make_unique<PrinterDiscoverySessionHostImpl>(
mojo::MakeRequest(&host_proxy), std::move(instance), this, profile_);
PrinterDiscoverySessionHostImpl* session_raw = session.get();
sessions_.emplace(session_raw, std::move(session));
std::move(callback).Run(std::move(host_proxy));
}
void ArcPrintServiceImpl::DeleteJob(PrintJobHostImpl* job) {
jobs_.erase(job);
}
void ArcPrintServiceImpl::DeleteSession(
PrinterDiscoverySessionHostImpl* session) {
sessions_.erase(session);
}
void ArcPrintServiceImpl::JobIdGenerated(PrintJobHostImpl* job,
const std::string& job_id) {
jobs_by_id_.emplace(job_id, job);
} }
} // namespace
// static
ArcPrintService* ArcPrintService::GetForBrowserContext(
content::BrowserContext* context) {
return ArcPrintServiceFactory::GetForBrowserContext(context);
}
ArcPrintService::ArcPrintService() {}
} // namespace arc } // namespace arc
...@@ -5,13 +5,7 @@ ...@@ -5,13 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_ARC_PRINT_ARC_PRINT_SERVICE_H_ #ifndef CHROME_BROWSER_CHROMEOS_ARC_PRINT_ARC_PRINT_SERVICE_H_
#define 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/arc/common/print.mojom.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content { namespace content {
class BrowserContext; class BrowserContext;
...@@ -19,33 +13,17 @@ class BrowserContext; ...@@ -19,33 +13,17 @@ class BrowserContext;
namespace arc { namespace arc {
class ArcBridgeService; class ArcPrintService : public mojom::PrintHost {
class ArcPrintService : public KeyedService,
public mojom::PrintHost {
public: public:
// Returns singleton instance for the given BrowserContext, // Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC. // or nullptr if the browser |context| is not allowed to use ARC.
static ArcPrintService* GetForBrowserContext( static ArcPrintService* GetForBrowserContext(
content::BrowserContext* context); content::BrowserContext* context);
ArcPrintService(content::BrowserContext* context, protected:
ArcBridgeService* bridge_service); ArcPrintService();
~ArcPrintService() override;
// mojom::PrintHost override:
void Print(mojo::ScopedHandle pdf_data) override;
private: 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); 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, ...@@ -306,18 +306,10 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
// Must be run from the UI thread. // Must be run from the UI thread.
void CancelPrintJob(CupsPrintJob* job) override { void CancelPrintJob(CupsPrintJob* job) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
job->set_state(CupsPrintJob::State::STATE_CANCELLED);
// Copy job_id and printer_id. |job| is about to be freed. NotifyJobCanceled(job);
const int job_id = job->job_id(); // Ideally we should wait for IPP response.
const std::string printer_id = job->printer().id(); FinishPrintJob(job);
// 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));
} }
bool SuspendPrintJob(CupsPrintJob* job) override { bool SuspendPrintJob(CupsPrintJob* job) override {
...@@ -396,6 +388,20 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager, ...@@ -396,6 +388,20 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
return true; 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|. // Schedule a query of CUPS for print job status with a delay of |delay|.
void ScheduleQuery(int attempt_count = 1) { void ScheduleQuery(int attempt_count = 1) {
const int delay_ms = kPollRate * attempt_count; const int delay_ms = kPollRate * attempt_count;
...@@ -473,11 +479,11 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager, ...@@ -473,11 +479,11 @@ class CupsPrintJobManagerImpl : public CupsPrintJobManager,
if (print_job->expired()) { if (print_job->expired()) {
// Job needs to be forcibly cancelled. // Job needs to be forcibly cancelled.
RecordJobResult(TIMEOUT_CANCEL); RecordJobResult(TIMEOUT_CANCEL);
CancelPrintJob(print_job); FinishPrintJob(print_job);
// Beware, print_job was removed from jobs_ and deleted. // Beware, print_job was removed from jobs_ and deleted.
} else if (print_job->PipelineDead()) { } else if (print_job->PipelineDead()) {
RecordJobResult(FILTER_FAILED); RecordJobResult(FILTER_FAILED);
CancelPrintJob(print_job); FinishPrintJob(print_job);
} else if (print_job->IsJobFinished()) { } else if (print_job->IsJobFinished()) {
// Cleanup completed jobs. // Cleanup completed jobs.
VLOG(1) << "Removing Job " << print_job->document_title(); VLOG(1) << "Removing Job " << print_job->document_title();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
...@@ -205,6 +206,20 @@ void PrintJobWorker::SetSettings( ...@@ -205,6 +206,20 @@ void PrintJobWorker::SetSettings(
base::Unretained(this), std::move(new_settings)))); 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( void PrintJobWorker::UpdatePrintSettings(
std::unique_ptr<base::DictionaryValue> new_settings) { std::unique_ptr<base::DictionaryValue> new_settings) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -213,6 +228,16 @@ void PrintJobWorker::UpdatePrintSettings( ...@@ -213,6 +228,16 @@ void PrintJobWorker::UpdatePrintSettings(
GetSettingsDone(result); 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) { void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
// Most PrintingContext functions may start a message loop and process // Most PrintingContext functions may start a message loop and process
// message recursively, so disable recursive task processing. // message recursively, so disable recursive task processing.
......
...@@ -54,9 +54,15 @@ class PrintJobWorker { ...@@ -54,9 +54,15 @@ class PrintJobWorker {
bool is_scripted, bool is_scripted,
bool is_modifiable); 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); 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 // Starts the printing loop. Every pages are printed as soon as the data is
// available. Makes sure the new_document is the right one. // available. Makes sure the new_document is the right one.
void StartPrinting(PrintedDocument* new_document); void StartPrinting(PrintedDocument* new_document);
...@@ -129,6 +135,12 @@ class PrintJobWorker { ...@@ -129,6 +135,12 @@ class PrintJobWorker {
// Called on the UI thread to update the print settings. // Called on the UI thread to update the print settings.
void UpdatePrintSettings(std::unique_ptr<base::DictionaryValue> new_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_. // Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result); void GetSettingsDone(PrintingContext::Result result);
......
...@@ -99,6 +99,19 @@ void PrinterQuery::SetSettings( ...@@ -99,6 +99,19 @@ void PrinterQuery::SetSettings(
std::move(new_settings))); 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) { void PrinterQuery::StartWorker(base::OnceClosure callback) {
DCHECK(!callback_); DCHECK(!callback_);
DCHECK(worker_); DCHECK(worker_);
......
...@@ -55,6 +55,12 @@ class PrinterQuery : public PrintJobWorkerOwner { ...@@ -55,6 +55,12 @@ class PrinterQuery : public PrintJobWorkerOwner {
void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings, void SetSettings(std::unique_ptr<base::DictionaryValue> new_settings,
base::OnceClosure callback); 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. // Stops the worker thread since the client is done with this object.
void StopWorker(); void StopWorker();
......
...@@ -6,12 +6,193 @@ ...@@ -6,12 +6,193 @@
module arc.mojom; 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 // 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 { 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 // Next method ID: 2
// Deprecated method ID: 0
interface PrintInstance { interface PrintInstance {
// DEPRECATED: Please use Init@1 instead. // DEPRECATED: Please use Init@1 instead.
InitDeprecated@0(PrintHost host_ptr); 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 = [ ...@@ -9,6 +9,7 @@ typemaps = [
"//components/arc/common/file_system.typemap", "//components/arc/common/file_system.typemap",
"//components/arc/common/gfx.typemap", "//components/arc/common/gfx.typemap",
"//components/arc/common/intent_helper.typemap", "//components/arc/common/intent_helper.typemap",
"//components/arc/common/print.typemap",
"//components/arc/common/timer.typemap", "//components/arc/common/timer.typemap",
"//components/arc/common/video_common.typemap", "//components/arc/common/video_common.typemap",
"//components/arc/common/video_encode_accelerator.typemap", "//components/arc/common/video_encode_accelerator.typemap",
......
...@@ -141,4 +141,16 @@ PrintingContext::Result PrintingContext::UpdatePrintSettings( ...@@ -141,4 +141,16 @@ PrintingContext::Result PrintingContext::UpdatePrintSettings(
page_count); 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 } // namespace printing
...@@ -86,6 +86,12 @@ class PRINTING_EXPORT PrintingContext { ...@@ -86,6 +86,12 @@ class PRINTING_EXPORT PrintingContext {
// settings information. |ranges| has the new page range settings. // settings information. |ranges| has the new page range settings.
Result UpdatePrintSettings(const base::DictionaryValue& job_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 // Does platform specific setup of the printer before the printing. Signal the
// printer that a document is about to be spooled. // printer that a document is about to be spooled.
// Warning: This function enters a message loop. That may cause side effects // Warning: This function enters a message loop. That may cause side effects
......
...@@ -12,6 +12,10 @@ namespace printing { ...@@ -12,6 +12,10 @@ namespace printing {
// Length of a thousandth of inches in 0.01mm unit. // Length of a thousandth of inches in 0.01mm unit.
const int kHundrethsMMPerInch = 2540; 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. // Length of an inch in CSS's 1pt unit.
// http://dev.w3.org/csswg/css3-values/#absolute-length-units-cm-mm.-in-pt-pc // http://dev.w3.org/csswg/css3-values/#absolute-length-units-cm-mm.-in-pt-pc
const int kPointsPerInch = 72; 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