Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / service / cloud_print / print_system_win.cc
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.
4
5 #include "chrome/service/cloud_print/print_system.h"
6
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"
30
31 namespace cloud_print {
32
33 namespace {
34
35 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
36  public:
37   PrintSystemWatcherWin()
38       : delegate_(NULL),
39         did_signal_(false) {
40   }
41   ~PrintSystemWatcherWin() {
42     Stop();
43   }
44
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;
52   };
53
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_);
59
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());
68     }
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);
75       }
76     }
77     if (!ret) {
78       Stop();
79     }
80     return ret;
81   }
82
83   bool Stop() {
84     watcher_.StopWatching();
85     printer_.Close();
86     printer_change_.Close();
87     return true;
88   }
89
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"));
96
97     crash_keys::ScopedPrinterInfo crash_key(printer_info_);
98     DWORD change = 0;
99     FindNextPrinterChangeNotification(object, &change, NULL, NULL);
100
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();
112       }
113       if (change & PRINTER_CHANGE_JOB) {
114         delegate_->OnJobChanged();
115       }
116     }
117     watcher_.StartWatching(printer_change_.Get(), this);
118   }
119
120   bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
121     DCHECK(printer_info);
122     return InitBasicPrinterInfo(printer_.Get(), printer_info);
123   }
124
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.
133 };
134
135 class PrintServerWatcherWin
136   : public PrintSystem::PrintServerWatcher,
137     public PrintSystemWatcherWin::Delegate {
138  public:
139   PrintServerWatcherWin() : delegate_(NULL) {}
140
141   // PrintSystem::PrintServerWatcher implementation.
142   virtual bool StartWatching(
143       PrintSystem::PrintServerWatcher::Delegate* delegate) override{
144     delegate_ = delegate;
145     return watcher_.Start(std::string(), this);
146   }
147
148   virtual bool StopWatching() override{
149     bool ret = watcher_.Stop();
150     delegate_ = NULL;
151     return ret;
152   }
153
154   // PrintSystemWatcherWin::Delegate implementation.
155   virtual void OnPrinterAdded() override {
156     delegate_->OnPrinterAdded();
157   }
158   virtual void OnPrinterDeleted() override {}
159   virtual void OnPrinterChanged() override {}
160   virtual void OnJobChanged() override {}
161
162  protected:
163   virtual ~PrintServerWatcherWin() {}
164
165  private:
166   PrintSystem::PrintServerWatcher::Delegate* delegate_;
167   PrintSystemWatcherWin watcher_;
168
169   DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
170 };
171
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) {
179   }
180
181   // PrintSystem::PrinterWatcher implementation.
182   virtual bool StartWatching(
183       PrintSystem::PrinterWatcher::Delegate* delegate) override {
184     delegate_ = delegate;
185     return watcher_.Start(printer_name_, this);
186   }
187
188   virtual bool StopWatching() override {
189     bool ret = watcher_.Stop();
190     delegate_ = NULL;
191     return ret;
192   }
193
194   virtual bool GetCurrentPrinterInfo(
195       printing::PrinterBasicInfo* printer_info) override {
196     return watcher_.GetCurrentPrinterInfo(printer_info);
197   }
198
199   // PrintSystemWatcherWin::Delegate implementation.
200   virtual void OnPrinterAdded() override {
201     NOTREACHED();
202   }
203   virtual void OnPrinterDeleted() override {
204     delegate_->OnPrinterDeleted();
205   }
206   virtual void OnPrinterChanged() override {
207     delegate_->OnPrinterChanged();
208   }
209   virtual void OnJobChanged() override {
210     delegate_->OnJobChanged();
211   }
212
213  protected:
214   virtual ~PrinterWatcherWin() {}
215
216  private:
217   std::string printer_name_;
218   PrintSystem::PrinterWatcher::Delegate* delegate_;
219   PrintSystemWatcherWin watcher_;
220
221   DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
222 };
223
224 class JobSpoolerWin : public PrintSystem::JobSpooler {
225  public:
226   JobSpoolerWin() : core_(new Core) {}
227
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);
245   }
246
247  protected:
248   virtual ~JobSpoolerWin() {}
249
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) {}
257
258     ~Core() {}
259
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;
271       }
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);
281         }
282
283         if (!dev_mode) {
284           NOTREACHED();
285           return false;
286         }
287
288         HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
289                           dev_mode.get());
290         if (!dc) {
291           NOTREACHED();
292           return false;
293         }
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;
302
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;
320       }
321       return true;
322     }
323
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);
337     }
338
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());
347     }
348
349     // ServiceUtilityProcessHost::Client implementation.
350     virtual void OnRenderPDFPagesToMetafileDone(bool success) override {
351       PrintJobDone(success);
352     }
353
354     virtual void OnChildDied() override { PrintJobDone(false); }
355
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"));
362
363       DCHECK(xps_print_job_);
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);
382       }
383     }
384
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) {
392       }
393       ~PrintJobCanceler() {
394         if (job_ptr_ && *job_ptr_) {
395           (*job_ptr_)->Cancel();
396           job_ptr_->Release();
397         }
398       }
399
400       void reset() { job_ptr_ = NULL; }
401
402      private:
403       base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
404
405       DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
406     };
407
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();
418       }
419       delegate_ = NULL;
420     }
421
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()));
435     }
436
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));
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));
460       }
461     }
462
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;
469
470       job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
471       if (!job_progress_event_.Get())
472         return false;
473
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;
484
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;
493
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;
504
505       job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
506       job_canceler.reset();
507       return true;
508     }
509
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_;
518
519     DISALLOW_COPY_AND_ASSIGN(Core);
520   };
521   scoped_refptr<Core> core_;
522
523   DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
524 };
525
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) {
534   }
535
536   // ServiceUtilityProcessHost::Client implementation.
537   virtual void OnChildDied() override {
538     OnGetPrinterCapsAndDefaults(false, printer_name_,
539                                 printing::PrinterCapsAndDefaults());
540   }
541
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();
549   }
550
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);
564       }
565     }
566     callback_.Run(succeeded, printer_name, printer_info);
567     callback_.Reset();
568     Release();
569   }
570
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()));
576   }
577
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()));
583   }
584
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));
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));
600     }
601   }
602
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));
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));
617     }
618   }
619
620   std::string printer_name_;
621   PrintSystem::PrinterCapsAndDefaultsCallback callback_;
622 };
623
624 class PrintSystemWin : public PrintSystem {
625  public:
626   PrintSystemWin();
627
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;
649
650  private:
651   std::string PrintSystemWin::GetPrinterDriverInfo(
652       const std::string& printer_name) const;
653
654   scoped_refptr<printing::PrintBackend> print_backend_;
655   bool use_cdd_;
656   DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
657 };
658
659 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
660   print_backend_ = printing::PrintBackend::CreateInstance(NULL);
661 }
662
663 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
664   use_cdd_ = !CommandLine::ForCurrentProcess()->HasSwitch(
665       switches::kEnableCloudPrintXps);
666
667   if (!use_cdd_)
668     use_cdd_ = !printing::XPSModule::Init();
669
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));
677   }
678
679   return PrintSystemResult(true, std::string());
680 }
681
682 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
683     printing::PrinterList* printer_list) {
684   bool ret = print_backend_->EnumeratePrinters(printer_list);
685   return PrintSystemResult(ret, std::string());
686 }
687
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();
700 }
701
702 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
703   return print_backend_->IsValidPrinter(printer_name);
704 }
705
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));
711
712   if (use_cdd_) {
713     return print_ticket_data_mime_type == kContentTypeJSON &&
714            IsValidCjt(print_ticket_data);
715   }
716   DCHECK(print_ticket_data_mime_type == kContentTypeXML);
717
718   printing::ScopedXPSInitializer xps_initializer;
719   if (!xps_initializer.initialized()) {
720     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
721     return false;
722   }
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);
749   }
750   return ret;
751 }
752
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);
779         }
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;
788         }
789         job_details->total_pages = job_info->TotalPages;
790         job_details->pages_printed = job_info->PagesPrinted;
791         ret = true;
792       }
793     }
794   }
795   return ret;
796 }
797
798 PrintSystem::PrintServerWatcher*
799 PrintSystemWin::CreatePrintServerWatcher() {
800   return new PrintServerWatcherWin();
801 }
802
803 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
804     const std::string& printer_name) {
805   DCHECK(!printer_name.empty());
806   return new PrinterWatcherWin(printer_name);
807 }
808
809 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
810   return new JobSpoolerWin();
811 }
812
813 bool PrintSystemWin::UseCddAndCjt() {
814   return use_cdd_;
815 }
816
817 std::string PrintSystemWin::GetSupportedMimeTypes() {
818   std::string result;
819   if (!use_cdd_) {
820     result = kContentTypeXPS;
821     result += ",";
822   }
823   result += kContentTypePDF;
824   return result;
825 }
826
827 std::string PrintSystemWin::GetPrinterDriverInfo(
828     const std::string& printer_name) const {
829   return print_backend_->GetPrinterDriverInfo(printer_name);
830 }
831
832 }  // namespace
833
834 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
835     const base::DictionaryValue* print_system_settings) {
836   return new PrintSystemWin;
837 }
838
839 }  // namespace cloud_print