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/files/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/pdf_render_settings.h"
27 #include "printing/printing_utils.h"
28 #include "ui/gfx/geometry/rect.h"
30 namespace cloud_print {
34 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
36 PrintSystemWatcherWin()
40 ~PrintSystemWatcherWin() {
46 virtual ~Delegate() {}
47 virtual void OnPrinterAdded() = 0;
48 virtual void OnPrinterDeleted() = 0;
49 virtual void OnPrinterChanged() = 0;
50 virtual void OnJobChanged() = 0;
53 bool Start(const std::string& printer_name, Delegate* delegate) {
54 scoped_refptr<printing::PrintBackend> print_backend(
55 printing::PrintBackend::CreateInstance(NULL));
56 printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
57 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
60 // An empty printer name means watch the current server, we need to pass
61 // NULL to OpenPrinter.
62 LPTSTR printer_name_to_use = NULL;
63 std::wstring printer_name_wide;
64 if (!printer_name.empty()) {
65 printer_name_wide = base::UTF8ToWide(printer_name);
66 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
69 if (printer_.OpenPrinter(printer_name_to_use)) {
70 printer_change_.Set(FindFirstPrinterChangeNotification(
71 printer_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
72 if (printer_change_.IsValid()) {
73 ret = watcher_.StartWatching(printer_change_.Get(), this);
83 watcher_.StopWatching();
85 printer_change_.Close();
89 // base::ObjectWatcher::Delegate method
90 virtual void OnObjectSignaled(HANDLE object) {
91 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
93 FindNextPrinterChangeNotification(object, &change, NULL, NULL);
95 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
96 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
97 // For printer connections, we get spurious change notifications with
98 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
100 if (change & PRINTER_CHANGE_ADD_PRINTER) {
101 delegate_->OnPrinterAdded();
102 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
103 delegate_->OnPrinterDeleted();
104 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
105 delegate_->OnPrinterChanged();
107 if (change & PRINTER_CHANGE_JOB) {
108 delegate_->OnJobChanged();
111 watcher_.StartWatching(printer_change_.Get(), this);
114 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
115 DCHECK(printer_info);
116 return InitBasicPrinterInfo(printer_.Get(), printer_info);
120 base::win::ObjectWatcher watcher_;
121 printing::ScopedPrinterHandle printer_; // The printer being watched
122 // Returned by FindFirstPrinterChangeNotifier.
123 printing::ScopedPrinterChangeHandle printer_change_;
124 Delegate* delegate_; // Delegate to notify
125 bool did_signal_; // DoneWaiting was called
126 std::string printer_info_; // For crash reporting.
129 class PrintServerWatcherWin
130 : public PrintSystem::PrintServerWatcher,
131 public PrintSystemWatcherWin::Delegate {
133 PrintServerWatcherWin() : delegate_(NULL) {}
135 // PrintSystem::PrintServerWatcher implementation.
136 virtual bool StartWatching(
137 PrintSystem::PrintServerWatcher::Delegate* delegate) OVERRIDE{
138 delegate_ = delegate;
139 return watcher_.Start(std::string(), this);
142 virtual bool StopWatching() OVERRIDE{
143 bool ret = watcher_.Stop();
148 // PrintSystemWatcherWin::Delegate implementation.
149 virtual void OnPrinterAdded() OVERRIDE {
150 delegate_->OnPrinterAdded();
152 virtual void OnPrinterDeleted() OVERRIDE {}
153 virtual void OnPrinterChanged() OVERRIDE {}
154 virtual void OnJobChanged() OVERRIDE {}
157 virtual ~PrintServerWatcherWin() {}
160 PrintSystem::PrintServerWatcher::Delegate* delegate_;
161 PrintSystemWatcherWin watcher_;
163 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
166 class PrinterWatcherWin
167 : public PrintSystem::PrinterWatcher,
168 public PrintSystemWatcherWin::Delegate {
170 explicit PrinterWatcherWin(const std::string& printer_name)
171 : printer_name_(printer_name),
175 // PrintSystem::PrinterWatcher implementation.
176 virtual bool StartWatching(
177 PrintSystem::PrinterWatcher::Delegate* delegate) OVERRIDE {
178 delegate_ = delegate;
179 return watcher_.Start(printer_name_, this);
182 virtual bool StopWatching() OVERRIDE {
183 bool ret = watcher_.Stop();
188 virtual bool GetCurrentPrinterInfo(
189 printing::PrinterBasicInfo* printer_info) OVERRIDE {
190 return watcher_.GetCurrentPrinterInfo(printer_info);
193 // PrintSystemWatcherWin::Delegate implementation.
194 virtual void OnPrinterAdded() OVERRIDE {
197 virtual void OnPrinterDeleted() OVERRIDE {
198 delegate_->OnPrinterDeleted();
200 virtual void OnPrinterChanged() OVERRIDE {
201 delegate_->OnPrinterChanged();
203 virtual void OnJobChanged() OVERRIDE {
204 delegate_->OnJobChanged();
208 virtual ~PrinterWatcherWin() {}
211 std::string printer_name_;
212 PrintSystem::PrinterWatcher::Delegate* delegate_;
213 PrintSystemWatcherWin watcher_;
215 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
218 class JobSpoolerWin : public PrintSystem::JobSpooler {
220 JobSpoolerWin() : core_(new Core) {}
222 // PrintSystem::JobSpooler implementation.
223 virtual bool Spool(const std::string& print_ticket,
224 const std::string& print_ticket_mime_type,
225 const base::FilePath& print_data_file_path,
226 const std::string& print_data_mime_type,
227 const std::string& printer_name,
228 const std::string& job_title,
229 const std::vector<std::string>& tags,
230 JobSpooler::Delegate* delegate) OVERRIDE {
231 // TODO(gene): add tags handling.
232 scoped_refptr<printing::PrintBackend> print_backend(
233 printing::PrintBackend::CreateInstance(NULL));
234 crash_keys::ScopedPrinterInfo crash_key(
235 print_backend->GetPrinterDriverInfo(printer_name));
236 return core_->Spool(print_ticket, print_ticket_mime_type,
237 print_data_file_path, print_data_mime_type,
238 printer_name, job_title, delegate);
242 virtual ~JobSpoolerWin() {}
245 // We use a Core class because we want a separate RefCountedThreadSafe
246 // implementation for ServiceUtilityProcessHost::Client.
247 class Core : public ServiceUtilityProcessHost::Client,
248 public base::win::ObjectWatcher::Delegate {
250 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
254 bool Spool(const std::string& print_ticket,
255 const std::string& print_ticket_mime_type,
256 const base::FilePath& print_data_file_path,
257 const std::string& print_data_mime_type,
258 const std::string& printer_name,
259 const std::string& job_title,
260 JobSpooler::Delegate* delegate) {
262 // We are already in the process of printing.
266 base::string16 printer_wide = base::UTF8ToWide(printer_name);
267 // We only support PDF and XPS documents for now.
268 if (print_data_mime_type == kContentTypePDF) {
269 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
270 if (print_ticket_mime_type == kContentTypeJSON) {
271 dev_mode = CjtToDevMode(printer_wide, print_ticket);
273 DCHECK(print_ticket_mime_type == kContentTypeXML);
274 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
282 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
289 di.cbSize = sizeof(DOCINFO);
290 base::string16 doc_name = base::UTF8ToUTF16(job_title);
291 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
292 di.lpszDocName = doc_name.c_str();
293 job_id_ = StartDoc(dc, &di);
298 saved_dc_ = SaveDC(printer_dc_.Get());
299 print_data_file_path_ = print_data_file_path;
300 delegate_ = delegate;
302 } else if (print_data_mime_type == kContentTypeXPS) {
303 DCHECK(print_ticket_mime_type == kContentTypeXML);
304 bool ret = PrintXPSDocument(printer_name,
306 print_data_file_path,
309 delegate_ = delegate;
318 void PreparePageDCForPrinting(HDC, double scale_factor) {
319 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
320 // Setup the matrix to translate and scale to the right place. Take in
321 // account the scale factor.
322 // Note that the printing output is relative to printable area of
323 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
324 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
325 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
327 xform.eDx = static_cast<float>(-offset_x);
328 xform.eDy = static_cast<float>(-offset_y);
329 xform.eM11 = xform.eM22 = 1.0 / scale_factor;
330 SetWorldTransform(printer_dc_.Get(), &xform);
333 // ServiceUtilityProcessHost::Client implementation.
334 virtual void OnRenderPDFPagesToMetafilePageDone(
336 const printing::MetafilePlayer& emf) OVERRIDE {
337 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
338 ::StartPage(printer_dc_.Get());
339 emf.SafePlayback(printer_dc_.Get());
340 ::EndPage(printer_dc_.Get());
343 // ServiceUtilityProcessHost::Client implementation.
344 virtual void OnRenderPDFPagesToMetafileDone(bool success) OVERRIDE {
345 PrintJobDone(success);
348 virtual void OnChildDied() OVERRIDE { PrintJobDone(false); }
350 // base::win::ObjectWatcher::Delegate implementation.
351 virtual void OnObjectSignaled(HANDLE object) OVERRIDE {
352 DCHECK(xps_print_job_);
353 DCHECK(object == job_progress_event_.Get());
354 ResetEvent(job_progress_event_.Get());
357 XPS_JOB_STATUS job_status = {0};
358 xps_print_job_->GetJobStatus(&job_status);
359 if ((job_status.completion == XPS_JOB_CANCELLED) ||
360 (job_status.completion == XPS_JOB_FAILED)) {
361 delegate_->OnJobSpoolFailed();
362 } else if (job_status.jobId ||
363 (job_status.completion == XPS_JOB_COMPLETED)) {
364 // Note: In the case of the XPS document being printed to the
365 // Microsoft XPS Document Writer, it seems to skip spooling the job
366 // and goes to the completed state without ever assigning a job id.
367 delegate_->OnJobSpoolSucceeded(job_status.jobId);
369 job_progress_watcher_.StopWatching();
370 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
375 // Helper class to allow PrintXPSDocument() to have multiple exits.
376 class PrintJobCanceler {
378 explicit PrintJobCanceler(
379 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
380 : job_ptr_(job_ptr) {
382 ~PrintJobCanceler() {
383 if (job_ptr_ && *job_ptr_) {
384 (*job_ptr_)->Cancel();
389 void reset() { job_ptr_ = NULL; }
392 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
394 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
397 void PrintJobDone(bool success) {
398 // If there is no delegate, then there is nothing pending to process.
401 RestoreDC(printer_dc_.Get(), saved_dc_);
402 EndDoc(printer_dc_.Get());
404 delegate_->OnJobSpoolSucceeded(job_id_);
406 delegate_->OnJobSpoolFailed();
411 void RenderPDFPages() {
412 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
413 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
414 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
415 gfx::Rect render_area(0, 0, dc_width, dc_height);
416 g_service_process->io_thread()->message_loop_proxy()->PostTask(
418 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox,
420 print_data_file_path_,
423 base::MessageLoopProxy::current()));
426 // Called on the service process IO thread.
427 void RenderPDFPagesInSandbox(const base::FilePath& pdf_path,
428 const gfx::Rect& render_area,
430 const scoped_refptr<base::MessageLoopProxy>&
431 client_message_loop_proxy) {
432 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
433 BelongsToCurrentThread());
434 scoped_ptr<ServiceUtilityProcessHost> utility_host(
435 new ServiceUtilityProcessHost(this, client_message_loop_proxy));
436 // TODO(gene): For now we disabling autorotation for CloudPrinting.
437 // Landscape/Portrait setting is passed in the print ticket and
438 // server is generating portrait PDF always.
439 // We should enable autorotation once server will be able to generate
440 // PDF that matches paper size and orientation.
441 if (utility_host->StartRenderPDFPagesToMetafile(
443 printing::PdfRenderSettings(render_area, render_dpi, false))) {
444 // The object will self-destruct when the child process dies.
445 utility_host.release();
447 client_message_loop_proxy->PostTask(
448 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
452 bool PrintXPSDocument(const std::string& printer_name,
453 const std::string& job_title,
454 const base::FilePath& print_data_file_path,
455 const std::string& print_ticket) {
456 if (!printing::XPSPrintModule::Init())
459 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
460 if (!job_progress_event_.Get())
463 PrintJobCanceler job_canceler(&xps_print_job_);
464 base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
465 base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
466 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
467 base::UTF8ToWide(printer_name).c_str(),
468 base::UTF8ToWide(job_title).c_str(),
469 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
470 xps_print_job_.Receive(), doc_stream.Receive(),
471 print_ticket_stream.Receive())))
474 ULONG print_bytes_written = 0;
475 if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
476 print_ticket.length(),
477 &print_bytes_written)))
479 DCHECK_EQ(print_ticket.length(), print_bytes_written);
480 if (FAILED(print_ticket_stream->Close()))
483 std::string document_data;
484 base::ReadFileToString(print_data_file_path, &document_data);
485 ULONG doc_bytes_written = 0;
486 if (FAILED(doc_stream->Write(document_data.c_str(),
487 document_data.length(),
488 &doc_bytes_written)))
490 DCHECK_EQ(document_data.length(), doc_bytes_written);
491 if (FAILED(doc_stream->Close()))
494 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
495 job_canceler.reset();
499 PlatformJobId job_id_;
500 PrintSystem::JobSpooler::Delegate* delegate_;
502 base::win::ScopedCreateDC printer_dc_;
503 base::FilePath print_data_file_path_;
504 base::win::ScopedHandle job_progress_event_;
505 base::win::ObjectWatcher job_progress_watcher_;
506 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
508 DISALLOW_COPY_AND_ASSIGN(Core);
510 scoped_refptr<Core> core_;
512 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
515 // A helper class to handle the response from the utility process to the
516 // request to fetch printer capabilities and defaults.
517 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
520 const std::string& printer_name,
521 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
522 : printer_name_(printer_name), callback_(callback) {
525 // ServiceUtilityProcessHost::Client implementation.
526 virtual void OnChildDied() OVERRIDE {
527 OnGetPrinterCapsAndDefaults(false, printer_name_,
528 printing::PrinterCapsAndDefaults());
531 virtual void OnGetPrinterCapsAndDefaults(
533 const std::string& printer_name,
534 const printing::PrinterCapsAndDefaults& caps_and_defaults) OVERRIDE {
535 callback_.Run(succeeded, printer_name, caps_and_defaults);
540 virtual void OnGetPrinterSemanticCapsAndDefaults(
542 const std::string& printer_name,
543 const printing::PrinterSemanticCapsAndDefaults& semantic_info) OVERRIDE {
544 printing::PrinterCapsAndDefaults printer_info;
546 printer_info.caps_mime_type = kContentTypeJSON;
547 scoped_ptr<base::DictionaryValue> description(
548 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
550 base::JSONWriter::WriteWithOptions(
551 description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
552 &printer_info.printer_capabilities);
555 callback_.Run(succeeded, printer_name, printer_info);
560 void StartGetPrinterCapsAndDefaults() {
561 g_service_process->io_thread()->message_loop_proxy()->PostTask(
563 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
564 base::MessageLoopProxy::current()));
567 void StartGetPrinterSemanticCapsAndDefaults() {
568 g_service_process->io_thread()->message_loop_proxy()->PostTask(
570 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
571 this, base::MessageLoopProxy::current()));
575 void GetPrinterCapsAndDefaultsImpl(
576 const scoped_refptr<base::MessageLoopProxy>&
577 client_message_loop_proxy) {
578 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
579 BelongsToCurrentThread());
580 scoped_ptr<ServiceUtilityProcessHost> utility_host(
581 new ServiceUtilityProcessHost(this, client_message_loop_proxy));
582 if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
583 // The object will self-destruct when the child process dies.
584 utility_host.release();
586 client_message_loop_proxy->PostTask(
588 base::Bind(&PrinterCapsHandler::OnChildDied, this));
592 void GetPrinterSemanticCapsAndDefaultsImpl(
593 const scoped_refptr<base::MessageLoopProxy>&
594 client_message_loop_proxy) {
595 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
596 BelongsToCurrentThread());
597 scoped_ptr<ServiceUtilityProcessHost> utility_host(
598 new ServiceUtilityProcessHost(this, client_message_loop_proxy));
599 if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
600 // The object will self-destruct when the child process dies.
601 utility_host.release();
603 client_message_loop_proxy->PostTask(
605 base::Bind(&PrinterCapsHandler::OnChildDied, this));
609 std::string printer_name_;
610 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
613 class PrintSystemWin : public PrintSystem {
617 // PrintSystem implementation.
618 virtual PrintSystemResult Init() OVERRIDE;
619 virtual PrintSystem::PrintSystemResult EnumeratePrinters(
620 printing::PrinterList* printer_list) OVERRIDE;
621 virtual void GetPrinterCapsAndDefaults(
622 const std::string& printer_name,
623 const PrinterCapsAndDefaultsCallback& callback) OVERRIDE;
624 virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
625 virtual bool ValidatePrintTicket(
626 const std::string& printer_name,
627 const std::string& print_ticket_data,
628 const std::string& print_ticket_data_mime_type) OVERRIDE;
629 virtual bool GetJobDetails(const std::string& printer_name,
630 PlatformJobId job_id,
631 PrintJobDetails *job_details) OVERRIDE;
632 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() OVERRIDE;
633 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
634 const std::string& printer_name) OVERRIDE;
635 virtual PrintSystem::JobSpooler* CreateJobSpooler() OVERRIDE;
636 virtual bool UseCddAndCjt() OVERRIDE;
637 virtual std::string GetSupportedMimeTypes() OVERRIDE;
640 std::string PrintSystemWin::GetPrinterDriverInfo(
641 const std::string& printer_name) const;
643 scoped_refptr<printing::PrintBackend> print_backend_;
645 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
648 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
649 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
652 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
653 use_cdd_ = !CommandLine::ForCurrentProcess()->HasSwitch(
654 switches::kEnableCloudPrintXps);
657 use_cdd_ = !printing::XPSModule::Init();
660 HPTPROVIDER provider = NULL;
661 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
663 printing::XPSModule::CloseProvider(provider);
664 // Use cdd if error is different from expected.
665 use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
668 return PrintSystemResult(true, std::string());
671 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
672 printing::PrinterList* printer_list) {
673 bool ret = print_backend_->EnumeratePrinters(printer_list);
674 return PrintSystemResult(ret, std::string());
677 void PrintSystemWin::GetPrinterCapsAndDefaults(
678 const std::string& printer_name,
679 const PrinterCapsAndDefaultsCallback& callback) {
680 // Launch as child process to retrieve the capabilities and defaults because
681 // this involves invoking a printer driver DLL and crashes have been known to
683 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
686 handler->StartGetPrinterSemanticCapsAndDefaults();
688 handler->StartGetPrinterCapsAndDefaults();
691 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
692 return print_backend_->IsValidPrinter(printer_name);
695 bool PrintSystemWin::ValidatePrintTicket(
696 const std::string& printer_name,
697 const std::string& print_ticket_data,
698 const std::string& print_ticket_data_mime_type) {
699 crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
702 return print_ticket_data_mime_type == kContentTypeJSON &&
703 IsValidCjt(print_ticket_data);
705 DCHECK(print_ticket_data_mime_type == kContentTypeXML);
707 printing::ScopedXPSInitializer xps_initializer;
708 if (!xps_initializer.initialized()) {
709 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
713 HPTPROVIDER provider = NULL;
714 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
717 base::win::ScopedComPtr<IStream> print_ticket_stream;
718 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
719 ULONG bytes_written = 0;
720 print_ticket_stream->Write(print_ticket_data.c_str(),
721 print_ticket_data.length(),
723 DCHECK(bytes_written == print_ticket_data.length());
724 LARGE_INTEGER pos = {0};
725 ULARGE_INTEGER new_pos = {0};
726 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
727 base::win::ScopedBstr error;
728 base::win::ScopedComPtr<IStream> result_ticket_stream;
729 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
730 ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
732 print_ticket_stream.get(),
735 result_ticket_stream.get(),
737 printing::XPSModule::CloseProvider(provider);
742 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
743 PlatformJobId job_id,
744 PrintJobDetails *job_details) {
745 crash_keys::ScopedPrinterInfo crash_key(
746 print_backend_->GetPrinterDriverInfo(printer_name));
748 printing::ScopedPrinterHandle printer_handle;
749 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
750 printer_handle.OpenPrinter(printer_name_wide.c_str());
751 DCHECK(printer_handle.IsValid());
753 if (printer_handle.IsValid()) {
754 DWORD bytes_needed = 0;
755 GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
756 DWORD last_error = GetLastError();
757 if (ERROR_INVALID_PARAMETER != last_error) {
758 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
759 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
760 scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
761 if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
762 bytes_needed, &bytes_needed)) {
763 JOB_INFO_1 *job_info =
764 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
765 if (job_info->pStatus) {
766 base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
767 &job_details->status_message);
769 job_details->platform_status_flags = job_info->Status;
770 if ((job_info->Status & JOB_STATUS_COMPLETE) ||
771 (job_info->Status & JOB_STATUS_PRINTED)) {
772 job_details->status = PRINT_JOB_STATUS_COMPLETED;
773 } else if (job_info->Status & JOB_STATUS_ERROR) {
774 job_details->status = PRINT_JOB_STATUS_ERROR;
776 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
778 job_details->total_pages = job_info->TotalPages;
779 job_details->pages_printed = job_info->PagesPrinted;
787 PrintSystem::PrintServerWatcher*
788 PrintSystemWin::CreatePrintServerWatcher() {
789 return new PrintServerWatcherWin();
792 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
793 const std::string& printer_name) {
794 DCHECK(!printer_name.empty());
795 return new PrinterWatcherWin(printer_name);
798 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
799 return new JobSpoolerWin();
802 bool PrintSystemWin::UseCddAndCjt() {
806 std::string PrintSystemWin::GetSupportedMimeTypes() {
809 result = kContentTypeXPS;
812 result += kContentTypePDF;
816 std::string PrintSystemWin::GetPrinterDriverInfo(
817 const std::string& printer_name) const {
818 return print_backend_->GetPrinterDriverInfo(printer_name);
823 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
824 const base::DictionaryValue* print_system_settings) {
825 return new PrintSystemWin;
828 } // namespace cloud_print