| // 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 "chrome/browser/chromeos/arc/print/arc_print_service.h" |
| |
| #include <cups/cups.h> |
| |
| #include <limits> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind_helpers.h" |
| #include "base/memory/singleton.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task_scheduler/post_task.h" |
| #include "chrome/browser/chrome_notification_types.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_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/public/cpp/bindings/strong_binding.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 { |
| |
| class PrintJobHostImpl; |
| class PrinterDiscoverySessionHostImpl; |
| |
| class ArcPrintServiceImpl : public ArcPrintService, |
| public chromeos::CupsPrintJobManager::Observer, |
| public KeyedService { |
| public: |
| ArcPrintServiceImpl(content::BrowserContext* context, |
| ArcBridgeService* bridge_service); |
| ~ArcPrintServiceImpl() override; |
| |
| // KeyedService: |
| void Shutdown() override; |
| |
| // 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; |
| |
| void DeleteJob(PrintJobHostImpl* job); |
| void DeleteSession(PrinterDiscoverySessionHostImpl* session); |
| void JobIdGenerated(PrintJobHostImpl* job, const std::string& job_id); |
| |
| protected: |
| // 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. |
| class ArcPrintServiceFactory |
| : public internal::ArcBrowserContextKeyedServiceFactoryBase< |
| ArcPrintServiceImpl, |
| ArcPrintServiceFactory> { |
| public: |
| // Factory name used by ArcBrowserContextKeyedServiceFactoryBase. |
| static constexpr const char* kName = "ArcPrintServiceFactory"; |
| |
| static ArcPrintServiceFactory* GetInstance() { |
| return base::Singleton<ArcPrintServiceFactory>::get(); |
| } |
| |
| private: |
| friend base::DefaultSingletonTraits<ArcPrintServiceFactory>; |
| ArcPrintServiceFactory() = default; |
| ~ArcPrintServiceFactory() override = default; |
| }; |
| |
| // 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; |
| |
| file.Close(); |
| |
| auto metafile = std::make_unique<printing::PdfMetafileSkia>( |
| printing::SkiaDocumentType::PDF); |
| if (!metafile->InitFromData(buf.data(), buf.size())) { |
| LOG(ERROR) << "Failed to initialize PDF metafile"; |
| return nullptr; |
| } |
| return metafile; |
| } |
| |
| using PrinterQueryCallback = |
| base::OnceCallback<void(scoped_refptr<printing::PrinterQuery>)>; |
| |
| void OnSetSettingsDoneOnIOThread(scoped_refptr<printing::PrinterQuery> query, |
| 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))); |
| } |
| |
| // Send initialized PrinterQuery to UI thread. |
| void OnSetSettingsDoneOnIOThread(scoped_refptr<printing::PrinterQuery> query, |
| PrinterQueryCallback callback) { |
| content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, |
| base::BindOnce(std::move(callback), query)); |
| } |
| |
| std::unique_ptr<printing::PrinterSemanticCapsAndDefaults> |
| FetchCapabilitiesOnBlockingTaskRunner(const std::string& printer_id) { |
| 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; |
| } |
| 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}); |
| } |
| |
| // Transform printer capabilities to mojo type and send to container. |
| void CapabilitiesReceived( |
| std::unique_ptr<chromeos::Printer> printer, |
| std::unique_ptr<printing::PrinterSemanticCapsAndDefaults> caps) { |
| if (!caps) { |
| RemovePrinter(printer->id()); |
| 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_; |
| |
| 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( |
| FROM_HERE, {base::MayBlock()}, |
| base::BindOnce(&ReadFileOnBlockingTaskRunner, std::move(file), |
| data_size), |
| base::BindOnce(&PrintJobHostImpl::OnFileRead, |
| 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 ArcPrintServiceImpl::Shutdown() { |
| chromeos::CupsPrintJobManagerFactory::GetForBrowserContext(profile_) |
| ->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; |
| } |
| |
| 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())); |
| |
| // Chrome expects empty set of pages to mean "all". |
| // Android uses a single range from 0 to 2^31-1 for that purpose. |
| 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 |