| Index: chrome/service/cloud_print/print_system_win.cc
|
| ===================================================================
|
| --- chrome/service/cloud_print/print_system_win.cc (revision 53070)
|
| +++ chrome/service/cloud_print/print_system_win.cc (working copy)
|
| @@ -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 @@
|
| 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 @@
|
| 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 @@
|
| delegate_->OnPrinterAdded();
|
| }
|
| virtual void OnPrinterDeleted() {
|
| - NOTREACHED();
|
| }
|
| virtual void OnPrinterChanged() {
|
| - NOTREACHED();
|
| }
|
| virtual void OnJobChanged() {
|
| - NOTREACHED();
|
| }
|
|
|
| private:
|
| @@ -349,9 +338,180 @@
|
| 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 @@
|
| 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 @@
|
| 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);
|
|
|