Home | History | Annotate | Download | only in cloud_print
      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/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 "grit/generated_resources.h"
     24 #include "printing/backend/win_helper.h"
     25 #include "printing/emf_win.h"
     26 #include "printing/page_range.h"
     27 #include "printing/printing_utils.h"
     28 #include "ui/base/l10n/l10n_util.h"
     29 
     30 namespace cloud_print {
     31 
     32 namespace {
     33 
     34 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
     35  public:
     36   PrintSystemWatcherWin()
     37       : delegate_(NULL),
     38         did_signal_(false) {
     39   }
     40   ~PrintSystemWatcherWin() {
     41     Stop();
     42   }
     43 
     44   class Delegate {
     45    public:
     46     virtual ~Delegate() {}
     47     virtual void OnPrinterAdded() = 0;
     48     virtual void OnPrinterDeleted() = 0;
     49     virtual void OnPrinterChanged() = 0;
     50     virtual void OnJobChanged() = 0;
     51   };
     52 
     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_);
     58 
     59     delegate_ = delegate;
     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());
     67     }
     68     bool ret = false;
     69     if (printer_.OpenPrinter(printer_name_to_use)) {
     70       printer_change_.Set(FindFirstPrinterChangeNotification(
     71           printer_, PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
     72       if (printer_change_.IsValid()) {
     73         ret = watcher_.StartWatching(printer_change_, this);
     74       }
     75     }
     76     if (!ret) {
     77       Stop();
     78     }
     79     return ret;
     80   }
     81 
     82   bool Stop() {
     83     watcher_.StopWatching();
     84     printer_.Close();
     85     printer_change_.Close();
     86     return true;
     87   }
     88 
     89   // base::ObjectWatcher::Delegate method
     90   virtual void OnObjectSignaled(HANDLE object) {
     91     crash_keys::ScopedPrinterInfo crash_key(printer_info_);
     92     DWORD change = 0;
     93     FindNextPrinterChangeNotification(object, &change, NULL, NULL);
     94 
     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.
     99       // Ignore these.
    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();
    106       }
    107       if (change & PRINTER_CHANGE_JOB) {
    108         delegate_->OnJobChanged();
    109       }
    110     }
    111     watcher_.StartWatching(printer_change_, this);
    112   }
    113 
    114   bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
    115     DCHECK(printer_info);
    116     return InitBasicPrinterInfo(printer_, printer_info);
    117   }
    118 
    119  private:
    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.
    127 };
    128 
    129 class PrintServerWatcherWin
    130   : public PrintSystem::PrintServerWatcher,
    131     public PrintSystemWatcherWin::Delegate {
    132  public:
    133   PrintServerWatcherWin() : delegate_(NULL) {}
    134 
    135   // PrintSystem::PrintServerWatcher implementation.
    136   virtual bool StartWatching(
    137       PrintSystem::PrintServerWatcher::Delegate* delegate) OVERRIDE{
    138     delegate_ = delegate;
    139     return watcher_.Start(std::string(), this);
    140   }
    141 
    142   virtual bool StopWatching() OVERRIDE{
    143     bool ret = watcher_.Stop();
    144     delegate_ = NULL;
    145     return ret;
    146   }
    147 
    148   // PrintSystemWatcherWin::Delegate implementation.
    149   virtual void OnPrinterAdded() OVERRIDE {
    150     delegate_->OnPrinterAdded();
    151   }
    152   virtual void OnPrinterDeleted() OVERRIDE {}
    153   virtual void OnPrinterChanged() OVERRIDE {}
    154   virtual void OnJobChanged() OVERRIDE {}
    155 
    156   protected:
    157   virtual ~PrintServerWatcherWin() {}
    158 
    159  private:
    160   PrintSystem::PrintServerWatcher::Delegate* delegate_;
    161   PrintSystemWatcherWin watcher_;
    162 
    163   DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
    164 };
    165 
    166 class PrinterWatcherWin
    167     : public PrintSystem::PrinterWatcher,
    168       public PrintSystemWatcherWin::Delegate {
    169  public:
    170   explicit PrinterWatcherWin(const std::string& printer_name)
    171       : printer_name_(printer_name),
    172         delegate_(NULL) {
    173   }
    174 
    175   // PrintSystem::PrinterWatcher implementation.
    176   virtual bool StartWatching(
    177       PrintSystem::PrinterWatcher::Delegate* delegate) OVERRIDE {
    178     delegate_ = delegate;
    179     return watcher_.Start(printer_name_, this);
    180   }
    181 
    182   virtual bool StopWatching() OVERRIDE {
    183     bool ret = watcher_.Stop();
    184     delegate_ = NULL;
    185     return ret;
    186   }
    187 
    188   virtual bool GetCurrentPrinterInfo(
    189       printing::PrinterBasicInfo* printer_info) OVERRIDE {
    190     return watcher_.GetCurrentPrinterInfo(printer_info);
    191   }
    192 
    193   // PrintSystemWatcherWin::Delegate implementation.
    194   virtual void OnPrinterAdded() OVERRIDE {
    195     NOTREACHED();
    196   }
    197   virtual void OnPrinterDeleted() OVERRIDE {
    198     delegate_->OnPrinterDeleted();
    199   }
    200   virtual void OnPrinterChanged() OVERRIDE {
    201     delegate_->OnPrinterChanged();
    202   }
    203   virtual void OnJobChanged() OVERRIDE {
    204     delegate_->OnJobChanged();
    205   }
    206 
    207   protected:
    208   virtual ~PrinterWatcherWin() {}
    209 
    210  private:
    211   std::string printer_name_;
    212   PrintSystem::PrinterWatcher::Delegate* delegate_;
    213   PrintSystemWatcherWin watcher_;
    214 
    215   DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
    216 };
    217 
    218 class JobSpoolerWin : public PrintSystem::JobSpooler {
    219  public:
    220   JobSpoolerWin() : core_(new Core) {}
    221 
    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);
    239   }
    240 
    241  protected:
    242   virtual ~JobSpoolerWin() {}
    243 
    244  private:
    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 {
    249    public:
    250     Core()
    251         : last_page_printed_(-1),
    252           job_id_(-1),
    253           delegate_(NULL),
    254           saved_dc_(0) {
    255     }
    256 
    257     ~Core() {}
    258 
    259     bool Spool(const std::string& print_ticket,
    260                const std::string& print_ticket_mime_type,
    261                const base::FilePath& print_data_file_path,
    262                const std::string& print_data_mime_type,
    263                const std::string& printer_name,
    264                const std::string& job_title,
    265                JobSpooler::Delegate* delegate) {
    266       if (delegate_) {
    267         // We are already in the process of printing.
    268         NOTREACHED();
    269         return false;
    270       }
    271       base::string16 printer_wide = base::UTF8ToWide(printer_name);
    272       last_page_printed_ = -1;
    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         RenderNextPDFPages();
    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, double 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.0 / scale_factor;
    336       SetWorldTransform(printer_dc_.Get(), &xform);
    337     }
    338 
    339     // ServiceUtilityProcessHost::Client implementation.
    340     virtual void OnRenderPDFPagesToMetafileSucceeded(
    341         const printing::Emf& metafile,
    342         int highest_rendered_page_number,
    343         double scale_factor) OVERRIDE {
    344       PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
    345       metafile.SafePlayback(printer_dc_.Get());
    346       bool done_printing = (highest_rendered_page_number !=
    347           last_page_printed_ + kPageCountPerBatch);
    348       last_page_printed_ = highest_rendered_page_number;
    349       if (done_printing)
    350         PrintJobDone();
    351       else
    352         RenderNextPDFPages();
    353     }
    354 
    355     // base::win::ObjectWatcher::Delegate implementation.
    356     virtual void OnObjectSignaled(HANDLE object) OVERRIDE {
    357       DCHECK(xps_print_job_);
    358       DCHECK(object == job_progress_event_.Get());
    359       ResetEvent(job_progress_event_.Get());
    360       if (!delegate_)
    361         return;
    362       XPS_JOB_STATUS job_status = {0};
    363       xps_print_job_->GetJobStatus(&job_status);
    364       if ((job_status.completion == XPS_JOB_CANCELLED) ||
    365           (job_status.completion == XPS_JOB_FAILED)) {
    366         delegate_->OnJobSpoolFailed();
    367       } else if (job_status.jobId ||
    368                   (job_status.completion == XPS_JOB_COMPLETED)) {
    369         // Note: In the case of the XPS document being printed to the
    370         // Microsoft XPS Document Writer, it seems to skip spooling the job
    371         // and goes to the completed state without ever assigning a job id.
    372         delegate_->OnJobSpoolSucceeded(job_status.jobId);
    373       } else {
    374         job_progress_watcher_.StopWatching();
    375         job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    376       }
    377     }
    378 
    379     virtual void OnRenderPDFPagesToMetafileFailed() OVERRIDE {
    380       PrintJobDone();
    381     }
    382 
    383     virtual void OnChildDied() OVERRIDE {
    384       PrintJobDone();
    385     }
    386 
    387    private:
    388     // Helper class to allow PrintXPSDocument() to have multiple exits.
    389     class PrintJobCanceler {
    390      public:
    391       explicit PrintJobCanceler(
    392           base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
    393           : job_ptr_(job_ptr) {
    394       }
    395       ~PrintJobCanceler() {
    396         if (job_ptr_ && *job_ptr_) {
    397           (*job_ptr_)->Cancel();
    398           job_ptr_->Release();
    399         }
    400       }
    401 
    402       void reset() { job_ptr_ = NULL; }
    403 
    404      private:
    405       base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
    406 
    407       DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
    408     };
    409 
    410     void PrintJobDone() {
    411       // If there is no delegate, then there is nothing pending to process.
    412       if (!delegate_)
    413         return;
    414       RestoreDC(printer_dc_.Get(), saved_dc_);
    415       EndDoc(printer_dc_.Get());
    416       if (-1 == last_page_printed_) {
    417         delegate_->OnJobSpoolFailed();
    418       } else {
    419         delegate_->OnJobSpoolSucceeded(job_id_);
    420       }
    421       delegate_ = NULL;
    422     }
    423 
    424     void RenderNextPDFPages() {
    425       printing::PageRange range;
    426       // Render 10 pages at a time.
    427       range.from = last_page_printed_ + 1;
    428       range.to = last_page_printed_ + kPageCountPerBatch;
    429       std::vector<printing::PageRange> page_ranges;
    430       page_ranges.push_back(range);
    431 
    432       int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
    433       int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
    434       int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
    435       gfx::Rect render_area(0, 0, dc_width, dc_height);
    436       g_service_process->io_thread()->message_loop_proxy()->PostTask(
    437           FROM_HERE,
    438           base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this,
    439                       print_data_file_path_, render_area, printer_dpi,
    440                       page_ranges, base::MessageLoopProxy::current()));
    441     }
    442 
    443     // Called on the service process IO thread.
    444     void RenderPDFPagesInSandbox(
    445         const base::FilePath& pdf_path, const gfx::Rect& render_area,
    446         int render_dpi, const std::vector<printing::PageRange>& page_ranges,
    447         const scoped_refptr<base::MessageLoopProxy>&
    448             client_message_loop_proxy) {
    449       DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    450           BelongsToCurrentThread());
    451       scoped_ptr<ServiceUtilityProcessHost> utility_host(
    452           new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    453       // TODO(gene): For now we disabling autorotation for CloudPrinting.
    454       // Landscape/Portrait setting is passed in the print ticket and
    455       // server is generating portrait PDF always.
    456       // We should enable autorotation once server will be able to generate
    457       // PDF that matches paper size and orientation.
    458       if (utility_host->StartRenderPDFPagesToMetafile(
    459               pdf_path,
    460               printing::PdfRenderSettings(render_area, render_dpi, false),
    461               page_ranges)) {
    462         // The object will self-destruct when the child process dies.
    463         utility_host.release();
    464       }
    465     }
    466 
    467     bool PrintXPSDocument(const std::string& printer_name,
    468                           const std::string& job_title,
    469                           const base::FilePath& print_data_file_path,
    470                           const std::string& print_ticket) {
    471       if (!printing::XPSPrintModule::Init())
    472         return false;
    473 
    474       job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
    475       if (!job_progress_event_.Get())
    476         return false;
    477 
    478       PrintJobCanceler job_canceler(&xps_print_job_);
    479       base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
    480       base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
    481       if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
    482               base::UTF8ToWide(printer_name).c_str(),
    483               base::UTF8ToWide(job_title).c_str(),
    484               NULL, job_progress_event_.Get(), NULL, NULL, NULL,
    485               xps_print_job_.Receive(), doc_stream.Receive(),
    486               print_ticket_stream.Receive())))
    487         return false;
    488 
    489       ULONG print_bytes_written = 0;
    490       if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
    491                                             print_ticket.length(),
    492                                             &print_bytes_written)))
    493         return false;
    494       DCHECK_EQ(print_ticket.length(), print_bytes_written);
    495       if (FAILED(print_ticket_stream->Close()))
    496         return false;
    497 
    498       std::string document_data;
    499       base::ReadFileToString(print_data_file_path, &document_data);
    500       ULONG doc_bytes_written = 0;
    501       if (FAILED(doc_stream->Write(document_data.c_str(),
    502                                     document_data.length(),
    503                                     &doc_bytes_written)))
    504         return false;
    505       DCHECK_EQ(document_data.length(), doc_bytes_written);
    506       if (FAILED(doc_stream->Close()))
    507         return false;
    508 
    509       job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    510       job_canceler.reset();
    511       return true;
    512     }
    513 
    514     // Some Cairo-generated PDFs from Chrome OS result in huge metafiles.
    515     // So the PageCountPerBatch is set to 1 for now.
    516     // TODO(sanjeevr): Figure out a smarter way to determine the pages per
    517     // batch. Filed a bug to track this at
    518     // http://code.google.com/p/chromium/issues/detail?id=57350.
    519     static const int kPageCountPerBatch = 1;
    520 
    521     int last_page_printed_;
    522     PlatformJobId job_id_;
    523     PrintSystem::JobSpooler::Delegate* delegate_;
    524     int saved_dc_;
    525     base::win::ScopedCreateDC printer_dc_;
    526     base::FilePath print_data_file_path_;
    527     base::win::ScopedHandle job_progress_event_;
    528     base::win::ObjectWatcher job_progress_watcher_;
    529     base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
    530 
    531     DISALLOW_COPY_AND_ASSIGN(Core);
    532   };
    533   scoped_refptr<Core> core_;
    534 
    535   DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
    536 };
    537 
    538 // A helper class to handle the response from the utility process to the
    539 // request to fetch printer capabilities and defaults.
    540 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
    541  public:
    542   PrinterCapsHandler(
    543       const std::string& printer_name,
    544       const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
    545           : printer_name_(printer_name), callback_(callback) {
    546   }
    547 
    548   // ServiceUtilityProcessHost::Client implementation.
    549   virtual void OnChildDied() OVERRIDE {
    550     OnGetPrinterCapsAndDefaults(false, printer_name_,
    551                                 printing::PrinterCapsAndDefaults());
    552   }
    553 
    554   virtual void OnGetPrinterCapsAndDefaults(
    555       bool succeeded,
    556       const std::string& printer_name,
    557       const printing::PrinterCapsAndDefaults& caps_and_defaults) OVERRIDE {
    558     callback_.Run(succeeded, printer_name, caps_and_defaults);
    559     callback_.Reset();
    560     Release();
    561   }
    562 
    563   virtual void OnGetPrinterSemanticCapsAndDefaults(
    564       bool succeeded,
    565       const std::string& printer_name,
    566       const printing::PrinterSemanticCapsAndDefaults& semantic_info) OVERRIDE {
    567     printing::PrinterCapsAndDefaults printer_info;
    568     if (succeeded) {
    569       printer_info.caps_mime_type = kContentTypeJSON;
    570       scoped_ptr<base::DictionaryValue> description(
    571           PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
    572       if (description) {
    573         base::JSONWriter::WriteWithOptions(
    574             description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
    575             &printer_info.printer_capabilities);
    576       }
    577     }
    578     callback_.Run(succeeded, printer_name, printer_info);
    579     callback_.Reset();
    580     Release();
    581   }
    582 
    583   void StartGetPrinterCapsAndDefaults() {
    584     g_service_process->io_thread()->message_loop_proxy()->PostTask(
    585         FROM_HERE,
    586         base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
    587                     base::MessageLoopProxy::current()));
    588   }
    589 
    590   void StartGetPrinterSemanticCapsAndDefaults() {
    591     g_service_process->io_thread()->message_loop_proxy()->PostTask(
    592         FROM_HERE,
    593         base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
    594                    this, base::MessageLoopProxy::current()));
    595   }
    596 
    597  private:
    598   void GetPrinterCapsAndDefaultsImpl(
    599       const scoped_refptr<base::MessageLoopProxy>&
    600           client_message_loop_proxy) {
    601     DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    602         BelongsToCurrentThread());
    603     scoped_ptr<ServiceUtilityProcessHost> utility_host(
    604         new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    605     if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
    606       // The object will self-destruct when the child process dies.
    607       utility_host.release();
    608     } else {
    609       client_message_loop_proxy->PostTask(
    610           FROM_HERE,
    611           base::Bind(&PrinterCapsHandler::OnChildDied, this));
    612     }
    613   }
    614 
    615   void GetPrinterSemanticCapsAndDefaultsImpl(
    616       const scoped_refptr<base::MessageLoopProxy>&
    617           client_message_loop_proxy) {
    618     DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    619         BelongsToCurrentThread());
    620     scoped_ptr<ServiceUtilityProcessHost> utility_host(
    621         new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    622     if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
    623       // The object will self-destruct when the child process dies.
    624       utility_host.release();
    625     } else {
    626       client_message_loop_proxy->PostTask(
    627           FROM_HERE,
    628           base::Bind(&PrinterCapsHandler::OnChildDied, this));
    629     }
    630   }
    631 
    632   std::string printer_name_;
    633   PrintSystem::PrinterCapsAndDefaultsCallback callback_;
    634 };
    635 
    636 class PrintSystemWin : public PrintSystem {
    637  public:
    638   PrintSystemWin();
    639 
    640   // PrintSystem implementation.
    641   virtual PrintSystemResult Init() OVERRIDE;
    642   virtual PrintSystem::PrintSystemResult EnumeratePrinters(
    643       printing::PrinterList* printer_list) OVERRIDE;
    644   virtual void GetPrinterCapsAndDefaults(
    645       const std::string& printer_name,
    646       const PrinterCapsAndDefaultsCallback& callback) OVERRIDE;
    647   virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
    648   virtual bool ValidatePrintTicket(
    649       const std::string& printer_name,
    650       const std::string& print_ticket_data,
    651       const std::string& print_ticket_data_mime_type) OVERRIDE;
    652   virtual bool GetJobDetails(const std::string& printer_name,
    653                              PlatformJobId job_id,
    654                              PrintJobDetails *job_details) OVERRIDE;
    655   virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() OVERRIDE;
    656   virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
    657       const std::string& printer_name) OVERRIDE;
    658   virtual PrintSystem::JobSpooler* CreateJobSpooler() OVERRIDE;
    659   virtual bool UseCddAndCjt() OVERRIDE;
    660   virtual std::string GetSupportedMimeTypes() OVERRIDE;
    661 
    662  private:
    663   std::string PrintSystemWin::GetPrinterDriverInfo(
    664       const std::string& printer_name) const;
    665 
    666   scoped_refptr<printing::PrintBackend> print_backend_;
    667   bool use_cdd_;
    668   DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
    669 };
    670 
    671 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
    672   print_backend_ = printing::PrintBackend::CreateInstance(NULL);
    673 }
    674 
    675 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
    676   use_cdd_ = !CommandLine::ForCurrentProcess()->HasSwitch(
    677       switches::kEnableCloudPrintXps);
    678 
    679   if (!use_cdd_)
    680     use_cdd_ = !printing::XPSModule::Init();
    681 
    682   if (!use_cdd_) {
    683     HPTPROVIDER provider = NULL;
    684     HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
    685     if (provider)
    686       printing::XPSModule::CloseProvider(provider);
    687     // Use cdd if error is different from expected.
    688     use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
    689   }
    690 
    691   return PrintSystemResult(true, std::string());
    692 }
    693 
    694 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
    695     printing::PrinterList* printer_list) {
    696   bool ret = print_backend_->EnumeratePrinters(printer_list);
    697   return PrintSystemResult(ret, std::string());
    698 }
    699 
    700 void PrintSystemWin::GetPrinterCapsAndDefaults(
    701     const std::string& printer_name,
    702     const PrinterCapsAndDefaultsCallback& callback) {
    703   // Launch as child process to retrieve the capabilities and defaults because
    704   // this involves invoking a printer driver DLL and crashes have been known to
    705   // occur.
    706   PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
    707   handler->AddRef();
    708   if (use_cdd_)
    709     handler->StartGetPrinterSemanticCapsAndDefaults();
    710   else
    711     handler->StartGetPrinterCapsAndDefaults();
    712 }
    713 
    714 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
    715   return print_backend_->IsValidPrinter(printer_name);
    716 }
    717 
    718 bool PrintSystemWin::ValidatePrintTicket(
    719     const std::string& printer_name,
    720     const std::string& print_ticket_data,
    721     const std::string& print_ticket_data_mime_type) {
    722   crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
    723 
    724   if (use_cdd_) {
    725     return print_ticket_data_mime_type == kContentTypeJSON &&
    726            IsValidCjt(print_ticket_data);
    727   }
    728   DCHECK(print_ticket_data_mime_type == kContentTypeXML);
    729 
    730   printing::ScopedXPSInitializer xps_initializer;
    731   if (!xps_initializer.initialized()) {
    732     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    733     return false;
    734   }
    735   bool ret = false;
    736   HPTPROVIDER provider = NULL;
    737   printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
    738                                     &provider);
    739   if (provider) {
    740     base::win::ScopedComPtr<IStream> print_ticket_stream;
    741     CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
    742     ULONG bytes_written = 0;
    743     print_ticket_stream->Write(print_ticket_data.c_str(),
    744                                print_ticket_data.length(),
    745                                &bytes_written);
    746     DCHECK(bytes_written == print_ticket_data.length());
    747     LARGE_INTEGER pos = {0};
    748     ULARGE_INTEGER new_pos = {0};
    749     print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
    750     base::win::ScopedBstr error;
    751     base::win::ScopedComPtr<IStream> result_ticket_stream;
    752     CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
    753     ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
    754         provider,
    755         print_ticket_stream.get(),
    756         NULL,
    757         kPTJobScope,
    758         result_ticket_stream.get(),
    759         error.Receive()));
    760     printing::XPSModule::CloseProvider(provider);
    761   }
    762   return ret;
    763 }
    764 
    765 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
    766                                    PlatformJobId job_id,
    767                                    PrintJobDetails *job_details) {
    768   crash_keys::ScopedPrinterInfo crash_key(
    769       print_backend_->GetPrinterDriverInfo(printer_name));
    770   DCHECK(job_details);
    771   printing::ScopedPrinterHandle printer_handle;
    772   std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
    773   printer_handle.OpenPrinter(printer_name_wide.c_str());
    774   DCHECK(printer_handle.IsValid());
    775   bool ret = false;
    776   if (printer_handle.IsValid()) {
    777     DWORD bytes_needed = 0;
    778     GetJob(printer_handle, job_id, 1, NULL, 0, &bytes_needed);
    779     DWORD last_error = GetLastError();
    780     if (ERROR_INVALID_PARAMETER != last_error) {
    781       // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
    782       DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
    783       scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
    784       if (GetJob(printer_handle, job_id, 1, job_info_buffer.get(), bytes_needed,
    785                 &bytes_needed)) {
    786         JOB_INFO_1 *job_info =
    787             reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
    788         if (job_info->pStatus) {
    789           base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
    790                            &job_details->status_message);
    791         }
    792         job_details->platform_status_flags = job_info->Status;
    793         if ((job_info->Status & JOB_STATUS_COMPLETE) ||
    794             (job_info->Status & JOB_STATUS_PRINTED)) {
    795           job_details->status = PRINT_JOB_STATUS_COMPLETED;
    796         } else if (job_info->Status & JOB_STATUS_ERROR) {
    797           job_details->status = PRINT_JOB_STATUS_ERROR;
    798         } else {
    799           job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
    800         }
    801         job_details->total_pages = job_info->TotalPages;
    802         job_details->pages_printed = job_info->PagesPrinted;
    803         ret = true;
    804       }
    805     }
    806   }
    807   return ret;
    808 }
    809 
    810 PrintSystem::PrintServerWatcher*
    811 PrintSystemWin::CreatePrintServerWatcher() {
    812   return new PrintServerWatcherWin();
    813 }
    814 
    815 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
    816     const std::string& printer_name) {
    817   DCHECK(!printer_name.empty());
    818   return new PrinterWatcherWin(printer_name);
    819 }
    820 
    821 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
    822   return new JobSpoolerWin();
    823 }
    824 
    825 bool PrintSystemWin::UseCddAndCjt() {
    826   return use_cdd_;
    827 }
    828 
    829 std::string PrintSystemWin::GetSupportedMimeTypes() {
    830   std::string result;
    831   if (!use_cdd_) {
    832     result = kContentTypeXPS;
    833     result += ",";
    834   }
    835   result += kContentTypePDF;
    836   return result;
    837 }
    838 
    839 std::string PrintSystemWin::GetPrinterDriverInfo(
    840     const std::string& printer_name) const {
    841   return print_backend_->GetPrinterDriverInfo(printer_name);
    842 }
    843 
    844 }  // namespace
    845 
    846 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
    847     const base::DictionaryValue* print_system_settings) {
    848   return new PrintSystemWin;
    849 }
    850 
    851 }  // namespace cloud_print
    852