summaryrefslogtreecommitdiffstats
path: root/chrome/service
diff options
context:
space:
mode:
authorsanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 20:15:30 +0000
committersanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 20:15:30 +0000
commita4db67d8bcfc6174c887e895b88d19efeea3d31d (patch)
tree10b4bea11216c76013630ed64259bbe2aaf57b05 /chrome/service
parent9c549acbadf14aaafef7edc981f0e5718a3bdbf6 (diff)
downloadchromium_src-a4db67d8bcfc6174c887e895b88d19efeea3d31d.zip
chromium_src-a4db67d8bcfc6174c887e895b88d19efeea3d31d.tar.gz
chromium_src-a4db67d8bcfc6174c887e895b88d19efeea3d31d.tar.bz2
Used the service utility process host to render PDFs in a sandbox for the Windows cloud print proxy. Also made the print spooling asynchronous.
BUG=None TEST=Test cloud print proxy on all supported platforms. Review URL: http://codereview.chromium.org/3051006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53238 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/service')
-rw-r--r--chrome/service/cloud_print/print_system.h75
-rw-r--r--chrome/service/cloud_print/print_system_cups.cc135
-rw-r--r--chrome/service/cloud_print/print_system_win.cc241
-rw-r--r--chrome/service/cloud_print/printer_job_handler.cc64
-rw-r--r--chrome/service/cloud_print/printer_job_handler.h24
5 files changed, 369 insertions, 170 deletions
diff --git a/chrome/service/cloud_print/print_system.h b/chrome/service/cloud_print/print_system.h
index b7d0ce5..1d83a87 100644
--- a/chrome/service/cloud_print/print_system.h
+++ b/chrome/service/cloud_print/print_system.h
@@ -81,35 +81,6 @@ struct PrintJobDetails {
// functionality on some platforms, while reusing core (CUPS) functions.
class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> {
public:
- virtual ~PrintSystem() {}
-
- // Enumerates the list of installed local and network printers.
- virtual void EnumeratePrinters(PrinterList* printer_list) = 0;
-
- // Gets the capabilities and defaults for a specific printer.
- virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
- PrinterCapsAndDefaults* printer_info) = 0;
-
- // Returns true if ticket is valid.
- virtual bool ValidatePrintTicket(const std::string& printer_name,
- const std::string& print_ticket_data) = 0;
-
- // Send job to the printer.
- virtual bool SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- PlatformJobId* job_id_ret) = 0;
-
- // Get details for already spooled job.
- virtual bool GetJobDetails(const std::string& printer_name,
- PlatformJobId job_id,
- PrintJobDetails *job_details) = 0;
-
- // Returns true if printer_name points to a valid printer.
- virtual bool IsValidPrinter(const std::string& printer_name) = 0;
-
class PrintServerWatcher
: public base::RefCountedThreadSafe<PrintServerWatcher> {
public:
@@ -141,11 +112,56 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> {
virtual bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) = 0;
};
+ class JobSpooler : public base::RefCountedThreadSafe<JobSpooler> {
+ public:
+ // Callback interface for JobSpooler notifications.
+ class Delegate {
+ public:
+ virtual ~Delegate() { }
+ virtual void OnJobSpoolSucceeded(const PlatformJobId& job_id) = 0;
+ virtual void OnJobSpoolFailed() = 0;
+ };
+
+ virtual ~JobSpooler() {}
+ // Spool job to the printer asynchronously. Caller will be notified via
+ // |delegate|. Note that only one print job can be in progress at any given
+ // time. Subsequent calls to Spool (before the Delegate::OnJobSpoolSucceeded
+ // or Delegate::OnJobSpoolFailed methods are called) can fail.
+ virtual bool Spool(const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title,
+ JobSpooler::Delegate* delegate) = 0;
+ };
+
+ virtual ~PrintSystem() {}
+
+ // Enumerates the list of installed local and network printers.
+ virtual void EnumeratePrinters(PrinterList* printer_list) = 0;
+
+ // Gets the capabilities and defaults for a specific printer.
+ virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
+ PrinterCapsAndDefaults* printer_info) = 0;
+
+ // Returns true if ticket is valid.
+ virtual bool ValidatePrintTicket(const std::string& printer_name,
+ const std::string& print_ticket_data) = 0;
+
+ // Get details for already spooled job.
+ virtual bool GetJobDetails(const std::string& printer_name,
+ PlatformJobId job_id,
+ PrintJobDetails *job_details) = 0;
+
+ // Returns true if printer_name points to a valid printer.
+ virtual bool IsValidPrinter(const std::string& printer_name) = 0;
+
// Factory methods to create corresponding watcher. Callee is responsible
// for deleting objects. Return NULL if failed.
virtual PrintServerWatcher* CreatePrintServerWatcher() = 0;
virtual PrinterWatcher* CreatePrinterWatcher(
const std::string& printer_name) = 0;
+ virtual JobSpooler* CreateJobSpooler() = 0;
// Generate unique for proxy.
static std::string GenerateProxyId();
@@ -164,6 +180,7 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> {
// the workaround was not needed for my machine).
typedef PrintSystem::PrintServerWatcher::Delegate PrintServerWatcherDelegate;
typedef PrintSystem::PrinterWatcher::Delegate PrinterWatcherDelegate;
+typedef PrintSystem::JobSpooler::Delegate JobSpoolerDelegate;
} // namespace cloud_print
diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc
index b624f40..dc1314c 100644
--- a/chrome/service/cloud_print/print_system_cups.cc
+++ b/chrome/service/cloud_print/print_system_cups.cc
@@ -124,6 +124,7 @@ class PrintSystemCUPS : public PrintSystem {
public:
explicit PrintSystemCUPS(const GURL& print_server_url);
+ // PrintSystem implementation.
virtual void EnumeratePrinters(PrinterList* printer_list);
virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
@@ -132,19 +133,13 @@ class PrintSystemCUPS : public PrintSystem {
virtual bool ValidatePrintTicket(const std::string& printer_name,
const std::string& print_ticket_data);
- virtual bool SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- PlatformJobId* job_id_ret);
-
virtual bool GetJobDetails(const std::string& printer_name,
PlatformJobId job_id,
PrintJobDetails *job_details);
virtual bool IsValidPrinter(const std::string& printer_name);
+
// TODO(gene): Add implementation for CUPS print server watcher.
class PrintServerWatcherCUPS
: public PrintSystem::PrintServerWatcher {
@@ -212,11 +207,53 @@ class PrintSystemCUPS : public PrintSystem {
DISALLOW_COPY_AND_ASSIGN(PrinterWatcherCUPS);
};
+ class JobSpoolerCUPS : public PrintSystem::JobSpooler {
+ public:
+ explicit JobSpoolerCUPS(PrintSystemCUPS* print_system)
+ : print_system_(print_system) {
+ DCHECK(print_system_.get());
+ }
+ // PrintSystem::JobSpooler implementation.
+ virtual bool Spool(const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title,
+ JobSpooler::Delegate* delegate) {
+ DCHECK(delegate);
+ int job_id = print_system_->SpoolPrintJob(
+ print_ticket, print_data_file_path, print_data_mime_type,
+ printer_name, job_title);
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableFunction(
+ &JobSpoolerCUPS::NotifyDelegate,
+ delegate,
+ job_id));
+ return true;
+ }
+
+ static void NotifyDelegate(JobSpooler::Delegate* delegate, int job_id) {
+ if (job_id)
+ delegate->OnJobSpoolSucceeded(job_id);
+ else
+ delegate->OnJobSpoolFailed();
+ }
+ private:
+ scoped_refptr<PrintSystemCUPS> print_system_;
+ DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS);
+ };
+
virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
const std::string& printer_name);
+ virtual PrintSystem::JobSpooler* CreateJobSpooler();
// Helper functions.
+ PlatformJobId SpoolPrintJob(const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title);
bool GetPrinterInfo(const std::string& printer_name, PrinterBasicInfo* info);
bool ParsePrintTicket(const std::string& print_ticket,
std::map<std::string, std::string>* options);
@@ -228,10 +265,10 @@ class PrintSystemCUPS : public PrintSystem {
// in the <functions>2(), it does not work in CUPS prior to 1.4.
int GetDests(cups_dest_t** dests);
FilePath GetPPD(const char* name);
- int PrintFile(const char* name, const char* filename, const char* title,
- int num_options, cups_option_t* options);
int GetJobs(cups_job_t** jobs, const char* name,
int myjobs, int whichjobs);
+ int PrintFile(const char* name, const char* filename, const char* title,
+ int num_options, cups_option_t* options);
GURL print_server_url_;
};
@@ -336,47 +373,6 @@ bool PrintSystemCUPS::ParsePrintTicket(const std::string& print_ticket,
return true;
}
-bool PrintSystemCUPS::SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- PlatformJobId* job_id_ret) {
- DCHECK(job_id_ret);
-
- LOG(INFO) << "CP_CUPS: Spooling print job for: " << printer_name;
-
- // We need to store options as char* string for the duration of the
- // cupsPrintFile2 call. We'll use map here to store options, since
- // Dictionary value from JSON parser returns wchat_t.
- std::map<std::string, std::string> options;
- bool res = ParsePrintTicket(print_ticket, &options);
- DCHECK(res); // If print ticket is invalid we still print using defaults.
-
- std::vector<cups_option_t> cups_options;
- std::map<std::string, std::string>::iterator it;
- for (it = options.begin(); it != options.end(); ++it) {
- cups_option_t opt;
- opt.name = const_cast<char*>(it->first.c_str());
- opt.value = const_cast<char*>(it->second.c_str());
- cups_options.push_back(opt);
- }
-
- int job_id = PrintFile(printer_name.c_str(),
- print_data_file_path.value().c_str(),
- job_title.c_str(),
- cups_options.size(),
- &(cups_options[0]));
-
- LOG(INFO) << "CP_CUPS: Job spooled, id: " << job_id;
-
- if (job_id == 0)
- return false;
-
- *job_id_ret = job_id;
- return true;
-}
-
bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name,
PlatformJobId job_id,
PrintJobDetails *job_details) {
@@ -462,6 +458,10 @@ PrintSystem::PrinterWatcher* PrintSystemCUPS::CreatePrinterWatcher(
return new PrinterWatcherCUPS(this, printer_name);
}
+PrintSystem::JobSpooler* PrintSystemCUPS::CreateJobSpooler() {
+ return new JobSpoolerCUPS(this);
+}
+
std::string PrintSystem::GenerateProxyId() {
// TODO(gene): This code should generate a unique id for proxy. ID should be
// unique for this user. Rand may return the same number. We'll need to change
@@ -534,4 +534,39 @@ int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const char* name,
}
}
+PlatformJobId PrintSystemCUPS::SpoolPrintJob(
+ const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title) {
+ LOG(INFO) << "CP_CUPS: Spooling print job for: " << printer_name;
+
+ // We need to store options as char* string for the duration of the
+ // cupsPrintFile2 call. We'll use map here to store options, since
+ // Dictionary value from JSON parser returns wchat_t.
+ std::map<std::string, std::string> options;
+ bool res = ParsePrintTicket(print_ticket, &options);
+ DCHECK(res); // If print ticket is invalid we still print using defaults.
+
+ std::vector<cups_option_t> cups_options;
+ std::map<std::string, std::string>::iterator it;
+ for (it = options.begin(); it != options.end(); ++it) {
+ cups_option_t opt;
+ opt.name = const_cast<char*>(it->first.c_str());
+ opt.value = const_cast<char*>(it->second.c_str());
+ cups_options.push_back(opt);
+ }
+
+ int job_id = PrintFile(printer_name.c_str(),
+ print_data_file_path.value().c_str(),
+ job_title.c_str(),
+ cups_options.size(),
+ &(cups_options[0]));
+
+ LOG(INFO) << "CP_CUPS: Job spooled, id: " << job_id;
+
+ return job_id;
+}
+
} // namespace cloud_print
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc
index d1e00c8..da16fa2 100644
--- a/chrome/service/cloud_print/print_system_win.cc
+++ b/chrome/service/cloud_print/print_system_win.cc
@@ -12,12 +12,18 @@
#include <winspool.h>
#include "base/lock.h"
+#include "base/file_util.h"
#include "base/object_watcher.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_handle_win.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
+#include "chrome/service/service_process.h"
+#include "chrome/service/service_utility_process_host.h"
+#include "gfx/rect.h"
+#include "printing/native_metafile.h"
+#include "printing/page_range.h"
#pragma comment(lib, "prntvpt.lib")
#pragma comment(lib, "rpcrt4.lib")
@@ -117,13 +123,6 @@ HRESULT PrintTicketToDevMode(const std::string& printer_name,
return hr;
}
-HRESULT PrintPdf2DC(HDC dc, const FilePath& pdf_filename) {
- HRESULT hr = E_NOTIMPL;
- // TODO(sanjeevr): Implement this.
- NOTIMPLEMENTED();
- return hr;
-}
-
} // namespace
namespace cloud_print {
@@ -255,13 +254,6 @@ class PrintSystemWin : public PrintSystem {
virtual bool ValidatePrintTicket(const std::string& printer_name,
const std::string& print_ticket_data);
- virtual bool SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- PlatformJobId* job_id_ret);
-
virtual bool GetJobDetails(const std::string& printer_name,
PlatformJobId job_id,
PrintJobDetails *job_details);
@@ -291,13 +283,10 @@ class PrintSystemWin : public PrintSystem {
delegate_->OnPrinterAdded();
}
virtual void OnPrinterDeleted() {
- NOTREACHED();
}
virtual void OnPrinterChanged() {
- NOTREACHED();
}
virtual void OnJobChanged() {
- NOTREACHED();
}
private:
@@ -349,9 +338,180 @@ class PrintSystemWin : public PrintSystem {
DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
};
+ class JobSpoolerWin : public PrintSystem::JobSpooler {
+ public:
+ JobSpoolerWin() : core_(new Core) {}
+ // PrintSystem::JobSpooler implementation.
+ virtual bool Spool(const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title,
+ JobSpooler::Delegate* delegate) {
+ return core_->Spool(print_ticket, print_data_file_path,
+ print_data_mime_type, printer_name, job_title,
+ delegate);
+ }
+ private:
+ // We use a Core class because we want a separate RefCountedThreadSafe
+ // implementation for ServiceUtilityProcessHost::Client.
+ class Core : public ServiceUtilityProcessHost::Client {
+ public:
+ Core()
+ : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) {
+ }
+ ~Core() {
+ }
+ bool Spool(const std::string& print_ticket,
+ const FilePath& print_data_file_path,
+ const std::string& print_data_mime_type,
+ const std::string& printer_name,
+ const std::string& job_title,
+ JobSpooler::Delegate* delegate) {
+ if (delegate_) {
+ // We are already in the process of printing.
+ NOTREACHED();
+ return false;
+ }
+ last_page_printed_ = -1;
+ // We only support PDFs for now.
+ if (print_data_mime_type != "application/pdf") {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!InitXPSModule()) {
+ // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
+ return false;
+ }
+ DevMode pt_dev_mode;
+ HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket,
+ &pt_dev_mode);
+ if (FAILED(hr)) {
+ NOTREACHED();
+ return false;
+ }
+ HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(),
+ NULL, pt_dev_mode.dm_);
+ if (!dc) {
+ NOTREACHED();
+ return false;
+ }
+ hr = E_FAIL;
+ DOCINFO di = {0};
+ di.cbSize = sizeof(DOCINFO);
+ std::wstring doc_name = UTF8ToWide(job_title);
+ di.lpszDocName = doc_name.c_str();
+ job_id_ = StartDoc(dc, &di);
+ if (SP_ERROR == job_id_)
+ return false;
+
+ printer_dc_.Set(dc);
+
+ int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
+ saved_dc_ = SaveDC(printer_dc_.Get());
+ SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
+ XFORM xform = {0};
+ xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) /
+ static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX));
+ ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY);
+ print_data_file_path_ = print_data_file_path;
+ delegate_ = delegate;
+ RenderNextPDFPages();
+ return true;
+ }
+
+ // ServiceUtilityProcessHost::Client implementation.
+ virtual void OnRenderPDFPagesToMetafileSucceeded(
+ const printing::NativeMetafile& metafile,
+ int highest_rendered_page_number) {
+ metafile.SafePlayback(printer_dc_.Get());
+ bool done_printing = (highest_rendered_page_number !=
+ last_page_printed_ + kPageCountPerBatch);
+ last_page_printed_ = highest_rendered_page_number;
+ if (done_printing)
+ PrintJobDone();
+ else
+ RenderNextPDFPages();
+ }
+ virtual void OnRenderPDFPagesToMetafileFailed() {
+ PrintJobDone();
+ }
+ virtual void OnChildDied() {
+ PrintJobDone();
+ }
+ private:
+ void PrintJobDone() {
+ // If there is no delegate, then there is nothing pending to process.
+ if (!delegate_)
+ return;
+ RestoreDC(printer_dc_.Get(), saved_dc_);
+ EndDoc(printer_dc_.Get());
+ if (-1 == last_page_printed_) {
+ delegate_->OnJobSpoolFailed();
+ } else {
+ delegate_->OnJobSpoolSucceeded(job_id_);
+ }
+ delegate_ = NULL;
+ }
+ void RenderNextPDFPages() {
+ printing::PageRange range;
+ // Render 10 pages at a time.
+ range.from = last_page_printed_ + 1;
+ range.to = last_page_printed_ + kPageCountPerBatch;
+ std::vector<printing::PageRange> page_ranges;
+ page_ranges.push_back(range);
+
+ int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
+ int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
+ int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
+ gfx::Rect render_area(0, 0, dc_width, dc_height);
+ g_service_process->io_thread()->message_loop_proxy()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &JobSpoolerWin::Core::RenderPDFPagesInSandbox,
+ print_data_file_path_,
+ render_area,
+ printer_dpi,
+ page_ranges,
+ base::MessageLoopProxy::CreateForCurrentThread()));
+ }
+ // Called on the service process IO thread.
+ void RenderPDFPagesInSandbox(
+ const FilePath& pdf_path, const gfx::Rect& render_area,
+ int render_dpi, const std::vector<printing::PageRange>& page_ranges,
+ const scoped_refptr<base::MessageLoopProxy>&
+ client_message_loop_proxy) {
+ DCHECK(g_service_process->io_thread()->message_loop_proxy()->
+ BelongsToCurrentThread());
+ scoped_ptr<ServiceUtilityProcessHost> utility_host(
+ new ServiceUtilityProcessHost(this, client_message_loop_proxy));
+ if (utility_host->StartRenderPDFPagesToMetafile(pdf_path,
+ render_area,
+ render_dpi,
+ page_ranges)) {
+ // The object will self-destruct when the child process dies.
+ utility_host.release();
+ }
+ }
+ static const int kPageCountPerBatch = 10;
+ int last_page_printed_;
+ PlatformJobId job_id_;
+ PrintSystem::JobSpooler::Delegate* delegate_;
+ int saved_dc_;
+ ScopedHDC printer_dc_;
+ FilePath print_data_file_path_;
+ DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core);
+ };
+ scoped_refptr<Core> core_;
+ DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
+ };
+
virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
const std::string& printer_name);
+ virtual PrintSystem::JobSpooler* CreateJobSpooler();
};
void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) {
@@ -486,48 +646,6 @@ bool PrintSystemWin::ValidatePrintTicket(
return ret;
}
-bool PrintSystemWin::SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- PlatformJobId* job_id_ret) {
- if (!InitXPSModule()) {
- // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
- return false;
- }
- DevMode pt_dev_mode;
- HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, &pt_dev_mode);
- if (FAILED(hr)) {
- NOTREACHED();
- return false;
- }
- ScopedHDC dc(CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), NULL,
- pt_dev_mode.dm_));
- if (!dc.Get()) {
- NOTREACHED();
- return false;
- }
- hr = E_FAIL;
- DOCINFO di = {0};
- di.cbSize = sizeof(DOCINFO);
- std::wstring doc_name = UTF8ToWide(job_title);
- di.lpszDocName = doc_name.c_str();
- int job_id = StartDoc(dc.Get(), &di);
- if (SP_ERROR != job_id) {
- if (print_data_mime_type == "application/pdf") {
- hr = PrintPdf2DC(dc.Get(), print_data_file_path);
- } else {
- NOTREACHED();
- }
- EndDoc(dc.Get());
- if (SUCCEEDED(hr) && job_id_ret) {
- *job_id_ret = job_id;
- }
- }
- return SUCCEEDED(hr);
-}
-
bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
PlatformJobId job_id,
PrintJobDetails *job_details) {
@@ -597,6 +715,11 @@ PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
return new PrinterWatcherWin(printer_name);
}
+PrintSystem::JobSpooler*
+PrintSystemWin::CreateJobSpooler() {
+ return new JobSpoolerWin();
+}
+
std::string PrintSystem::GenerateProxyId() {
GUID proxy_id = {0};
HRESULT hr = UuidCreate(&proxy_id);
diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc
index 040c449..d5cef62 100644
--- a/chrome/service/cloud_print/printer_job_handler.cc
+++ b/chrome/service/cloud_print/printer_job_handler.cc
@@ -36,6 +36,8 @@ PrinterJobHandler::PrinterJobHandler(
next_failure_handler_(NULL),
server_error_count_(0),
print_thread_("Chrome_CloudPrintJobPrintThread"),
+ job_handler_message_loop_proxy_(
+ base::MessageLoopProxy::CreateForCurrentThread()),
shutting_down_(false),
server_job_available_(false),
printer_update_pending_(true),
@@ -431,11 +433,9 @@ void PrinterJobHandler::StartPrinting() {
JobFailed(PRINT_FAILED);
} else {
print_thread_.message_loop()->PostTask(
- FROM_HERE, NewRunnableFunction(&PrinterJobHandler::DoPrint,
- job_details_,
- printer_info_.printer_name,
- print_system_, this,
- MessageLoop::current()));
+ FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::DoPrint,
+ job_details_,
+ printer_info_.printer_name));
}
}
}
@@ -590,29 +590,41 @@ void PrinterJobHandler::FailedFetchingJobData() {
}
}
+// The following methods are called on |print_thread_|. It is not safe to
+// access any members other than |job_handler_message_loop_proxy_|,
+// |job_spooler_| and |print_system_|.
void PrinterJobHandler::DoPrint(const JobDetails& job_details,
- const std::string& printer_name,
- scoped_refptr<cloud_print::PrintSystem> print_system,
- PrinterJobHandler* job_handler,
- MessageLoop* job_message_loop) {
- DCHECK(job_handler);
- DCHECK(job_message_loop);
- LOG(INFO) << "CP_PROXY: Printing: " << printer_name;
- cloud_print::PlatformJobId job_id = -1;
- if (print_system->SpoolPrintJob(job_details.print_ticket_,
- job_details.print_data_file_path_,
- job_details.print_data_mime_type_,
- printer_name,
- job_details.job_title_, &job_id)) {
- job_message_loop->PostTask(FROM_HERE,
- NewRunnableMethod(job_handler,
- &PrinterJobHandler::JobSpooled,
- job_id));
+ const std::string& printer_name) {
+ job_spooler_ = print_system_->CreateJobSpooler();
+ DCHECK(job_spooler_);
+ if (job_spooler_) {
+ job_spooler_->Spool(job_details.print_ticket_,
+ job_details.print_data_file_path_,
+ job_details.print_data_mime_type_,
+ printer_name,
+ job_details.job_title_,
+ this);
} else {
- job_message_loop->PostTask(FROM_HERE,
- NewRunnableMethod(job_handler,
- &PrinterJobHandler::JobFailed,
- PRINT_FAILED));
+ OnJobSpoolFailed();
}
}
+void PrinterJobHandler::OnJobSpoolSucceeded(
+ const cloud_print::PlatformJobId& job_id) {
+ DCHECK(MessageLoop::current() == print_thread_.message_loop());
+ job_spooler_ = NULL;
+ job_handler_message_loop_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &PrinterJobHandler::JobSpooled,
+ job_id));
+}
+
+void PrinterJobHandler::OnJobSpoolFailed() {
+ DCHECK(MessageLoop::current() == print_thread_.message_loop());
+ job_spooler_ = NULL;
+ job_handler_message_loop_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &PrinterJobHandler::JobFailed,
+ PRINT_FAILED));
+}
+
diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h
index c24e7b6..81f802b 100644
--- a/chrome/service/cloud_print/printer_job_handler.h
+++ b/chrome/service/cloud_print/printer_job_handler.h
@@ -10,6 +10,7 @@
#include "base/file_path.h"
#include "base/ref_counted.h"
+#include "base/message_loop_proxy.h"
#include "base/thread.h"
#include "chrome/service/cloud_print/job_status_updater.h"
#include "chrome/service/cloud_print/print_system.h"
@@ -61,7 +62,8 @@ typedef URLFetcher::Delegate URLFetcherDelegate;
class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
public URLFetcherDelegate,
public JobStatusUpdaterDelegate,
- public cloud_print::PrinterWatcherDelegate {
+ public cloud_print::PrinterWatcherDelegate,
+ public cloud_print::JobSpoolerDelegate {
enum PrintJobError {
SUCCESS,
JOB_DOWNLOAD_FAILED,
@@ -121,6 +123,11 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
virtual void OnPrinterChanged();
virtual void OnJobChanged();
+ // cloud_print::JobSpoolerDelegate implementation.
+ // Called on print_thread_.
+ virtual void OnJobSpoolSucceeded(const cloud_print::PlatformJobId& job_id);
+ virtual void OnJobSpoolFailed();
+
// End Delegate implementations
private:
@@ -207,11 +214,9 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
bool HavePendingTasks();
void FailedFetchingJobData();
- static void DoPrint(const JobDetails& job_details,
- const std::string& printer_name,
- scoped_refptr<cloud_print::PrintSystem> print_system,
- PrinterJobHandler* job_handler,
- MessageLoop* job_message_loop);
+ // Called on print_thread_.
+ void DoPrint(const JobDetails& job_details,
+ const std::string& printer_name);
scoped_ptr<URLFetcher> request_;
scoped_refptr<cloud_print::PrintSystem> print_system_;
@@ -232,6 +237,13 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
int server_error_count_;
// The thread on which the actual print operation happens
base::Thread print_thread_;
+ // The Job spooler object. This is only non-NULL during a print operation.
+ // It lives and dies on |print_thread_|
+ scoped_refptr<cloud_print::PrintSystem::JobSpooler> job_spooler_;
+ // The message loop proxy representing the thread on which this object
+ // was created. Used by the print thread.
+ scoped_refptr<base::MessageLoopProxy> job_handler_message_loop_proxy_;
+
// There may be pending tasks in the message queue when Shutdown is called.
// We set this flag so as to do nothing in those tasks.
bool shutting_down_;