Commit 4df4bf62 authored by tbarzic's avatar tbarzic Committed by Commit bot

Handle an extension printer supporting only PWG raster data

If an extension printer does not declare support for PDF in its
capabilities, convert print data to PWG raster before dispatching
print request to the extension.

BUG=408772

Review URL: https://codereview.chromium.org/919213002

Cr-Commit-Position: refs/heads/master@{#317012}
parent 836dc7a4
......@@ -4,21 +4,71 @@
#include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h"
#include <algorithm>
#include "base/bind.h"
#include "base/callback.h"
#include "base/values.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/task_runner_util.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/local_discovery/pwg_raster_converter.h"
#include "components/cloud_devices/common/cloud_device_description.h"
#include "components/cloud_devices/common/printer_description.h"
#include "extensions/browser/api/printer_provider/printer_provider_api.h"
#include "printing/print_job_constants.h"
#include "printing/pdf_render_settings.h"
#include "printing/pwg_raster_settings.h"
using local_discovery::PWGRasterConverter;
namespace {
const char kContentTypePdf[] = "application/pdf";
const char kContentTypePWGRaster[] = "image/pwg-raster";
const char kContentTypeAll[] = "*/*";
const char kInvalidDataPrintError[] = "INVALID_DATA";
// Reads raster data from file path |raster_path| and returns it as
// RefCountedMemory. Returns NULL on error.
scoped_refptr<base::RefCountedMemory> ReadConvertedPWGRasterFileOnWorkerThread(
const base::FilePath& raster_path) {
int64 file_size;
if (base::GetFileSize(raster_path, &file_size) &&
file_size <= extensions::PrinterProviderAPI::kMaxDocumentSize) {
std::string data;
data.reserve(file_size);
if (base::ReadFileToString(raster_path, &data)) {
return scoped_refptr<base::RefCountedMemory>(
base::RefCountedString::TakeString(&data));
}
} else {
LOG(ERROR) << "Invalid raster file size.";
}
return scoped_refptr<base::RefCountedMemory>();
}
// Posts a task to read a file containing converted PWG raster data to the
// worker pool.
void ReadConvertedPWGRasterFile(
const ExtensionPrinterHandler::RefCountedMemoryCallback& callback,
bool success,
const base::FilePath& pwg_file_path) {
if (!success) {
callback.Run(scoped_refptr<base::RefCountedMemory>());
return;
}
base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
base::Bind(&ReadConvertedPWGRasterFileOnWorkerThread, pwg_file_path),
callback);
}
} // namespace
ExtensionPrinterHandler::ExtensionPrinterHandler(
......@@ -59,11 +109,13 @@ void ExtensionPrinterHandler::StartPrint(
const std::string& destination_id,
const std::string& capability,
const std::string& ticket_json,
const gfx::Size& page_size,
const scoped_refptr<base::RefCountedMemory>& print_data,
const PrinterHandler::PrintCallback& callback) {
extensions::PrinterProviderAPI::PrintJob print_job;
print_job.printer_id = destination_id;
print_job.ticket_json = ticket_json;
scoped_ptr<extensions::PrinterProviderAPI::PrintJob> print_job(
new extensions::PrinterProviderAPI::PrintJob());
print_job->printer_id = destination_id;
print_job->ticket_json = ticket_json;
cloud_devices::CloudDeviceDescription printer_description;
printer_description.InitFromString(capability);
......@@ -74,20 +126,57 @@ void ExtensionPrinterHandler::StartPrint(
const bool kUsePdf = content_types.Contains(kContentTypePdf) ||
content_types.Contains(kContentTypeAll);
if (!kUsePdf) {
// TODO(tbarzic): Convert data to PWG raster if the printer does not support
// PDF.
if (kUsePdf) {
print_job->content_type = kContentTypePdf;
DispatchPrintJob(callback, print_job.Pass(), print_data);
return;
}
print_job->content_type = kContentTypePWGRaster;
ConvertToPWGRaster(print_data, printer_description, ticket_json, page_size,
base::Bind(&ExtensionPrinterHandler::DispatchPrintJob,
weak_ptr_factory_.GetWeakPtr(), callback,
base::Passed(&print_job)));
}
void ExtensionPrinterHandler::ConvertToPWGRaster(
const scoped_refptr<base::RefCountedMemory>& data,
const cloud_devices::CloudDeviceDescription& printer_description,
const std::string& ticket_json,
const gfx::Size& page_size,
const ExtensionPrinterHandler::RefCountedMemoryCallback& callback) {
cloud_devices::CloudDeviceDescription ticket;
if (!ticket.InitFromString(ticket_json)) {
callback.Run(scoped_refptr<base::RefCountedMemory>());
return;
}
if (!pwg_raster_converter_) {
pwg_raster_converter_ = PWGRasterConverter::CreateDefault();
}
pwg_raster_converter_->Start(
data.get(),
PWGRasterConverter::GetConversionSettings(printer_description, page_size),
PWGRasterConverter::GetBitmapSettings(printer_description, ticket),
base::Bind(&ReadConvertedPWGRasterFile, callback));
}
void ExtensionPrinterHandler::DispatchPrintJob(
const PrinterHandler::PrintCallback& callback,
scoped_ptr<extensions::PrinterProviderAPI::PrintJob> print_job,
const scoped_refptr<base::RefCountedMemory>& print_data) {
if (!print_data) {
WrapPrintCallback(callback, false, kInvalidDataPrintError);
return;
}
print_job.content_type = kContentTypePdf;
print_job.document_bytes = print_data;
print_job->document_bytes = print_data;
extensions::PrinterProviderAPI::GetFactoryInstance()
->Get(browser_context_)
->DispatchPrintRequested(
print_job, base::Bind(&ExtensionPrinterHandler::WrapPrintCallback,
weak_ptr_factory_.GetWeakPtr(), callback));
*print_job, base::Bind(&ExtensionPrinterHandler::WrapPrintCallback,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void ExtensionPrinterHandler::WrapGetPrintersCallback(
......
......@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
#include "extensions/browser/api/printer_provider/printer_provider_api.h"
namespace base {
class DictionaryValue;
......@@ -22,10 +23,25 @@ namespace content {
class BrowserContext;
}
namespace cloud_devices {
class CloudDeviceDescription;
}
namespace gfx {
class Size;
}
namespace local_discovery {
class PWGRasterConverter;
}
// Implementation of PrinterHandler interface backed by printerProvider
// extension API.
class ExtensionPrinterHandler : public PrinterHandler {
public:
using RefCountedMemoryCallback =
base::Callback<void(const scoped_refptr<base::RefCountedMemory>&)>;
explicit ExtensionPrinterHandler(content::BrowserContext* browser_context);
~ExtensionPrinterHandler() override;
......@@ -41,10 +57,29 @@ class ExtensionPrinterHandler : public PrinterHandler {
void StartPrint(const std::string& destination_id,
const std::string& capability,
const std::string& ticket_json,
const gfx::Size& page_size,
const scoped_refptr<base::RefCountedMemory>& print_data,
const PrinterHandler::PrintCallback& callback) override;
private:
// Converts |data| to PWG raster format (from PDF) for a printer described
// by |printer_description|.
// |callback| is called with the converted data.
void ConvertToPWGRaster(
const scoped_refptr<base::RefCountedMemory>& data,
const cloud_devices::CloudDeviceDescription& printer_description,
const std::string& ticket,
const gfx::Size& page_size,
const RefCountedMemoryCallback& callback);
// Sets print job document data and dispatches it using printerProvider API.
// TODO(tbarzic): Move PrinterProvider::PrintJob to it's own file so it can
// be forward-declared.
void DispatchPrintJob(
const PrinterHandler::PrintCallback& callback,
scoped_ptr<extensions::PrinterProviderAPI::PrintJob> print_job,
const scoped_refptr<base::RefCountedMemory>& data);
// Methods used as wrappers to callbacks for extensions::PrinterProviderAPI
// methods, primarily so the callbacks can be bound to this class' weak ptr.
// They just propagate results to callbacks passed to them.
......@@ -62,6 +97,8 @@ class ExtensionPrinterHandler : public PrinterHandler {
content::BrowserContext* browser_context_;
scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter_;
base::WeakPtrFactory<ExtensionPrinterHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ExtensionPrinterHandler);
......
......@@ -889,9 +889,14 @@ void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
std::string destination_id;
std::string print_ticket;
std::string capabilities;
int width = 0;
int height = 0;
if (!settings->GetString(printing::kSettingDeviceName, &destination_id) ||
!settings->GetString(printing::kSettingTicket, &print_ticket) ||
!settings->GetString(printing::kSettingCapabilities, &capabilities)) {
!settings->GetString(printing::kSettingCapabilities, &capabilities) ||
!settings->GetInteger(printing::kSettingPageWidth, &width) ||
!settings->GetInteger(printing::kSettingPageHeight, &height) ||
width <= 0 || height <= 0) {
NOTREACHED();
OnExtensionPrintResult(false, "FAILED");
return;
......@@ -907,9 +912,9 @@ void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
EnsureExtensionPrinterHandlerSet();
extension_printer_handler_->StartPrint(
destination_id, capabilities, print_ticket, data,
base::Bind(&PrintPreviewHandler::OnExtensionPrintResult,
base::Unretained(this)));
destination_id, capabilities, print_ticket, gfx::Size(width, height),
data, base::Bind(&PrintPreviewHandler::OnExtensionPrintResult,
base::Unretained(this)));
return;
}
......
......@@ -21,6 +21,10 @@ namespace content {
class BrowserContext;
}
namespace gfx {
class Size;
}
// Wrapper around PrinterProviderAPI to be used by print preview.
// It makes request lifetime management easier, and hides details of more
// complex operations like printing from the print preview handler.
......@@ -58,12 +62,15 @@ class PrinterHandler {
// |destination_id|: The printer to which print job should be sent.
// |capability|: Capability reported by the printer.
// |ticket_json|: The print job ticket as JSON string.
// |page_size|: The document page size.
// |print_data|: The document bytes to print.
// |callback| should be called in the response to the request.
// TODO(tbarzic): Page size should be extracted from print data.
virtual void StartPrint(
const std::string& destination_id,
const std::string& capability,
const std::string& ticket_json,
const gfx::Size& page_size,
const scoped_refptr<base::RefCountedMemory>& print_data,
const PrintCallback& callback) = 0;
};
......
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