Index: chrome/service/cloud_print/print_system_win.cc |
=================================================================== |
--- chrome/service/cloud_print/print_system_win.cc (revision 74874) |
+++ chrome/service/cloud_print/print_system_win.cc (working copy) |
@@ -6,8 +6,14 @@ |
#include <objidl.h> |
#include <winspool.h> |
+#if defined(_WIN32_WINNT) |
+#undef _WIN32_WINNT |
+#endif // defined(_WIN32_WINNT) |
+#define _WIN32_WINNT _WIN32_WINNT_WIN7 |
+#include <xpsprint.h> |
#include "base/file_path.h" |
+#include "base/file_util.h" |
#include "base/scoped_ptr.h" |
#include "base/utf_string_conversions.h" |
#include "base/win/object_watcher.h" |
@@ -366,10 +372,15 @@ |
private: |
// We use a Core class because we want a separate RefCountedThreadSafe |
// implementation for ServiceUtilityProcessHost::Client. |
- class Core : public ServiceUtilityProcessHost::Client { |
+ class Core : public ServiceUtilityProcessHost::Client, |
+ public base::win::ObjectWatcher::Delegate { |
public: |
Core() |
- : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) { |
+ : last_page_printed_(-1), |
+ job_id_(-1), |
+ delegate_(NULL), |
+ saved_dc_(0), |
+ should_couninit_(false) { |
} |
~Core() { |
} |
@@ -385,47 +396,54 @@ |
return false; |
} |
last_page_printed_ = -1; |
- // We only support PDFs for now. |
- if (print_data_mime_type != "application/pdf") { |
- NOTREACHED(); |
- return false; |
- } |
+ // We only support PDF and XPS documents for now. |
+ if (print_data_mime_type == "application/pdf") { |
+ DevMode pt_dev_mode; |
+ HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket, |
+ &pt_dev_mode); |
+ if (FAILED(hr)) { |
+ NOTREACHED(); |
+ 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 (job_id_ <= 0) |
+ return false; |
- HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(), |
- NULL, pt_dev_mode.dm_); |
- if (!dc) { |
+ 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(); |
+ } else if (print_data_mime_type == "application/vnd.ms-xpsdocument") { |
+ bool ret = PrintXPSDocument(printer_name, |
+ job_title, |
+ print_data_file_path, |
+ print_ticket); |
+ if (ret) |
+ delegate_ = delegate; |
+ return ret; |
+ } else { |
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 (job_id_ <= 0) |
- 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; |
} |
@@ -442,6 +460,33 @@ |
else |
RenderNextPDFPages(); |
} |
+ |
+ // base::win::ObjectWatcher::Delegate inplementation. |
+ virtual void OnObjectSignaled(HANDLE object) { |
+ DCHECK(xps_print_job_); |
+ if (!delegate_) |
+ return; |
+ XPS_JOB_STATUS job_status = {0}; |
+ xps_print_job_->GetJobStatus(&job_status); |
+ bool done = false; |
+ if ((job_status.completion == XPS_JOB_CANCELLED) || |
+ (job_status.completion == XPS_JOB_FAILED)) { |
+ delegate_->OnJobSpoolFailed(); |
+ done = true; |
+ } else if (job_status.jobId) { |
+ delegate_->OnJobSpoolSucceeded(job_status.jobId); |
+ done = true; |
+ } else { |
+ ResetEvent(job_progress_event_.Get()); |
+ job_progress_watcher_.StopWatching(); |
+ job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); |
+ } |
+ if (done && should_couninit_) { |
+ CoUninitialize(); |
+ should_couninit_ = false; |
+ } |
+ } |
+ |
virtual void OnRenderPDFPagesToMetafileFailed() { |
PrintJobDone(); |
} |
@@ -503,6 +548,67 @@ |
utility_host.release(); |
} |
} |
+ bool PrintXPSDocument(const std::string& printer_name, |
+ const std::string& job_title, |
+ const FilePath& print_data_file_path, |
+ const std::string& print_ticket) { |
+ if (!printing::XPSPrintModule::Init()) |
+ return false; |
+ job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL)); |
+ if (!job_progress_event_.Get()) |
+ return false; |
+ should_couninit_ = SUCCEEDED(CoInitializeEx(NULL, |
+ COINIT_MULTITHREADED)); |
+ ScopedComPtr<IXpsPrintJobStream> doc_stream; |
+ ScopedComPtr<IXpsPrintJobStream> print_ticket_stream; |
+ bool ret = false; |
+ // Use nested SUCCEEDED checks because we want a common return point. |
+ if (SUCCEEDED(printing::XPSPrintModule::StartXpsPrintJob( |
+ UTF8ToWide(printer_name).c_str(), |
+ UTF8ToWide(job_title).c_str(), |
+ NULL, |
+ job_progress_event_.Get(), |
+ NULL, |
+ NULL, |
+ NULL, |
+ xps_print_job_.Receive(), |
+ doc_stream.Receive(), |
+ print_ticket_stream.Receive()))) { |
+ ULONG bytes_written = 0; |
+ if (SUCCEEDED(print_ticket_stream->Write(print_ticket.c_str(), |
+ print_ticket.length(), |
+ &bytes_written))) { |
+ DCHECK(bytes_written == print_ticket.length()); |
+ if (SUCCEEDED(print_ticket_stream->Close())) { |
+ std::string document_data; |
+ file_util::ReadFileToString(print_data_file_path, &document_data); |
+ bytes_written = 0; |
+ if (SUCCEEDED(doc_stream->Write(document_data.c_str(), |
+ document_data.length(), |
+ &bytes_written))) { |
+ DCHECK(bytes_written == document_data.length()); |
+ if (SUCCEEDED(doc_stream->Close())) { |
+ job_progress_watcher_.StartWatching(job_progress_event_.Get(), |
+ this); |
+ ret = true; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ if (!ret) { |
+ if (xps_print_job_) { |
+ xps_print_job_->Cancel(); |
+ xps_print_job_.Release(); |
+ } |
+ if (should_couninit_) { |
+ CoUninitialize(); |
+ should_couninit_ = false; |
+ } |
+ } |
+ return ret; |
+ } |
+ |
// Some Cairo-generated PDFs from Chrome OS result in huge metafiles. |
// So the PageCountPerBatch is set to 1 for now. |
// TODO(sanjeevr): Figure out a smarter way to determine the pages per |
@@ -515,6 +621,10 @@ |
int saved_dc_; |
base::win::ScopedHDC printer_dc_; |
FilePath print_data_file_path_; |
+ base::win::ScopedHandle job_progress_event_; |
+ base::win::ObjectWatcher job_progress_watcher_; |
+ ScopedComPtr<IXpsPrintJob> xps_print_job_; |
+ bool should_couninit_; |
DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); |
}; |
scoped_refptr<Core> core_; |
@@ -588,7 +698,9 @@ |
virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( |
const std::string& printer_name); |
virtual PrintSystem::JobSpooler* CreateJobSpooler(); |
+ virtual std::string GetSupportedMimeTypes(); |
+ |
private: |
scoped_refptr<printing::PrintBackend> print_backend_; |
}; |
@@ -728,6 +840,13 @@ |
return new JobSpoolerWin(); |
} |
+std::string PrintSystemWin::GetSupportedMimeTypes() { |
+ if (printing::XPSPrintModule::Init()) |
+ return "application/vnd.ms-xpsdocument,application/pdf"; |
+ return "application/pdf"; |
+} |
+ |
+ |
std::string PrintSystem::GenerateProxyId() { |
GUID proxy_id = {0}; |
HRESULT hr = UuidCreate(&proxy_id); |