Revert of Create a new AccountTrackerService (patchset #8 of https://codereview.chrom...
[chromium-blink-merge.git] / chrome / service / cloud_print / print_system_win.cc
bloba0939f564dd0e99c1558eccafe66c4214f48412b
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 {
30 namespace {
32 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
33 public:
34 PrintSystemWatcherWin()
35 : delegate_(NULL),
36 did_signal_(false) {
38 ~PrintSystemWatcherWin() {
39 Stop();
42 class Delegate {
43 public:
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_);
57 delegate_ = delegate;
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());
66 bool ret = false;
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);
74 if (!ret) {
75 Stop();
77 return ret;
80 bool Stop() {
81 watcher_.StopWatching();
82 printer_.Close();
83 printer_change_.Close();
84 return true;
87 // base::ObjectWatcher::Delegate method
88 virtual void OnObjectSignaled(HANDLE object) {
89 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
90 DWORD change = 0;
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.
97 // Ignore these.
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);
117 private:
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 {
130 public:
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();
142 delegate_ = NULL;
143 return ret;
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 {}
154 protected:
155 virtual ~PrintServerWatcherWin() {}
157 private:
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 {
167 public:
168 explicit PrinterWatcherWin(const std::string& printer_name)
169 : printer_name_(printer_name),
170 delegate_(NULL) {
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();
182 delegate_ = NULL;
183 return ret;
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 {
193 NOTREACHED();
195 virtual void OnPrinterDeleted() OVERRIDE {
196 delegate_->OnPrinterDeleted();
198 virtual void OnPrinterChanged() OVERRIDE {
199 delegate_->OnPrinterChanged();
201 virtual void OnJobChanged() OVERRIDE {
202 delegate_->OnJobChanged();
205 protected:
206 virtual ~PrinterWatcherWin() {}
208 private:
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 {
217 public:
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);
239 protected:
240 virtual ~JobSpoolerWin() {}
242 private:
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 {
247 public:
248 Core()
249 : last_page_printed_(-1),
250 job_id_(-1),
251 delegate_(NULL),
252 saved_dc_(0) {
255 ~Core() {}
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) {
264 if (delegate_) {
265 // We are already in the process of printing.
266 NOTREACHED();
267 return false;
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);
276 } else {
277 DCHECK(print_ticket_mime_type == kContentTypeXML);
278 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
281 if (!dev_mode) {
282 NOTREACHED();
283 return false;
286 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
287 dev_mode.get());
288 if (!dc) {
289 NOTREACHED();
290 return false;
292 DOCINFO di = {0};
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);
298 if (job_id_ <= 0)
299 return false;
301 printer_dc_.Set(dc);
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,
309 job_title,
310 print_data_file_path,
311 print_ticket);
312 if (ret)
313 delegate_ = delegate;
314 return ret;
315 } else {
316 NOTREACHED();
317 return false;
319 return true;
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);
330 XFORM xform = {0};
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;
347 if (done_printing)
348 PrintJobDone();
349 else
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());
358 if (!delegate_)
359 return;
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);
371 } else {
372 job_progress_watcher_.StopWatching();
373 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
377 virtual void OnRenderPDFPagesToMetafileFailed() OVERRIDE {
378 PrintJobDone();
381 virtual void OnChildDied() OVERRIDE {
382 PrintJobDone();
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_) {
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() {
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 (-1 == last_page_printed_) {
415 delegate_->OnJobSpoolFailed();
416 } else {
417 delegate_->OnJobSpoolSucceeded(job_id_);
419 delegate_ = NULL;
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(
435 FROM_HERE,
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(
457 pdf_path,
458 printing::PdfRenderSettings(render_area, render_dpi, false),
459 page_ranges)) {
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())
470 return false;
472 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
473 if (!job_progress_event_.Get())
474 return false;
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())))
485 return false;
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)))
491 return false;
492 DCHECK_EQ(print_ticket.length(), print_bytes_written);
493 if (FAILED(print_ticket_stream->Close()))
494 return false;
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)))
502 return false;
503 DCHECK_EQ(document_data.length(), doc_bytes_written);
504 if (FAILED(doc_stream->Close()))
505 return false;
507 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
508 job_canceler.reset();
509 return true;
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_;
522 int saved_dc_;
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 {
539 public:
540 PrinterCapsHandler(
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(
553 bool succeeded,
554 const std::string& printer_name,
555 const printing::PrinterCapsAndDefaults& caps_and_defaults) OVERRIDE {
556 callback_.Run(succeeded, printer_name, caps_and_defaults);
557 callback_.Reset();
558 Release();
561 virtual void OnGetPrinterSemanticCapsAndDefaults(
562 bool succeeded,
563 const std::string& printer_name,
564 const printing::PrinterSemanticCapsAndDefaults& semantic_info) OVERRIDE {
565 printing::PrinterCapsAndDefaults printer_info;
566 if (succeeded) {
567 printer_info.caps_mime_type = kContentTypeJSON;
568 scoped_ptr<base::DictionaryValue> description(
569 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
570 if (description) {
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);
577 callback_.Reset();
578 Release();
581 void StartGetPrinterCapsAndDefaults() {
582 g_service_process->io_thread()->message_loop_proxy()->PostTask(
583 FROM_HERE,
584 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
585 base::MessageLoopProxy::current()));
588 void StartGetPrinterSemanticCapsAndDefaults() {
589 g_service_process->io_thread()->message_loop_proxy()->PostTask(
590 FROM_HERE,
591 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
592 this, base::MessageLoopProxy::current()));
595 private:
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();
606 } else {
607 client_message_loop_proxy->PostTask(
608 FROM_HERE,
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();
623 } else {
624 client_message_loop_proxy->PostTask(
625 FROM_HERE,
626 base::Bind(&PrinterCapsHandler::OnChildDied, this));
630 std::string printer_name_;
631 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
634 class PrintSystemWin : public PrintSystem {
635 public:
636 PrintSystemWin();
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;
660 private:
661 std::string PrintSystemWin::GetPrinterDriverInfo(
662 const std::string& printer_name) const;
664 scoped_refptr<printing::PrintBackend> print_backend_;
665 bool use_cdd_;
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);
677 if (!use_cdd_)
678 use_cdd_ = !printing::XPSModule::Init();
680 if (!use_cdd_) {
681 HPTPROVIDER provider = NULL;
682 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
683 if (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
703 // occur.
704 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
705 handler->AddRef();
706 if (use_cdd_)
707 handler->StartGetPrinterSemanticCapsAndDefaults();
708 else
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));
722 if (use_cdd_) {
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)
731 return false;
733 bool ret = false;
734 HPTPROVIDER provider = NULL;
735 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
736 &provider);
737 if (provider) {
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(),
743 &bytes_written);
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(
752 provider,
753 print_ticket_stream.get(),
754 NULL,
755 kPTJobScope,
756 result_ticket_stream.get(),
757 error.Receive()));
758 printing::XPSModule::CloseProvider(provider);
760 return ret;
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));
768 DCHECK(job_details);
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());
773 bool ret = false;
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,
783 &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;
796 } else {
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;
801 ret = true;
805 return ret;
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() {
824 return use_cdd_;
827 std::string PrintSystemWin::GetSupportedMimeTypes() {
828 std::string result;
829 if (!use_cdd_) {
830 result = kContentTypeXPS;
831 result += ",";
833 result += kContentTypePDF;
834 return result;
837 std::string PrintSystemWin::GetPrinterDriverInfo(
838 const std::string& printer_name) const {
839 return print_backend_->GetPrinterDriverInfo(printer_name);
842 } // namespace
844 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
845 const base::DictionaryValue* print_system_settings) {
846 return new PrintSystemWin;
849 } // namespace cloud_print