1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/service/cloud_print/print_system.h"
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/json/json_writer.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/win/object_watcher.h"
13 #include "base/win/scoped_bstr.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_hdc.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
18 #include "chrome/common/cloud_print/cloud_print_constants.h"
19 #include "chrome/common/crash_keys.h"
20 #include "chrome/service/cloud_print/cdd_conversion_win.h"
21 #include "chrome/service/service_process.h"
22 #include "chrome/service/service_utility_process_host.h"
23 #include "printing/backend/win_helper.h"
24 #include "printing/emf_win.h"
25 #include "printing/page_range.h"
26 #include "printing/printing_utils.h"
28 namespace cloud_print
{
32 class PrintSystemWatcherWin
: public base::win::ObjectWatcher::Delegate
{
34 PrintSystemWatcherWin()
38 ~PrintSystemWatcherWin() {
44 virtual ~Delegate() {}
45 virtual void OnPrinterAdded() = 0;
46 virtual void OnPrinterDeleted() = 0;
47 virtual void OnPrinterChanged() = 0;
48 virtual void OnJobChanged() = 0;
51 bool Start(const std::string
& printer_name
, Delegate
* delegate
) {
52 scoped_refptr
<printing::PrintBackend
> print_backend(
53 printing::PrintBackend::CreateInstance(NULL
));
54 printer_info_
= print_backend
->GetPrinterDriverInfo(printer_name
);
55 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
58 // An empty printer name means watch the current server, we need to pass
59 // NULL to OpenPrinter.
60 LPTSTR printer_name_to_use
= NULL
;
61 std::wstring printer_name_wide
;
62 if (!printer_name
.empty()) {
63 printer_name_wide
= base::UTF8ToWide(printer_name
);
64 printer_name_to_use
= const_cast<LPTSTR
>(printer_name_wide
.c_str());
67 if (printer_
.OpenPrinter(printer_name_to_use
)) {
68 printer_change_
.Set(FindFirstPrinterChangeNotification(
69 printer_
, PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
, 0, NULL
));
70 if (printer_change_
.IsValid()) {
71 ret
= watcher_
.StartWatching(printer_change_
, this);
81 watcher_
.StopWatching();
83 printer_change_
.Close();
87 // base::ObjectWatcher::Delegate method
88 virtual void OnObjectSignaled(HANDLE object
) {
89 crash_keys::ScopedPrinterInfo
crash_key(printer_info_
);
91 FindNextPrinterChangeNotification(object
, &change
, NULL
, NULL
);
93 if (change
!= ((PRINTER_CHANGE_PRINTER
|PRINTER_CHANGE_JOB
) &
94 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
))) {
95 // For printer connections, we get spurious change notifications with
96 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
98 if (change
& PRINTER_CHANGE_ADD_PRINTER
) {
99 delegate_
->OnPrinterAdded();
100 } else if (change
& PRINTER_CHANGE_DELETE_PRINTER
) {
101 delegate_
->OnPrinterDeleted();
102 } else if (change
& PRINTER_CHANGE_SET_PRINTER
) {
103 delegate_
->OnPrinterChanged();
105 if (change
& PRINTER_CHANGE_JOB
) {
106 delegate_
->OnJobChanged();
109 watcher_
.StartWatching(printer_change_
, this);
112 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo
* printer_info
) {
113 DCHECK(printer_info
);
114 return InitBasicPrinterInfo(printer_
, printer_info
);
118 base::win::ObjectWatcher watcher_
;
119 printing::ScopedPrinterHandle printer_
; // The printer being watched
120 // Returned by FindFirstPrinterChangeNotifier.
121 printing::ScopedPrinterChangeHandle printer_change_
;
122 Delegate
* delegate_
; // Delegate to notify
123 bool did_signal_
; // DoneWaiting was called
124 std::string printer_info_
; // For crash reporting.
127 class PrintServerWatcherWin
128 : public PrintSystem::PrintServerWatcher
,
129 public PrintSystemWatcherWin::Delegate
{
131 PrintServerWatcherWin() : delegate_(NULL
) {}
133 // PrintSystem::PrintServerWatcher implementation.
134 virtual bool StartWatching(
135 PrintSystem::PrintServerWatcher::Delegate
* delegate
) OVERRIDE
{
136 delegate_
= delegate
;
137 return watcher_
.Start(std::string(), this);
140 virtual bool StopWatching() OVERRIDE
{
141 bool ret
= watcher_
.Stop();
146 // PrintSystemWatcherWin::Delegate implementation.
147 virtual void OnPrinterAdded() OVERRIDE
{
148 delegate_
->OnPrinterAdded();
150 virtual void OnPrinterDeleted() OVERRIDE
{}
151 virtual void OnPrinterChanged() OVERRIDE
{}
152 virtual void OnJobChanged() OVERRIDE
{}
155 virtual ~PrintServerWatcherWin() {}
158 PrintSystem::PrintServerWatcher::Delegate
* delegate_
;
159 PrintSystemWatcherWin watcher_
;
161 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin
);
164 class PrinterWatcherWin
165 : public PrintSystem::PrinterWatcher
,
166 public PrintSystemWatcherWin::Delegate
{
168 explicit PrinterWatcherWin(const std::string
& printer_name
)
169 : printer_name_(printer_name
),
173 // PrintSystem::PrinterWatcher implementation.
174 virtual bool StartWatching(
175 PrintSystem::PrinterWatcher::Delegate
* delegate
) OVERRIDE
{
176 delegate_
= delegate
;
177 return watcher_
.Start(printer_name_
, this);
180 virtual bool StopWatching() OVERRIDE
{
181 bool ret
= watcher_
.Stop();
186 virtual bool GetCurrentPrinterInfo(
187 printing::PrinterBasicInfo
* printer_info
) OVERRIDE
{
188 return watcher_
.GetCurrentPrinterInfo(printer_info
);
191 // PrintSystemWatcherWin::Delegate implementation.
192 virtual void OnPrinterAdded() OVERRIDE
{
195 virtual void OnPrinterDeleted() OVERRIDE
{
196 delegate_
->OnPrinterDeleted();
198 virtual void OnPrinterChanged() OVERRIDE
{
199 delegate_
->OnPrinterChanged();
201 virtual void OnJobChanged() OVERRIDE
{
202 delegate_
->OnJobChanged();
206 virtual ~PrinterWatcherWin() {}
209 std::string printer_name_
;
210 PrintSystem::PrinterWatcher::Delegate
* delegate_
;
211 PrintSystemWatcherWin watcher_
;
213 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin
);
216 class JobSpoolerWin
: public PrintSystem::JobSpooler
{
218 JobSpoolerWin() : core_(new Core
) {}
220 // PrintSystem::JobSpooler implementation.
221 virtual bool Spool(const std::string
& print_ticket
,
222 const std::string
& print_ticket_mime_type
,
223 const base::FilePath
& print_data_file_path
,
224 const std::string
& print_data_mime_type
,
225 const std::string
& printer_name
,
226 const std::string
& job_title
,
227 const std::vector
<std::string
>& tags
,
228 JobSpooler::Delegate
* delegate
) OVERRIDE
{
229 // TODO(gene): add tags handling.
230 scoped_refptr
<printing::PrintBackend
> print_backend(
231 printing::PrintBackend::CreateInstance(NULL
));
232 crash_keys::ScopedPrinterInfo
crash_key(
233 print_backend
->GetPrinterDriverInfo(printer_name
));
234 return core_
->Spool(print_ticket
, print_ticket_mime_type
,
235 print_data_file_path
, print_data_mime_type
,
236 printer_name
, job_title
, delegate
);
240 virtual ~JobSpoolerWin() {}
243 // We use a Core class because we want a separate RefCountedThreadSafe
244 // implementation for ServiceUtilityProcessHost::Client.
245 class Core
: public ServiceUtilityProcessHost::Client
,
246 public base::win::ObjectWatcher::Delegate
{
249 : last_page_printed_(-1),
257 bool Spool(const std::string
& print_ticket
,
258 const std::string
& print_ticket_mime_type
,
259 const base::FilePath
& print_data_file_path
,
260 const std::string
& print_data_mime_type
,
261 const std::string
& printer_name
,
262 const std::string
& job_title
,
263 JobSpooler::Delegate
* delegate
) {
265 // We are already in the process of printing.
269 base::string16 printer_wide
= base::UTF8ToWide(printer_name
);
270 last_page_printed_
= -1;
271 // We only support PDF and XPS documents for now.
272 if (print_data_mime_type
== kContentTypePDF
) {
273 scoped_ptr
<DEVMODE
, base::FreeDeleter
> dev_mode
;
274 if (print_ticket_mime_type
== kContentTypeJSON
) {
275 dev_mode
= CjtToDevMode(printer_wide
, print_ticket
);
277 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
278 dev_mode
= printing::XpsTicketToDevMode(printer_wide
, print_ticket
);
286 HDC dc
= CreateDC(L
"WINSPOOL", printer_wide
.c_str(), NULL
,
293 di
.cbSize
= sizeof(DOCINFO
);
294 base::string16 doc_name
= base::UTF8ToUTF16(job_title
);
295 DCHECK(printing::SimplifyDocumentTitle(doc_name
) == doc_name
);
296 di
.lpszDocName
= doc_name
.c_str();
297 job_id_
= StartDoc(dc
, &di
);
302 saved_dc_
= SaveDC(printer_dc_
.Get());
303 print_data_file_path_
= print_data_file_path
;
304 delegate_
= delegate
;
305 RenderNextPDFPages();
306 } else if (print_data_mime_type
== kContentTypeXPS
) {
307 DCHECK(print_ticket_mime_type
== kContentTypeXML
);
308 bool ret
= PrintXPSDocument(printer_name
,
310 print_data_file_path
,
313 delegate_
= delegate
;
322 void PreparePageDCForPrinting(HDC
, double scale_factor
) {
323 SetGraphicsMode(printer_dc_
.Get(), GM_ADVANCED
);
324 // Setup the matrix to translate and scale to the right place. Take in
325 // account the scale factor.
326 // Note that the printing output is relative to printable area of
327 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
328 int offset_x
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETX
);
329 int offset_y
= ::GetDeviceCaps(printer_dc_
.Get(), PHYSICALOFFSETY
);
331 xform
.eDx
= static_cast<float>(-offset_x
);
332 xform
.eDy
= static_cast<float>(-offset_y
);
333 xform
.eM11
= xform
.eM22
= 1.0 / scale_factor
;
334 SetWorldTransform(printer_dc_
.Get(), &xform
);
337 // ServiceUtilityProcessHost::Client implementation.
338 virtual void OnRenderPDFPagesToMetafileSucceeded(
339 const printing::Emf
& metafile
,
340 int highest_rendered_page_number
,
341 double scale_factor
) OVERRIDE
{
342 PreparePageDCForPrinting(printer_dc_
.Get(), scale_factor
);
343 metafile
.SafePlayback(printer_dc_
.Get());
344 bool done_printing
= (highest_rendered_page_number
!=
345 last_page_printed_
+ kPageCountPerBatch
);
346 last_page_printed_
= highest_rendered_page_number
;
350 RenderNextPDFPages();
353 // base::win::ObjectWatcher::Delegate implementation.
354 virtual void OnObjectSignaled(HANDLE object
) OVERRIDE
{
355 DCHECK(xps_print_job_
);
356 DCHECK(object
== job_progress_event_
.Get());
357 ResetEvent(job_progress_event_
.Get());
360 XPS_JOB_STATUS job_status
= {0};
361 xps_print_job_
->GetJobStatus(&job_status
);
362 if ((job_status
.completion
== XPS_JOB_CANCELLED
) ||
363 (job_status
.completion
== XPS_JOB_FAILED
)) {
364 delegate_
->OnJobSpoolFailed();
365 } else if (job_status
.jobId
||
366 (job_status
.completion
== XPS_JOB_COMPLETED
)) {
367 // Note: In the case of the XPS document being printed to the
368 // Microsoft XPS Document Writer, it seems to skip spooling the job
369 // and goes to the completed state without ever assigning a job id.
370 delegate_
->OnJobSpoolSucceeded(job_status
.jobId
);
372 job_progress_watcher_
.StopWatching();
373 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
377 virtual void OnRenderPDFPagesToMetafileFailed() OVERRIDE
{
381 virtual void OnChildDied() OVERRIDE
{
386 // Helper class to allow PrintXPSDocument() to have multiple exits.
387 class PrintJobCanceler
{
389 explicit PrintJobCanceler(
390 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr
)
391 : job_ptr_(job_ptr
) {
393 ~PrintJobCanceler() {
394 if (job_ptr_
&& *job_ptr_
) {
395 (*job_ptr_
)->Cancel();
400 void reset() { job_ptr_
= NULL
; }
403 base::win::ScopedComPtr
<IXpsPrintJob
>* job_ptr_
;
405 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler
);
408 void PrintJobDone() {
409 // If there is no delegate, then there is nothing pending to process.
412 RestoreDC(printer_dc_
.Get(), saved_dc_
);
413 EndDoc(printer_dc_
.Get());
414 if (-1 == last_page_printed_
) {
415 delegate_
->OnJobSpoolFailed();
417 delegate_
->OnJobSpoolSucceeded(job_id_
);
422 void RenderNextPDFPages() {
423 printing::PageRange range
;
424 // Render 10 pages at a time.
425 range
.from
= last_page_printed_
+ 1;
426 range
.to
= last_page_printed_
+ kPageCountPerBatch
;
427 std::vector
<printing::PageRange
> page_ranges
;
428 page_ranges
.push_back(range
);
430 int printer_dpi
= ::GetDeviceCaps(printer_dc_
.Get(), LOGPIXELSX
);
431 int dc_width
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALWIDTH
);
432 int dc_height
= GetDeviceCaps(printer_dc_
.Get(), PHYSICALHEIGHT
);
433 gfx::Rect
render_area(0, 0, dc_width
, dc_height
);
434 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
436 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox
, this,
437 print_data_file_path_
, render_area
, printer_dpi
,
438 page_ranges
, base::MessageLoopProxy::current()));
441 // Called on the service process IO thread.
442 void RenderPDFPagesInSandbox(
443 const base::FilePath
& pdf_path
, const gfx::Rect
& render_area
,
444 int render_dpi
, const std::vector
<printing::PageRange
>& page_ranges
,
445 const scoped_refptr
<base::MessageLoopProxy
>&
446 client_message_loop_proxy
) {
447 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
448 BelongsToCurrentThread());
449 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
450 new ServiceUtilityProcessHost(this, client_message_loop_proxy
));
451 // TODO(gene): For now we disabling autorotation for CloudPrinting.
452 // Landscape/Portrait setting is passed in the print ticket and
453 // server is generating portrait PDF always.
454 // We should enable autorotation once server will be able to generate
455 // PDF that matches paper size and orientation.
456 if (utility_host
->StartRenderPDFPagesToMetafile(
458 printing::PdfRenderSettings(render_area
, render_dpi
, false),
460 // The object will self-destruct when the child process dies.
461 utility_host
.release();
465 bool PrintXPSDocument(const std::string
& printer_name
,
466 const std::string
& job_title
,
467 const base::FilePath
& print_data_file_path
,
468 const std::string
& print_ticket
) {
469 if (!printing::XPSPrintModule::Init())
472 job_progress_event_
.Set(CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
473 if (!job_progress_event_
.Get())
476 PrintJobCanceler
job_canceler(&xps_print_job_
);
477 base::win::ScopedComPtr
<IXpsPrintJobStream
> doc_stream
;
478 base::win::ScopedComPtr
<IXpsPrintJobStream
> print_ticket_stream
;
479 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
480 base::UTF8ToWide(printer_name
).c_str(),
481 base::UTF8ToWide(job_title
).c_str(),
482 NULL
, job_progress_event_
.Get(), NULL
, NULL
, NULL
,
483 xps_print_job_
.Receive(), doc_stream
.Receive(),
484 print_ticket_stream
.Receive())))
487 ULONG print_bytes_written
= 0;
488 if (FAILED(print_ticket_stream
->Write(print_ticket
.c_str(),
489 print_ticket
.length(),
490 &print_bytes_written
)))
492 DCHECK_EQ(print_ticket
.length(), print_bytes_written
);
493 if (FAILED(print_ticket_stream
->Close()))
496 std::string document_data
;
497 base::ReadFileToString(print_data_file_path
, &document_data
);
498 ULONG doc_bytes_written
= 0;
499 if (FAILED(doc_stream
->Write(document_data
.c_str(),
500 document_data
.length(),
501 &doc_bytes_written
)))
503 DCHECK_EQ(document_data
.length(), doc_bytes_written
);
504 if (FAILED(doc_stream
->Close()))
507 job_progress_watcher_
.StartWatching(job_progress_event_
.Get(), this);
508 job_canceler
.reset();
512 // Some Cairo-generated PDFs from Chrome OS result in huge metafiles.
513 // So the PageCountPerBatch is set to 1 for now.
514 // TODO(sanjeevr): Figure out a smarter way to determine the pages per
515 // batch. Filed a bug to track this at
516 // http://code.google.com/p/chromium/issues/detail?id=57350.
517 static const int kPageCountPerBatch
= 1;
519 int last_page_printed_
;
520 PlatformJobId job_id_
;
521 PrintSystem::JobSpooler::Delegate
* delegate_
;
523 base::win::ScopedCreateDC printer_dc_
;
524 base::FilePath print_data_file_path_
;
525 base::win::ScopedHandle job_progress_event_
;
526 base::win::ObjectWatcher job_progress_watcher_
;
527 base::win::ScopedComPtr
<IXpsPrintJob
> xps_print_job_
;
529 DISALLOW_COPY_AND_ASSIGN(Core
);
531 scoped_refptr
<Core
> core_
;
533 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin
);
536 // A helper class to handle the response from the utility process to the
537 // request to fetch printer capabilities and defaults.
538 class PrinterCapsHandler
: public ServiceUtilityProcessHost::Client
{
541 const std::string
& printer_name
,
542 const PrintSystem::PrinterCapsAndDefaultsCallback
& callback
)
543 : printer_name_(printer_name
), callback_(callback
) {
546 // ServiceUtilityProcessHost::Client implementation.
547 virtual void OnChildDied() OVERRIDE
{
548 OnGetPrinterCapsAndDefaults(false, printer_name_
,
549 printing::PrinterCapsAndDefaults());
552 virtual void OnGetPrinterCapsAndDefaults(
554 const std::string
& printer_name
,
555 const printing::PrinterCapsAndDefaults
& caps_and_defaults
) OVERRIDE
{
556 callback_
.Run(succeeded
, printer_name
, caps_and_defaults
);
561 virtual void OnGetPrinterSemanticCapsAndDefaults(
563 const std::string
& printer_name
,
564 const printing::PrinterSemanticCapsAndDefaults
& semantic_info
) OVERRIDE
{
565 printing::PrinterCapsAndDefaults printer_info
;
567 printer_info
.caps_mime_type
= kContentTypeJSON
;
568 scoped_ptr
<base::DictionaryValue
> description(
569 PrinterSemanticCapsAndDefaultsToCdd(semantic_info
));
571 base::JSONWriter::WriteWithOptions(
572 description
.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT
,
573 &printer_info
.printer_capabilities
);
576 callback_
.Run(succeeded
, printer_name
, printer_info
);
581 void StartGetPrinterCapsAndDefaults() {
582 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
584 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl
, this,
585 base::MessageLoopProxy::current()));
588 void StartGetPrinterSemanticCapsAndDefaults() {
589 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
591 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl
,
592 this, base::MessageLoopProxy::current()));
596 void GetPrinterCapsAndDefaultsImpl(
597 const scoped_refptr
<base::MessageLoopProxy
>&
598 client_message_loop_proxy
) {
599 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
600 BelongsToCurrentThread());
601 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
602 new ServiceUtilityProcessHost(this, client_message_loop_proxy
));
603 if (utility_host
->StartGetPrinterCapsAndDefaults(printer_name_
)) {
604 // The object will self-destruct when the child process dies.
605 utility_host
.release();
607 client_message_loop_proxy
->PostTask(
609 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
613 void GetPrinterSemanticCapsAndDefaultsImpl(
614 const scoped_refptr
<base::MessageLoopProxy
>&
615 client_message_loop_proxy
) {
616 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
617 BelongsToCurrentThread());
618 scoped_ptr
<ServiceUtilityProcessHost
> utility_host(
619 new ServiceUtilityProcessHost(this, client_message_loop_proxy
));
620 if (utility_host
->StartGetPrinterSemanticCapsAndDefaults(printer_name_
)) {
621 // The object will self-destruct when the child process dies.
622 utility_host
.release();
624 client_message_loop_proxy
->PostTask(
626 base::Bind(&PrinterCapsHandler::OnChildDied
, this));
630 std::string printer_name_
;
631 PrintSystem::PrinterCapsAndDefaultsCallback callback_
;
634 class PrintSystemWin
: public PrintSystem
{
638 // PrintSystem implementation.
639 virtual PrintSystemResult
Init() OVERRIDE
;
640 virtual PrintSystem::PrintSystemResult
EnumeratePrinters(
641 printing::PrinterList
* printer_list
) OVERRIDE
;
642 virtual void GetPrinterCapsAndDefaults(
643 const std::string
& printer_name
,
644 const PrinterCapsAndDefaultsCallback
& callback
) OVERRIDE
;
645 virtual bool IsValidPrinter(const std::string
& printer_name
) OVERRIDE
;
646 virtual bool ValidatePrintTicket(
647 const std::string
& printer_name
,
648 const std::string
& print_ticket_data
,
649 const std::string
& print_ticket_data_mime_type
) OVERRIDE
;
650 virtual bool GetJobDetails(const std::string
& printer_name
,
651 PlatformJobId job_id
,
652 PrintJobDetails
*job_details
) OVERRIDE
;
653 virtual PrintSystem::PrintServerWatcher
* CreatePrintServerWatcher() OVERRIDE
;
654 virtual PrintSystem::PrinterWatcher
* CreatePrinterWatcher(
655 const std::string
& printer_name
) OVERRIDE
;
656 virtual PrintSystem::JobSpooler
* CreateJobSpooler() OVERRIDE
;
657 virtual bool UseCddAndCjt() OVERRIDE
;
658 virtual std::string
GetSupportedMimeTypes() OVERRIDE
;
661 std::string
PrintSystemWin::GetPrinterDriverInfo(
662 const std::string
& printer_name
) const;
664 scoped_refptr
<printing::PrintBackend
> print_backend_
;
666 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin
);
669 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
670 print_backend_
= printing::PrintBackend::CreateInstance(NULL
);
673 PrintSystem::PrintSystemResult
PrintSystemWin::Init() {
674 use_cdd_
= !CommandLine::ForCurrentProcess()->HasSwitch(
675 switches::kEnableCloudPrintXps
);
678 use_cdd_
= !printing::XPSModule::Init();
681 HPTPROVIDER provider
= NULL
;
682 HRESULT hr
= printing::XPSModule::OpenProvider(L
"", 1, &provider
);
684 printing::XPSModule::CloseProvider(provider
);
685 // Use cdd if error is different from expected.
686 use_cdd_
= (hr
!= HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME
));
689 return PrintSystemResult(true, std::string());
692 PrintSystem::PrintSystemResult
PrintSystemWin::EnumeratePrinters(
693 printing::PrinterList
* printer_list
) {
694 bool ret
= print_backend_
->EnumeratePrinters(printer_list
);
695 return PrintSystemResult(ret
, std::string());
698 void PrintSystemWin::GetPrinterCapsAndDefaults(
699 const std::string
& printer_name
,
700 const PrinterCapsAndDefaultsCallback
& callback
) {
701 // Launch as child process to retrieve the capabilities and defaults because
702 // this involves invoking a printer driver DLL and crashes have been known to
704 PrinterCapsHandler
* handler
= new PrinterCapsHandler(printer_name
, callback
);
707 handler
->StartGetPrinterSemanticCapsAndDefaults();
709 handler
->StartGetPrinterCapsAndDefaults();
712 bool PrintSystemWin::IsValidPrinter(const std::string
& printer_name
) {
713 return print_backend_
->IsValidPrinter(printer_name
);
716 bool PrintSystemWin::ValidatePrintTicket(
717 const std::string
& printer_name
,
718 const std::string
& print_ticket_data
,
719 const std::string
& print_ticket_data_mime_type
) {
720 crash_keys::ScopedPrinterInfo
crash_key(GetPrinterDriverInfo(printer_name
));
723 return print_ticket_data_mime_type
== kContentTypeJSON
&&
724 IsValidCjt(print_ticket_data
);
726 DCHECK(print_ticket_data_mime_type
== kContentTypeXML
);
728 printing::ScopedXPSInitializer xps_initializer
;
729 if (!xps_initializer
.initialized()) {
730 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
734 HPTPROVIDER provider
= NULL
;
735 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name
), 1,
738 base::win::ScopedComPtr
<IStream
> print_ticket_stream
;
739 CreateStreamOnHGlobal(NULL
, TRUE
, print_ticket_stream
.Receive());
740 ULONG bytes_written
= 0;
741 print_ticket_stream
->Write(print_ticket_data
.c_str(),
742 print_ticket_data
.length(),
744 DCHECK(bytes_written
== print_ticket_data
.length());
745 LARGE_INTEGER pos
= {0};
746 ULARGE_INTEGER new_pos
= {0};
747 print_ticket_stream
->Seek(pos
, STREAM_SEEK_SET
, &new_pos
);
748 base::win::ScopedBstr error
;
749 base::win::ScopedComPtr
<IStream
> result_ticket_stream
;
750 CreateStreamOnHGlobal(NULL
, TRUE
, result_ticket_stream
.Receive());
751 ret
= SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
753 print_ticket_stream
.get(),
756 result_ticket_stream
.get(),
758 printing::XPSModule::CloseProvider(provider
);
763 bool PrintSystemWin::GetJobDetails(const std::string
& printer_name
,
764 PlatformJobId job_id
,
765 PrintJobDetails
*job_details
) {
766 crash_keys::ScopedPrinterInfo
crash_key(
767 print_backend_
->GetPrinterDriverInfo(printer_name
));
769 printing::ScopedPrinterHandle printer_handle
;
770 std::wstring printer_name_wide
= base::UTF8ToWide(printer_name
);
771 printer_handle
.OpenPrinter(printer_name_wide
.c_str());
772 DCHECK(printer_handle
.IsValid());
774 if (printer_handle
.IsValid()) {
775 DWORD bytes_needed
= 0;
776 GetJob(printer_handle
, job_id
, 1, NULL
, 0, &bytes_needed
);
777 DWORD last_error
= GetLastError();
778 if (ERROR_INVALID_PARAMETER
!= last_error
) {
779 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
780 DCHECK(last_error
== ERROR_INSUFFICIENT_BUFFER
);
781 scoped_ptr
<BYTE
[]> job_info_buffer(new BYTE
[bytes_needed
]);
782 if (GetJob(printer_handle
, job_id
, 1, job_info_buffer
.get(), bytes_needed
,
784 JOB_INFO_1
*job_info
=
785 reinterpret_cast<JOB_INFO_1
*>(job_info_buffer
.get());
786 if (job_info
->pStatus
) {
787 base::WideToUTF8(job_info
->pStatus
, wcslen(job_info
->pStatus
),
788 &job_details
->status_message
);
790 job_details
->platform_status_flags
= job_info
->Status
;
791 if ((job_info
->Status
& JOB_STATUS_COMPLETE
) ||
792 (job_info
->Status
& JOB_STATUS_PRINTED
)) {
793 job_details
->status
= PRINT_JOB_STATUS_COMPLETED
;
794 } else if (job_info
->Status
& JOB_STATUS_ERROR
) {
795 job_details
->status
= PRINT_JOB_STATUS_ERROR
;
797 job_details
->status
= PRINT_JOB_STATUS_IN_PROGRESS
;
799 job_details
->total_pages
= job_info
->TotalPages
;
800 job_details
->pages_printed
= job_info
->PagesPrinted
;
808 PrintSystem::PrintServerWatcher
*
809 PrintSystemWin::CreatePrintServerWatcher() {
810 return new PrintServerWatcherWin();
813 PrintSystem::PrinterWatcher
* PrintSystemWin::CreatePrinterWatcher(
814 const std::string
& printer_name
) {
815 DCHECK(!printer_name
.empty());
816 return new PrinterWatcherWin(printer_name
);
819 PrintSystem::JobSpooler
* PrintSystemWin::CreateJobSpooler() {
820 return new JobSpoolerWin();
823 bool PrintSystemWin::UseCddAndCjt() {
827 std::string
PrintSystemWin::GetSupportedMimeTypes() {
830 result
= kContentTypeXPS
;
833 result
+= kContentTypePDF
;
837 std::string
PrintSystemWin::GetPrinterDriverInfo(
838 const std::string
& printer_name
) const {
839 return print_backend_
->GetPrinterDriverInfo(printer_name
);
844 scoped_refptr
<PrintSystem
> PrintSystem::CreateInstance(
845 const base::DictionaryValue
* print_system_settings
) {
846 return new PrintSystemWin
;
849 } // namespace cloud_print