Commit 779d6a04 authored by Nikita Podguzov's avatar Nikita Podguzov Committed by Commit Bot

Printing API: Add PrintJobController component

This component is responsible for actual sending print job to the
Chrome printing pipeline.

Bug: 996785
Change-Id: I9d1e2f2b55fffbf0d876af222fdebb0b8d0989a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1962200Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarSean Kau <skau@chromium.org>
Commit-Queue: Nikita Podguzov <nikitapodguzov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732317}
parent 63628067
...@@ -2408,6 +2408,8 @@ source_set("chromeos") { ...@@ -2408,6 +2408,8 @@ source_set("chromeos") {
"//chrome/services/cups_proxy/public/mojom", "//chrome/services/cups_proxy/public/mojom",
] ]
sources += [ sources += [
"extensions/printing/print_job_controller.cc",
"extensions/printing/print_job_controller.h",
"extensions/printing/printing_api.cc", "extensions/printing/printing_api.cc",
"extensions/printing/printing_api.h", "extensions/printing/printing_api.h",
"extensions/printing/printing_api_handler.cc", "extensions/printing/printing_api_handler.cc",
......
// Copyright 2020 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/extensions/printing/print_job_controller.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/task/post_task.h"
#include "chrome/browser/printing/printer_query.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/child_process_host.h"
#include "printing/metafile_skia.h"
#include "printing/print_settings.h"
#include "printing/printed_document.h"
namespace extensions {
namespace {
using PrinterQueryCallback =
base::OnceCallback<void(std::unique_ptr<printing::PrinterQuery>)>;
// Send initialized PrinterQuery to UI thread.
void OnSettingsSetOnIOThread(std::unique_ptr<printing::PrinterQuery> query,
PrinterQueryCallback callback) {
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(std::move(callback), std::move(query)));
}
void CreateQueryOnIOThread(std::unique_ptr<printing::PrintSettings> settings,
PrinterQueryCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
auto query = std::make_unique<printing::PrinterQuery>(
content::ChildProcessHost::kInvalidUniqueID,
content::ChildProcessHost::kInvalidUniqueID);
auto* query_ptr = query.get();
query_ptr->SetSettingsFromPOD(
std::move(settings),
base::BindOnce(&OnSettingsSetOnIOThread, std::move(query),
std::move(callback)));
}
} // namespace
PrintJobController::JobState::JobState(scoped_refptr<printing::PrintJob> job,
StartPrintJobCallback callback)
: job(job), callback(std::move(callback)) {}
PrintJobController::JobState::JobState(JobState&&) = default;
PrintJobController::JobState& PrintJobController::JobState::operator=(
JobState&&) = default;
PrintJobController::JobState::~JobState() = default;
PrintJobController::PrintJobController() = default;
PrintJobController::~PrintJobController() = default;
void PrintJobController::StartPrintJob(
const std::string& extension_id,
std::unique_ptr<printing::MetafileSkia> metafile,
std::unique_ptr<printing::PrintSettings> settings,
StartPrintJobCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::PostTask(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(
&CreateQueryOnIOThread, std::move(settings),
base::BindOnce(&PrintJobController::StartPrinting,
weak_ptr_factory_.GetWeakPtr(), extension_id,
std::move(metafile), std::move(callback))));
}
void PrintJobController::StartPrinting(
const std::string& extension_id,
std::unique_ptr<printing::MetafileSkia> metafile,
StartPrintJobCallback callback,
std::unique_ptr<printing::PrinterQuery> query) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto job = base::MakeRefCounted<printing::PrintJob>();
// Save in separate variable because |query| is moved.
base::string16 title = query->settings().title();
job->Initialize(std::move(query), title, /*page_count=*/1);
job->SetSource(printing::PrintJob::Source::EXTENSION, extension_id);
printing::PrintedDocument* document = job->document();
// |paper_size| and |page_rect| are used only for OS_MACOSX, so just use
// default constructor values.
document->SetDocument(std::move(metafile),
/*paper_size=*/gfx::Size(),
/*page_rect=*/gfx::Rect());
// Save PrintJob scoped refptr and callback to resolve when print job is
// created.
extension_pending_jobs_[extension_id].emplace(job, std::move(callback));
job->StartPrinting();
}
void PrintJobController::OnPrintJobCreated(const std::string& extension_id,
const std::string& job_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto it = extension_pending_jobs_.find(extension_id);
if (it == extension_pending_jobs_.end())
return;
auto& pending_jobs = it->second;
if (!pending_jobs.empty()) {
// We need to move corresponding scoped refptr of PrintJob from queue
// of pending pointers to global map. We can't drop it as the print job is
// not completed yet so we should not destruct it.
print_jobs_map_[job_id] = pending_jobs.front().job;
// The job is submitted to CUPS so we have to resolve the first callback
// in the corresponding queue.
auto callback = std::move(pending_jobs.front().callback);
pending_jobs.pop();
if (pending_jobs.empty())
extension_pending_jobs_.erase(it);
std::move(callback).Run(std::make_unique<std::string>(job_id));
}
}
void PrintJobController::OnPrintJobFinished(const std::string& job_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
print_jobs_map_.erase(job_id);
}
} // namespace extensions
// Copyright 2020 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_EXTENSIONS_PRINTING_PRINT_JOB_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_PRINT_JOB_CONTROLLER_H_
#include <memory>
#include <string>
#include "base/callback_forward.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/printing/print_job.h"
namespace printing {
class MetafileSkia;
class PrinterQuery;
class PrintSettings;
} // namespace printing
namespace extensions {
// This class is responsible for sending print jobs in the printing pipeline and
// cancelling them. It should be used by API handler as the entry point of
// actual printing pipeline.
// This class lives on UI thread.
class PrintJobController {
public:
using StartPrintJobCallback =
base::OnceCallback<void(std::unique_ptr<std::string> job_id)>;
PrintJobController();
~PrintJobController();
// Creates, initializes and adds print job to the queue of pending print jobs.
void StartPrintJob(const std::string& extension_id,
std::unique_ptr<printing::MetafileSkia> metafile,
std::unique_ptr<printing::PrintSettings> settings,
StartPrintJobCallback callback);
// Moves print job pointer to |print_jobs_map_| and resolves corresponding
// callback.
// This should be called when CupsPrintJobManager created CupsPrintJob.
void OnPrintJobCreated(const std::string& extension_id,
const std::string& job_id);
// Removes print job pointer from |print_jobs_map_| as the job is finished.
// This should be called when CupsPrintJob is finished (it could be either
// completed, failed or cancelled).
void OnPrintJobFinished(const std::string& job_id);
private:
struct JobState {
scoped_refptr<printing::PrintJob> job;
StartPrintJobCallback callback;
JobState(scoped_refptr<printing::PrintJob> job,
StartPrintJobCallback callback);
JobState(JobState&&);
JobState& operator=(JobState&&);
~JobState();
};
void StartPrinting(const std::string& extension_id,
std::unique_ptr<printing::MetafileSkia> metafile,
StartPrintJobCallback callback,
std::unique_ptr<printing::PrinterQuery> query);
// Stores mapping from extension id to queue of pending jobs to resolve.
// Placing a job state in the map means that we sent print job to the printing
// pipeline and have been waiting for the response with created job id.
// After that we could resolve a callback and move PrintJob to global map.
// We need to store job pointers to keep the current scheduled print jobs
// alive (as they're ref counted).
base::flat_map<std::string, base::queue<JobState>> extension_pending_jobs_;
// Stores mapping from job id to printing::PrintJob.
// This is needed to hold PrintJob pointer and correct handle CancelJob()
// requests.
base::flat_map<std::string, scoped_refptr<printing::PrintJob>>
print_jobs_map_;
base::WeakPtrFactory<PrintJobController> weak_ptr_factory_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_PRINTING_PRINT_JOB_CONTROLLER_H_
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