[Storage] Blob Storage Refactoring pt 1:
[chromium-blink-merge.git] / chrome / service / cloud_print / print_system_win.cc
blob2d78735212b7f26163f632874a94609bac5ad98b
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/profiler/scoped_tracker.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/win/object_watcher.h"
14 #include "base/win/scoped_bstr.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/scoped_hdc.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
19 #include "chrome/common/cloud_print/cloud_print_constants.h"
20 #include "chrome/common/crash_keys.h"
21 #include "chrome/service/cloud_print/cdd_conversion_win.h"
22 #include "chrome/service/service_process.h"
23 #include "chrome/service/service_utility_process_host.h"
24 #include "printing/backend/win_helper.h"
25 #include "printing/emf_win.h"
26 #include "printing/page_range.h"
27 #include "printing/pdf_render_settings.h"
28 #include "printing/printing_utils.h"
29 #include "ui/gfx/geometry/rect.h"
31 namespace cloud_print {
33 namespace {
35 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
36 public:
37 PrintSystemWatcherWin()
38 : delegate_(NULL),
39 did_signal_(false) {
41 ~PrintSystemWatcherWin() {
42 Stop();
45 class Delegate {
46 public:
47 virtual ~Delegate() {}
48 virtual void OnPrinterAdded() = 0;
49 virtual void OnPrinterDeleted() = 0;
50 virtual void OnPrinterChanged() = 0;
51 virtual void OnJobChanged() = 0;
54 bool Start(const std::string& printer_name, Delegate* delegate) {
55 scoped_refptr<printing::PrintBackend> print_backend(
56 printing::PrintBackend::CreateInstance(NULL));
57 printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
58 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
60 delegate_ = delegate;
61 // An empty printer name means watch the current server, we need to pass
62 // NULL to OpenPrinter.
63 LPTSTR printer_name_to_use = NULL;
64 std::wstring printer_name_wide;
65 if (!printer_name.empty()) {
66 printer_name_wide = base::UTF8ToWide(printer_name);
67 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
69 bool ret = false;
70 if (printer_.OpenPrinter(printer_name_to_use)) {
71 printer_change_.Set(FindFirstPrinterChangeNotification(
72 printer_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
73 if (printer_change_.IsValid()) {
74 ret = watcher_.StartWatching(printer_change_.Get(), this);
77 if (!ret) {
78 Stop();
80 return ret;
83 bool Stop() {
84 watcher_.StopWatching();
85 printer_.Close();
86 printer_change_.Close();
87 return true;
90 // base::ObjectWatcher::Delegate method
91 virtual void OnObjectSignaled(HANDLE object) {
92 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
93 tracked_objects::ScopedTracker tracking_profile(
94 FROM_HERE_WITH_EXPLICIT_FUNCTION(
95 "PrintSystemWatcherWin_OnObjectSignaled"));
97 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
98 DWORD change = 0;
99 FindNextPrinterChangeNotification(object, &change, NULL, NULL);
101 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
102 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
103 // For printer connections, we get spurious change notifications with
104 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
105 // Ignore these.
106 if (change & PRINTER_CHANGE_ADD_PRINTER) {
107 delegate_->OnPrinterAdded();
108 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
109 delegate_->OnPrinterDeleted();
110 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
111 delegate_->OnPrinterChanged();
113 if (change & PRINTER_CHANGE_JOB) {
114 delegate_->OnJobChanged();
117 watcher_.StartWatching(printer_change_.Get(), this);
120 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
121 DCHECK(printer_info);
122 return InitBasicPrinterInfo(printer_.Get(), printer_info);
125 private:
126 base::win::ObjectWatcher watcher_;
127 printing::ScopedPrinterHandle printer_; // The printer being watched
128 // Returned by FindFirstPrinterChangeNotifier.
129 printing::ScopedPrinterChangeHandle printer_change_;
130 Delegate* delegate_; // Delegate to notify
131 bool did_signal_; // DoneWaiting was called
132 std::string printer_info_; // For crash reporting.
135 class PrintServerWatcherWin
136 : public PrintSystem::PrintServerWatcher,
137 public PrintSystemWatcherWin::Delegate {
138 public:
139 PrintServerWatcherWin() : delegate_(NULL) {}
141 // PrintSystem::PrintServerWatcher implementation.
142 virtual bool StartWatching(
143 PrintSystem::PrintServerWatcher::Delegate* delegate) override{
144 delegate_ = delegate;
145 return watcher_.Start(std::string(), this);
148 virtual bool StopWatching() override{
149 bool ret = watcher_.Stop();
150 delegate_ = NULL;
151 return ret;
154 // PrintSystemWatcherWin::Delegate implementation.
155 virtual void OnPrinterAdded() override {
156 delegate_->OnPrinterAdded();
158 virtual void OnPrinterDeleted() override {}
159 virtual void OnPrinterChanged() override {}
160 virtual void OnJobChanged() override {}
162 protected:
163 virtual ~PrintServerWatcherWin() {}
165 private:
166 PrintSystem::PrintServerWatcher::Delegate* delegate_;
167 PrintSystemWatcherWin watcher_;
169 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
172 class PrinterWatcherWin
173 : public PrintSystem::PrinterWatcher,
174 public PrintSystemWatcherWin::Delegate {
175 public:
176 explicit PrinterWatcherWin(const std::string& printer_name)
177 : printer_name_(printer_name),
178 delegate_(NULL) {
181 // PrintSystem::PrinterWatcher implementation.
182 virtual bool StartWatching(
183 PrintSystem::PrinterWatcher::Delegate* delegate) override {
184 delegate_ = delegate;
185 return watcher_.Start(printer_name_, this);
188 virtual bool StopWatching() override {
189 bool ret = watcher_.Stop();
190 delegate_ = NULL;
191 return ret;
194 virtual bool GetCurrentPrinterInfo(
195 printing::PrinterBasicInfo* printer_info) override {
196 return watcher_.GetCurrentPrinterInfo(printer_info);
199 // PrintSystemWatcherWin::Delegate implementation.
200 virtual void OnPrinterAdded() override {
201 NOTREACHED();
203 virtual void OnPrinterDeleted() override {
204 delegate_->OnPrinterDeleted();
206 virtual void OnPrinterChanged() override {
207 delegate_->OnPrinterChanged();
209 virtual void OnJobChanged() override {
210 delegate_->OnJobChanged();
213 protected:
214 virtual ~PrinterWatcherWin() {}
216 private:
217 std::string printer_name_;
218 PrintSystem::PrinterWatcher::Delegate* delegate_;
219 PrintSystemWatcherWin watcher_;
221 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
224 class JobSpoolerWin : public PrintSystem::JobSpooler {
225 public:
226 JobSpoolerWin() : core_(new Core) {}
228 // PrintSystem::JobSpooler implementation.
229 virtual bool Spool(const std::string& print_ticket,
230 const std::string& print_ticket_mime_type,
231 const base::FilePath& print_data_file_path,
232 const std::string& print_data_mime_type,
233 const std::string& printer_name,
234 const std::string& job_title,
235 const std::vector<std::string>& tags,
236 JobSpooler::Delegate* delegate) override {
237 // TODO(gene): add tags handling.
238 scoped_refptr<printing::PrintBackend> print_backend(
239 printing::PrintBackend::CreateInstance(NULL));
240 crash_keys::ScopedPrinterInfo crash_key(
241 print_backend->GetPrinterDriverInfo(printer_name));
242 return core_->Spool(print_ticket, print_ticket_mime_type,
243 print_data_file_path, print_data_mime_type,
244 printer_name, job_title, delegate);
247 protected:
248 virtual ~JobSpoolerWin() {}
250 private:
251 // We use a Core class because we want a separate RefCountedThreadSafe
252 // implementation for ServiceUtilityProcessHost::Client.
253 class Core : public ServiceUtilityProcessHost::Client,
254 public base::win::ObjectWatcher::Delegate {
255 public:
256 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
258 ~Core() {}
260 bool Spool(const std::string& print_ticket,
261 const std::string& print_ticket_mime_type,
262 const base::FilePath& print_data_file_path,
263 const std::string& print_data_mime_type,
264 const std::string& printer_name,
265 const std::string& job_title,
266 JobSpooler::Delegate* delegate) {
267 if (delegate_) {
268 // We are already in the process of printing.
269 NOTREACHED();
270 return false;
272 base::string16 printer_wide = base::UTF8ToWide(printer_name);
273 // We only support PDF and XPS documents for now.
274 if (print_data_mime_type == kContentTypePDF) {
275 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
276 if (print_ticket_mime_type == kContentTypeJSON) {
277 dev_mode = CjtToDevMode(printer_wide, print_ticket);
278 } else {
279 DCHECK(print_ticket_mime_type == kContentTypeXML);
280 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
283 if (!dev_mode) {
284 NOTREACHED();
285 return false;
288 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
289 dev_mode.get());
290 if (!dc) {
291 NOTREACHED();
292 return false;
294 DOCINFO di = {0};
295 di.cbSize = sizeof(DOCINFO);
296 base::string16 doc_name = base::UTF8ToUTF16(job_title);
297 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
298 di.lpszDocName = doc_name.c_str();
299 job_id_ = StartDoc(dc, &di);
300 if (job_id_ <= 0)
301 return false;
303 printer_dc_.Set(dc);
304 saved_dc_ = SaveDC(printer_dc_.Get());
305 print_data_file_path_ = print_data_file_path;
306 delegate_ = delegate;
307 RenderPDFPages();
308 } else if (print_data_mime_type == kContentTypeXPS) {
309 DCHECK(print_ticket_mime_type == kContentTypeXML);
310 bool ret = PrintXPSDocument(printer_name,
311 job_title,
312 print_data_file_path,
313 print_ticket);
314 if (ret)
315 delegate_ = delegate;
316 return ret;
317 } else {
318 NOTREACHED();
319 return false;
321 return true;
324 void PreparePageDCForPrinting(HDC, float scale_factor) {
325 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
326 // Setup the matrix to translate and scale to the right place. Take in
327 // account the scale factor.
328 // Note that the printing output is relative to printable area of
329 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
330 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
331 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
332 XFORM xform = {0};
333 xform.eDx = static_cast<float>(-offset_x);
334 xform.eDy = static_cast<float>(-offset_y);
335 xform.eM11 = xform.eM22 = 1.0f / scale_factor;
336 SetWorldTransform(printer_dc_.Get(), &xform);
339 // ServiceUtilityProcessHost::Client implementation.
340 virtual void OnRenderPDFPagesToMetafilePageDone(
341 float scale_factor,
342 const printing::MetafilePlayer& emf) override {
343 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
344 ::StartPage(printer_dc_.Get());
345 emf.SafePlayback(printer_dc_.Get());
346 ::EndPage(printer_dc_.Get());
349 // ServiceUtilityProcessHost::Client implementation.
350 virtual void OnRenderPDFPagesToMetafileDone(bool success) override {
351 PrintJobDone(success);
354 virtual void OnChildDied() override { PrintJobDone(false); }
356 // base::win::ObjectWatcher::Delegate implementation.
357 virtual void OnObjectSignaled(HANDLE object) override {
358 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is
359 // fixed.
360 tracked_objects::ScopedTracker tracking_profile(
361 FROM_HERE_WITH_EXPLICIT_FUNCTION("Core_OnObjectSignaled"));
363 DCHECK(xps_print_job_.get());
364 DCHECK(object == job_progress_event_.Get());
365 ResetEvent(job_progress_event_.Get());
366 if (!delegate_)
367 return;
368 XPS_JOB_STATUS job_status = {0};
369 xps_print_job_->GetJobStatus(&job_status);
370 if ((job_status.completion == XPS_JOB_CANCELLED) ||
371 (job_status.completion == XPS_JOB_FAILED)) {
372 delegate_->OnJobSpoolFailed();
373 } else if (job_status.jobId ||
374 (job_status.completion == XPS_JOB_COMPLETED)) {
375 // Note: In the case of the XPS document being printed to the
376 // Microsoft XPS Document Writer, it seems to skip spooling the job
377 // and goes to the completed state without ever assigning a job id.
378 delegate_->OnJobSpoolSucceeded(job_status.jobId);
379 } else {
380 job_progress_watcher_.StopWatching();
381 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
385 private:
386 // Helper class to allow PrintXPSDocument() to have multiple exits.
387 class PrintJobCanceler {
388 public:
389 explicit PrintJobCanceler(
390 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
391 : job_ptr_(job_ptr) {
393 ~PrintJobCanceler() {
394 if (job_ptr_ && job_ptr_->get()) {
395 (*job_ptr_)->Cancel();
396 job_ptr_->Release();
400 void reset() { job_ptr_ = NULL; }
402 private:
403 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
405 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
408 void PrintJobDone(bool success) {
409 // If there is no delegate, then there is nothing pending to process.
410 if (!delegate_)
411 return;
412 RestoreDC(printer_dc_.Get(), saved_dc_);
413 EndDoc(printer_dc_.Get());
414 if (success) {
415 delegate_->OnJobSpoolSucceeded(job_id_);
416 } else {
417 delegate_->OnJobSpoolFailed();
419 delegate_ = NULL;
422 void RenderPDFPages() {
423 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
424 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
425 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
426 gfx::Rect render_area(0, 0, dc_width, dc_height);
427 g_service_process->io_thread()->message_loop_proxy()->PostTask(
428 FROM_HERE,
429 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox,
430 this,
431 print_data_file_path_,
432 render_area,
433 printer_dpi,
434 base::MessageLoopProxy::current()));
437 // Called on the service process IO thread.
438 void RenderPDFPagesInSandbox(const base::FilePath& pdf_path,
439 const gfx::Rect& render_area,
440 int render_dpi,
441 const scoped_refptr<base::MessageLoopProxy>&
442 client_message_loop_proxy) {
443 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
444 BelongsToCurrentThread());
445 scoped_ptr<ServiceUtilityProcessHost> utility_host(
446 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
447 // TODO(gene): For now we disabling autorotation for CloudPrinting.
448 // Landscape/Portrait setting is passed in the print ticket and
449 // server is generating portrait PDF always.
450 // We should enable autorotation once server will be able to generate
451 // PDF that matches paper size and orientation.
452 if (utility_host->StartRenderPDFPagesToMetafile(
453 pdf_path,
454 printing::PdfRenderSettings(render_area, render_dpi, false))) {
455 // The object will self-destruct when the child process dies.
456 utility_host.release();
457 } else {
458 client_message_loop_proxy->PostTask(
459 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
463 bool PrintXPSDocument(const std::string& printer_name,
464 const std::string& job_title,
465 const base::FilePath& print_data_file_path,
466 const std::string& print_ticket) {
467 if (!printing::XPSPrintModule::Init())
468 return false;
470 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
471 if (!job_progress_event_.Get())
472 return false;
474 PrintJobCanceler job_canceler(&xps_print_job_);
475 base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
476 base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
477 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
478 base::UTF8ToWide(printer_name).c_str(),
479 base::UTF8ToWide(job_title).c_str(),
480 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
481 xps_print_job_.Receive(), doc_stream.Receive(),
482 print_ticket_stream.Receive())))
483 return false;
485 ULONG print_bytes_written = 0;
486 if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
487 print_ticket.length(),
488 &print_bytes_written)))
489 return false;
490 DCHECK_EQ(print_ticket.length(), print_bytes_written);
491 if (FAILED(print_ticket_stream->Close()))
492 return false;
494 std::string document_data;
495 base::ReadFileToString(print_data_file_path, &document_data);
496 ULONG doc_bytes_written = 0;
497 if (FAILED(doc_stream->Write(document_data.c_str(),
498 document_data.length(),
499 &doc_bytes_written)))
500 return false;
501 DCHECK_EQ(document_data.length(), doc_bytes_written);
502 if (FAILED(doc_stream->Close()))
503 return false;
505 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
506 job_canceler.reset();
507 return true;
510 PlatformJobId job_id_;
511 PrintSystem::JobSpooler::Delegate* delegate_;
512 int saved_dc_;
513 base::win::ScopedCreateDC printer_dc_;
514 base::FilePath print_data_file_path_;
515 base::win::ScopedHandle job_progress_event_;
516 base::win::ObjectWatcher job_progress_watcher_;
517 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
519 DISALLOW_COPY_AND_ASSIGN(Core);
521 scoped_refptr<Core> core_;
523 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
526 // A helper class to handle the response from the utility process to the
527 // request to fetch printer capabilities and defaults.
528 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
529 public:
530 PrinterCapsHandler(
531 const std::string& printer_name,
532 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
533 : printer_name_(printer_name), callback_(callback) {
536 // ServiceUtilityProcessHost::Client implementation.
537 virtual void OnChildDied() override {
538 OnGetPrinterCapsAndDefaults(false, printer_name_,
539 printing::PrinterCapsAndDefaults());
542 virtual void OnGetPrinterCapsAndDefaults(
543 bool succeeded,
544 const std::string& printer_name,
545 const printing::PrinterCapsAndDefaults& caps_and_defaults) override {
546 callback_.Run(succeeded, printer_name, caps_and_defaults);
547 callback_.Reset();
548 Release();
551 virtual void OnGetPrinterSemanticCapsAndDefaults(
552 bool succeeded,
553 const std::string& printer_name,
554 const printing::PrinterSemanticCapsAndDefaults& semantic_info) override {
555 printing::PrinterCapsAndDefaults printer_info;
556 if (succeeded) {
557 printer_info.caps_mime_type = kContentTypeJSON;
558 scoped_ptr<base::DictionaryValue> description(
559 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
560 if (description) {
561 base::JSONWriter::WriteWithOptions(
562 description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
563 &printer_info.printer_capabilities);
566 callback_.Run(succeeded, printer_name, printer_info);
567 callback_.Reset();
568 Release();
571 void StartGetPrinterCapsAndDefaults() {
572 g_service_process->io_thread()->message_loop_proxy()->PostTask(
573 FROM_HERE,
574 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
575 base::MessageLoopProxy::current()));
578 void StartGetPrinterSemanticCapsAndDefaults() {
579 g_service_process->io_thread()->message_loop_proxy()->PostTask(
580 FROM_HERE,
581 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
582 this, base::MessageLoopProxy::current()));
585 private:
586 void GetPrinterCapsAndDefaultsImpl(
587 const scoped_refptr<base::MessageLoopProxy>&
588 client_message_loop_proxy) {
589 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
590 BelongsToCurrentThread());
591 scoped_ptr<ServiceUtilityProcessHost> utility_host(
592 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
593 if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
594 // The object will self-destruct when the child process dies.
595 utility_host.release();
596 } else {
597 client_message_loop_proxy->PostTask(
598 FROM_HERE,
599 base::Bind(&PrinterCapsHandler::OnChildDied, this));
603 void GetPrinterSemanticCapsAndDefaultsImpl(
604 const scoped_refptr<base::MessageLoopProxy>&
605 client_message_loop_proxy) {
606 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
607 BelongsToCurrentThread());
608 scoped_ptr<ServiceUtilityProcessHost> utility_host(
609 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
610 if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
611 // The object will self-destruct when the child process dies.
612 utility_host.release();
613 } else {
614 client_message_loop_proxy->PostTask(
615 FROM_HERE,
616 base::Bind(&PrinterCapsHandler::OnChildDied, this));
620 std::string printer_name_;
621 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
624 class PrintSystemWin : public PrintSystem {
625 public:
626 PrintSystemWin();
628 // PrintSystem implementation.
629 virtual PrintSystemResult Init() override;
630 virtual PrintSystem::PrintSystemResult EnumeratePrinters(
631 printing::PrinterList* printer_list) override;
632 virtual void GetPrinterCapsAndDefaults(
633 const std::string& printer_name,
634 const PrinterCapsAndDefaultsCallback& callback) override;
635 virtual bool IsValidPrinter(const std::string& printer_name) override;
636 virtual bool ValidatePrintTicket(
637 const std::string& printer_name,
638 const std::string& print_ticket_data,
639 const std::string& print_ticket_data_mime_type) override;
640 virtual bool GetJobDetails(const std::string& printer_name,
641 PlatformJobId job_id,
642 PrintJobDetails *job_details) override;
643 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() override;
644 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
645 const std::string& printer_name) override;
646 virtual PrintSystem::JobSpooler* CreateJobSpooler() override;
647 virtual bool UseCddAndCjt() override;
648 virtual std::string GetSupportedMimeTypes() override;
650 private:
651 std::string PrintSystemWin::GetPrinterDriverInfo(
652 const std::string& printer_name) const;
654 scoped_refptr<printing::PrintBackend> print_backend_;
655 bool use_cdd_;
656 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
659 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
660 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
663 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
664 use_cdd_ = !base::CommandLine::ForCurrentProcess()->HasSwitch(
665 switches::kEnableCloudPrintXps);
667 if (!use_cdd_)
668 use_cdd_ = !printing::XPSModule::Init();
670 if (!use_cdd_) {
671 HPTPROVIDER provider = NULL;
672 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
673 if (provider)
674 printing::XPSModule::CloseProvider(provider);
675 // Use cdd if error is different from expected.
676 use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
679 return PrintSystemResult(true, std::string());
682 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
683 printing::PrinterList* printer_list) {
684 bool ret = print_backend_->EnumeratePrinters(printer_list);
685 return PrintSystemResult(ret, std::string());
688 void PrintSystemWin::GetPrinterCapsAndDefaults(
689 const std::string& printer_name,
690 const PrinterCapsAndDefaultsCallback& callback) {
691 // Launch as child process to retrieve the capabilities and defaults because
692 // this involves invoking a printer driver DLL and crashes have been known to
693 // occur.
694 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
695 handler->AddRef();
696 if (use_cdd_)
697 handler->StartGetPrinterSemanticCapsAndDefaults();
698 else
699 handler->StartGetPrinterCapsAndDefaults();
702 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
703 return print_backend_->IsValidPrinter(printer_name);
706 bool PrintSystemWin::ValidatePrintTicket(
707 const std::string& printer_name,
708 const std::string& print_ticket_data,
709 const std::string& print_ticket_data_mime_type) {
710 crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
712 if (use_cdd_) {
713 return print_ticket_data_mime_type == kContentTypeJSON &&
714 IsValidCjt(print_ticket_data);
716 DCHECK(print_ticket_data_mime_type == kContentTypeXML);
718 printing::ScopedXPSInitializer xps_initializer;
719 if (!xps_initializer.initialized()) {
720 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
721 return false;
723 bool ret = false;
724 HPTPROVIDER provider = NULL;
725 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
726 &provider);
727 if (provider) {
728 base::win::ScopedComPtr<IStream> print_ticket_stream;
729 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
730 ULONG bytes_written = 0;
731 print_ticket_stream->Write(print_ticket_data.c_str(),
732 print_ticket_data.length(),
733 &bytes_written);
734 DCHECK(bytes_written == print_ticket_data.length());
735 LARGE_INTEGER pos = {0};
736 ULARGE_INTEGER new_pos = {0};
737 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
738 base::win::ScopedBstr error;
739 base::win::ScopedComPtr<IStream> result_ticket_stream;
740 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
741 ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
742 provider,
743 print_ticket_stream.get(),
744 NULL,
745 kPTJobScope,
746 result_ticket_stream.get(),
747 error.Receive()));
748 printing::XPSModule::CloseProvider(provider);
750 return ret;
753 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
754 PlatformJobId job_id,
755 PrintJobDetails *job_details) {
756 crash_keys::ScopedPrinterInfo crash_key(
757 print_backend_->GetPrinterDriverInfo(printer_name));
758 DCHECK(job_details);
759 printing::ScopedPrinterHandle printer_handle;
760 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
761 printer_handle.OpenPrinter(printer_name_wide.c_str());
762 DCHECK(printer_handle.IsValid());
763 bool ret = false;
764 if (printer_handle.IsValid()) {
765 DWORD bytes_needed = 0;
766 GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
767 DWORD last_error = GetLastError();
768 if (ERROR_INVALID_PARAMETER != last_error) {
769 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
770 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
771 scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
772 if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
773 bytes_needed, &bytes_needed)) {
774 JOB_INFO_1 *job_info =
775 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
776 if (job_info->pStatus) {
777 base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
778 &job_details->status_message);
780 job_details->platform_status_flags = job_info->Status;
781 if ((job_info->Status & JOB_STATUS_COMPLETE) ||
782 (job_info->Status & JOB_STATUS_PRINTED)) {
783 job_details->status = PRINT_JOB_STATUS_COMPLETED;
784 } else if (job_info->Status & JOB_STATUS_ERROR) {
785 job_details->status = PRINT_JOB_STATUS_ERROR;
786 } else {
787 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
789 job_details->total_pages = job_info->TotalPages;
790 job_details->pages_printed = job_info->PagesPrinted;
791 ret = true;
795 return ret;
798 PrintSystem::PrintServerWatcher*
799 PrintSystemWin::CreatePrintServerWatcher() {
800 return new PrintServerWatcherWin();
803 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
804 const std::string& printer_name) {
805 DCHECK(!printer_name.empty());
806 return new PrinterWatcherWin(printer_name);
809 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
810 return new JobSpoolerWin();
813 bool PrintSystemWin::UseCddAndCjt() {
814 return use_cdd_;
817 std::string PrintSystemWin::GetSupportedMimeTypes() {
818 std::string result;
819 if (!use_cdd_) {
820 result = kContentTypeXPS;
821 result += ",";
823 result += kContentTypePDF;
824 return result;
827 std::string PrintSystemWin::GetPrinterDriverInfo(
828 const std::string& printer_name) const {
829 return print_backend_->GetPrinterDriverInfo(printer_name);
832 } // namespace
834 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
835 const base::DictionaryValue* print_system_settings) {
836 return new PrintSystemWin;
839 } // namespace cloud_print