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/files/file_util.h"
      9 #include "base/json/json_writer.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "base/win/object_watcher.h"
     13 #include "base/win/scoped_bstr.h"
     14 #include "base/win/scoped_comptr.h"
     15 #include "base/win/scoped_hdc.h"
     16 #include "chrome/common/chrome_switches.h"
     17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
     18 #include "chrome/common/cloud_print/cloud_print_constants.h"
     19 #include "chrome/common/crash_keys.h"
     20 #include "chrome/service/cloud_print/cdd_conversion_win.h"
     21 #include "chrome/service/service_process.h"
     22 #include "chrome/service/service_utility_process_host.h"
     23 #include "printing/backend/win_helper.h"
     24 #include "printing/emf_win.h"
     25 #include "printing/page_range.h"
     26 #include "printing/pdf_render_settings.h"
     27 #include "printing/printing_utils.h"
     28 #include "ui/gfx/geometry/rect.h"
     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_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
     72       if (printer_change_.IsValid()) {
     73         ret = watcher_.StartWatching(printer_change_.Get(), 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_.Get(), this);
    112   }
    113 
    114   bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
    115     DCHECK(printer_info);
    116     return InitBasicPrinterInfo(printer_.Get(), 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() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
    251 
    252     ~Core() {}
    253 
    254     bool Spool(const std::string& print_ticket,
    255                const std::string& print_ticket_mime_type,
    256                const base::FilePath& print_data_file_path,
    257                const std::string& print_data_mime_type,
    258                const std::string& printer_name,
    259                const std::string& job_title,
    260                JobSpooler::Delegate* delegate) {
    261       if (delegate_) {
    262         // We are already in the process of printing.
    263         NOTREACHED();
    264         return false;
    265       }
    266       base::string16 printer_wide = base::UTF8ToWide(printer_name);
    267       // We only support PDF and XPS documents for now.
    268       if (print_data_mime_type == kContentTypePDF) {
    269         scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
    270         if (print_ticket_mime_type == kContentTypeJSON) {
    271           dev_mode = CjtToDevMode(printer_wide, print_ticket);
    272         } else {
    273           DCHECK(print_ticket_mime_type == kContentTypeXML);
    274           dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
    275         }
    276 
    277         if (!dev_mode) {
    278           NOTREACHED();
    279           return false;
    280         }
    281 
    282         HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
    283                           dev_mode.get());
    284         if (!dc) {
    285           NOTREACHED();
    286           return false;
    287         }
    288         DOCINFO di = {0};
    289         di.cbSize = sizeof(DOCINFO);
    290         base::string16 doc_name = base::UTF8ToUTF16(job_title);
    291         DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
    292         di.lpszDocName = doc_name.c_str();
    293         job_id_ = StartDoc(dc, &di);
    294         if (job_id_ <= 0)
    295           return false;
    296 
    297         printer_dc_.Set(dc);
    298         saved_dc_ = SaveDC(printer_dc_.Get());
    299         print_data_file_path_ = print_data_file_path;
    300         delegate_ = delegate;
    301         RenderPDFPages();
    302       } else if (print_data_mime_type == kContentTypeXPS) {
    303         DCHECK(print_ticket_mime_type == kContentTypeXML);
    304         bool ret = PrintXPSDocument(printer_name,
    305                                     job_title,
    306                                     print_data_file_path,
    307                                     print_ticket);
    308         if (ret)
    309           delegate_ = delegate;
    310         return ret;
    311       } else {
    312         NOTREACHED();
    313         return false;
    314       }
    315       return true;
    316     }
    317 
    318     void PreparePageDCForPrinting(HDC, double scale_factor) {
    319       SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
    320       // Setup the matrix to translate and scale to the right place. Take in
    321       // account the scale factor.
    322       // Note that the printing output is relative to printable area of
    323       // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
    324       int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
    325       int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
    326       XFORM xform = {0};
    327       xform.eDx = static_cast<float>(-offset_x);
    328       xform.eDy = static_cast<float>(-offset_y);
    329       xform.eM11 = xform.eM22 = 1.0 / scale_factor;
    330       SetWorldTransform(printer_dc_.Get(), &xform);
    331     }
    332 
    333     // ServiceUtilityProcessHost::Client implementation.
    334     virtual void OnRenderPDFPagesToMetafilePageDone(
    335         double scale_factor,
    336         const printing::MetafilePlayer& emf) OVERRIDE {
    337       PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
    338       ::StartPage(printer_dc_.Get());
    339       emf.SafePlayback(printer_dc_.Get());
    340       ::EndPage(printer_dc_.Get());
    341     }
    342 
    343     // ServiceUtilityProcessHost::Client implementation.
    344     virtual void OnRenderPDFPagesToMetafileDone(bool success) OVERRIDE {
    345       PrintJobDone(success);
    346     }
    347 
    348     virtual void OnChildDied() OVERRIDE { PrintJobDone(false); }
    349 
    350     // base::win::ObjectWatcher::Delegate implementation.
    351     virtual void OnObjectSignaled(HANDLE object) OVERRIDE {
    352       DCHECK(xps_print_job_);
    353       DCHECK(object == job_progress_event_.Get());
    354       ResetEvent(job_progress_event_.Get());
    355       if (!delegate_)
    356         return;
    357       XPS_JOB_STATUS job_status = {0};
    358       xps_print_job_->GetJobStatus(&job_status);
    359       if ((job_status.completion == XPS_JOB_CANCELLED) ||
    360           (job_status.completion == XPS_JOB_FAILED)) {
    361         delegate_->OnJobSpoolFailed();
    362       } else if (job_status.jobId ||
    363                   (job_status.completion == XPS_JOB_COMPLETED)) {
    364         // Note: In the case of the XPS document being printed to the
    365         // Microsoft XPS Document Writer, it seems to skip spooling the job
    366         // and goes to the completed state without ever assigning a job id.
    367         delegate_->OnJobSpoolSucceeded(job_status.jobId);
    368       } else {
    369         job_progress_watcher_.StopWatching();
    370         job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    371       }
    372     }
    373 
    374    private:
    375     // Helper class to allow PrintXPSDocument() to have multiple exits.
    376     class PrintJobCanceler {
    377      public:
    378       explicit PrintJobCanceler(
    379           base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
    380           : job_ptr_(job_ptr) {
    381       }
    382       ~PrintJobCanceler() {
    383         if (job_ptr_ && *job_ptr_) {
    384           (*job_ptr_)->Cancel();
    385           job_ptr_->Release();
    386         }
    387       }
    388 
    389       void reset() { job_ptr_ = NULL; }
    390 
    391      private:
    392       base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
    393 
    394       DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
    395     };
    396 
    397     void PrintJobDone(bool success) {
    398       // If there is no delegate, then there is nothing pending to process.
    399       if (!delegate_)
    400         return;
    401       RestoreDC(printer_dc_.Get(), saved_dc_);
    402       EndDoc(printer_dc_.Get());
    403       if (success) {
    404         delegate_->OnJobSpoolSucceeded(job_id_);
    405       } else {
    406         delegate_->OnJobSpoolFailed();
    407       }
    408       delegate_ = NULL;
    409     }
    410 
    411     void RenderPDFPages() {
    412       int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
    413       int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
    414       int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
    415       gfx::Rect render_area(0, 0, dc_width, dc_height);
    416       g_service_process->io_thread()->message_loop_proxy()->PostTask(
    417           FROM_HERE,
    418           base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox,
    419                      this,
    420                      print_data_file_path_,
    421                      render_area,
    422                      printer_dpi,
    423                      base::MessageLoopProxy::current()));
    424     }
    425 
    426     // Called on the service process IO thread.
    427     void RenderPDFPagesInSandbox(const base::FilePath& pdf_path,
    428                                  const gfx::Rect& render_area,
    429                                  int render_dpi,
    430                                  const scoped_refptr<base::MessageLoopProxy>&
    431                                      client_message_loop_proxy) {
    432       DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    433           BelongsToCurrentThread());
    434       scoped_ptr<ServiceUtilityProcessHost> utility_host(
    435           new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    436       // TODO(gene): For now we disabling autorotation for CloudPrinting.
    437       // Landscape/Portrait setting is passed in the print ticket and
    438       // server is generating portrait PDF always.
    439       // We should enable autorotation once server will be able to generate
    440       // PDF that matches paper size and orientation.
    441       if (utility_host->StartRenderPDFPagesToMetafile(
    442               pdf_path,
    443               printing::PdfRenderSettings(render_area, render_dpi, false))) {
    444         // The object will self-destruct when the child process dies.
    445         utility_host.release();
    446       } else {
    447         client_message_loop_proxy->PostTask(
    448             FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
    449       }
    450     }
    451 
    452     bool PrintXPSDocument(const std::string& printer_name,
    453                           const std::string& job_title,
    454                           const base::FilePath& print_data_file_path,
    455                           const std::string& print_ticket) {
    456       if (!printing::XPSPrintModule::Init())
    457         return false;
    458 
    459       job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
    460       if (!job_progress_event_.Get())
    461         return false;
    462 
    463       PrintJobCanceler job_canceler(&xps_print_job_);
    464       base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
    465       base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
    466       if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
    467               base::UTF8ToWide(printer_name).c_str(),
    468               base::UTF8ToWide(job_title).c_str(),
    469               NULL, job_progress_event_.Get(), NULL, NULL, NULL,
    470               xps_print_job_.Receive(), doc_stream.Receive(),
    471               print_ticket_stream.Receive())))
    472         return false;
    473 
    474       ULONG print_bytes_written = 0;
    475       if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
    476                                             print_ticket.length(),
    477                                             &print_bytes_written)))
    478         return false;
    479       DCHECK_EQ(print_ticket.length(), print_bytes_written);
    480       if (FAILED(print_ticket_stream->Close()))
    481         return false;
    482 
    483       std::string document_data;
    484       base::ReadFileToString(print_data_file_path, &document_data);
    485       ULONG doc_bytes_written = 0;
    486       if (FAILED(doc_stream->Write(document_data.c_str(),
    487                                     document_data.length(),
    488                                     &doc_bytes_written)))
    489         return false;
    490       DCHECK_EQ(document_data.length(), doc_bytes_written);
    491       if (FAILED(doc_stream->Close()))
    492         return false;
    493 
    494       job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    495       job_canceler.reset();
    496       return true;
    497     }
    498 
    499     PlatformJobId job_id_;
    500     PrintSystem::JobSpooler::Delegate* delegate_;
    501     int saved_dc_;
    502     base::win::ScopedCreateDC printer_dc_;
    503     base::FilePath print_data_file_path_;
    504     base::win::ScopedHandle job_progress_event_;
    505     base::win::ObjectWatcher job_progress_watcher_;
    506     base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
    507 
    508     DISALLOW_COPY_AND_ASSIGN(Core);
    509   };
    510   scoped_refptr<Core> core_;
    511 
    512   DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
    513 };
    514 
    515 // A helper class to handle the response from the utility process to the
    516 // request to fetch printer capabilities and defaults.
    517 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
    518  public:
    519   PrinterCapsHandler(
    520       const std::string& printer_name,
    521       const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
    522           : printer_name_(printer_name), callback_(callback) {
    523   }
    524 
    525   // ServiceUtilityProcessHost::Client implementation.
    526   virtual void OnChildDied() OVERRIDE {
    527     OnGetPrinterCapsAndDefaults(false, printer_name_,
    528                                 printing::PrinterCapsAndDefaults());
    529   }
    530 
    531   virtual void OnGetPrinterCapsAndDefaults(
    532       bool succeeded,
    533       const std::string& printer_name,
    534       const printing::PrinterCapsAndDefaults& caps_and_defaults) OVERRIDE {
    535     callback_.Run(succeeded, printer_name, caps_and_defaults);
    536     callback_.Reset();
    537     Release();
    538   }
    539 
    540   virtual void OnGetPrinterSemanticCapsAndDefaults(
    541       bool succeeded,
    542       const std::string& printer_name,
    543       const printing::PrinterSemanticCapsAndDefaults& semantic_info) OVERRIDE {
    544     printing::PrinterCapsAndDefaults printer_info;
    545     if (succeeded) {
    546       printer_info.caps_mime_type = kContentTypeJSON;
    547       scoped_ptr<base::DictionaryValue> description(
    548           PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
    549       if (description) {
    550         base::JSONWriter::WriteWithOptions(
    551             description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
    552             &printer_info.printer_capabilities);
    553       }
    554     }
    555     callback_.Run(succeeded, printer_name, printer_info);
    556     callback_.Reset();
    557     Release();
    558   }
    559 
    560   void StartGetPrinterCapsAndDefaults() {
    561     g_service_process->io_thread()->message_loop_proxy()->PostTask(
    562         FROM_HERE,
    563         base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
    564                     base::MessageLoopProxy::current()));
    565   }
    566 
    567   void StartGetPrinterSemanticCapsAndDefaults() {
    568     g_service_process->io_thread()->message_loop_proxy()->PostTask(
    569         FROM_HERE,
    570         base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
    571                    this, base::MessageLoopProxy::current()));
    572   }
    573 
    574  private:
    575   void GetPrinterCapsAndDefaultsImpl(
    576       const scoped_refptr<base::MessageLoopProxy>&
    577           client_message_loop_proxy) {
    578     DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    579         BelongsToCurrentThread());
    580     scoped_ptr<ServiceUtilityProcessHost> utility_host(
    581         new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    582     if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
    583       // The object will self-destruct when the child process dies.
    584       utility_host.release();
    585     } else {
    586       client_message_loop_proxy->PostTask(
    587           FROM_HERE,
    588           base::Bind(&PrinterCapsHandler::OnChildDied, this));
    589     }
    590   }
    591 
    592   void GetPrinterSemanticCapsAndDefaultsImpl(
    593       const scoped_refptr<base::MessageLoopProxy>&
    594           client_message_loop_proxy) {
    595     DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    596         BelongsToCurrentThread());
    597     scoped_ptr<ServiceUtilityProcessHost> utility_host(
    598         new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    599     if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
    600       // The object will self-destruct when the child process dies.
    601       utility_host.release();
    602     } else {
    603       client_message_loop_proxy->PostTask(
    604           FROM_HERE,
    605           base::Bind(&PrinterCapsHandler::OnChildDied, this));
    606     }
    607   }
    608 
    609   std::string printer_name_;
    610   PrintSystem::PrinterCapsAndDefaultsCallback callback_;
    611 };
    612 
    613 class PrintSystemWin : public PrintSystem {
    614  public:
    615   PrintSystemWin();
    616 
    617   // PrintSystem implementation.
    618   virtual PrintSystemResult Init() OVERRIDE;
    619   virtual PrintSystem::PrintSystemResult EnumeratePrinters(
    620       printing::PrinterList* printer_list) OVERRIDE;
    621   virtual void GetPrinterCapsAndDefaults(
    622       const std::string& printer_name,
    623       const PrinterCapsAndDefaultsCallback& callback) OVERRIDE;
    624   virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
    625   virtual bool ValidatePrintTicket(
    626       const std::string& printer_name,
    627       const std::string& print_ticket_data,
    628       const std::string& print_ticket_data_mime_type) OVERRIDE;
    629   virtual bool GetJobDetails(const std::string& printer_name,
    630                              PlatformJobId job_id,
    631                              PrintJobDetails *job_details) OVERRIDE;
    632   virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() OVERRIDE;
    633   virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
    634       const std::string& printer_name) OVERRIDE;
    635   virtual PrintSystem::JobSpooler* CreateJobSpooler() OVERRIDE;
    636   virtual bool UseCddAndCjt() OVERRIDE;
    637   virtual std::string GetSupportedMimeTypes() OVERRIDE;
    638 
    639  private:
    640   std::string PrintSystemWin::GetPrinterDriverInfo(
    641       const std::string& printer_name) const;
    642 
    643   scoped_refptr<printing::PrintBackend> print_backend_;
    644   bool use_cdd_;
    645   DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
    646 };
    647 
    648 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
    649   print_backend_ = printing::PrintBackend::CreateInstance(NULL);
    650 }
    651 
    652 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
    653   use_cdd_ = !CommandLine::ForCurrentProcess()->HasSwitch(
    654       switches::kEnableCloudPrintXps);
    655 
    656   if (!use_cdd_)
    657     use_cdd_ = !printing::XPSModule::Init();
    658 
    659   if (!use_cdd_) {
    660     HPTPROVIDER provider = NULL;
    661     HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
    662     if (provider)
    663       printing::XPSModule::CloseProvider(provider);
    664     // Use cdd if error is different from expected.
    665     use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
    666   }
    667 
    668   return PrintSystemResult(true, std::string());
    669 }
    670 
    671 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
    672     printing::PrinterList* printer_list) {
    673   bool ret = print_backend_->EnumeratePrinters(printer_list);
    674   return PrintSystemResult(ret, std::string());
    675 }
    676 
    677 void PrintSystemWin::GetPrinterCapsAndDefaults(
    678     const std::string& printer_name,
    679     const PrinterCapsAndDefaultsCallback& callback) {
    680   // Launch as child process to retrieve the capabilities and defaults because
    681   // this involves invoking a printer driver DLL and crashes have been known to
    682   // occur.
    683   PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
    684   handler->AddRef();
    685   if (use_cdd_)
    686     handler->StartGetPrinterSemanticCapsAndDefaults();
    687   else
    688     handler->StartGetPrinterCapsAndDefaults();
    689 }
    690 
    691 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
    692   return print_backend_->IsValidPrinter(printer_name);
    693 }
    694 
    695 bool PrintSystemWin::ValidatePrintTicket(
    696     const std::string& printer_name,
    697     const std::string& print_ticket_data,
    698     const std::string& print_ticket_data_mime_type) {
    699   crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
    700 
    701   if (use_cdd_) {
    702     return print_ticket_data_mime_type == kContentTypeJSON &&
    703            IsValidCjt(print_ticket_data);
    704   }
    705   DCHECK(print_ticket_data_mime_type == kContentTypeXML);
    706 
    707   printing::ScopedXPSInitializer xps_initializer;
    708   if (!xps_initializer.initialized()) {
    709     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    710     return false;
    711   }
    712   bool ret = false;
    713   HPTPROVIDER provider = NULL;
    714   printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
    715                                     &provider);
    716   if (provider) {
    717     base::win::ScopedComPtr<IStream> print_ticket_stream;
    718     CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
    719     ULONG bytes_written = 0;
    720     print_ticket_stream->Write(print_ticket_data.c_str(),
    721                                print_ticket_data.length(),
    722                                &bytes_written);
    723     DCHECK(bytes_written == print_ticket_data.length());
    724     LARGE_INTEGER pos = {0};
    725     ULARGE_INTEGER new_pos = {0};
    726     print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
    727     base::win::ScopedBstr error;
    728     base::win::ScopedComPtr<IStream> result_ticket_stream;
    729     CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
    730     ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
    731         provider,
    732         print_ticket_stream.get(),
    733         NULL,
    734         kPTJobScope,
    735         result_ticket_stream.get(),
    736         error.Receive()));
    737     printing::XPSModule::CloseProvider(provider);
    738   }
    739   return ret;
    740 }
    741 
    742 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
    743                                    PlatformJobId job_id,
    744                                    PrintJobDetails *job_details) {
    745   crash_keys::ScopedPrinterInfo crash_key(
    746       print_backend_->GetPrinterDriverInfo(printer_name));
    747   DCHECK(job_details);
    748   printing::ScopedPrinterHandle printer_handle;
    749   std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
    750   printer_handle.OpenPrinter(printer_name_wide.c_str());
    751   DCHECK(printer_handle.IsValid());
    752   bool ret = false;
    753   if (printer_handle.IsValid()) {
    754     DWORD bytes_needed = 0;
    755     GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
    756     DWORD last_error = GetLastError();
    757     if (ERROR_INVALID_PARAMETER != last_error) {
    758       // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
    759       DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
    760       scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
    761       if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
    762                  bytes_needed, &bytes_needed)) {
    763         JOB_INFO_1 *job_info =
    764             reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
    765         if (job_info->pStatus) {
    766           base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
    767                            &job_details->status_message);
    768         }
    769         job_details->platform_status_flags = job_info->Status;
    770         if ((job_info->Status & JOB_STATUS_COMPLETE) ||
    771             (job_info->Status & JOB_STATUS_PRINTED)) {
    772           job_details->status = PRINT_JOB_STATUS_COMPLETED;
    773         } else if (job_info->Status & JOB_STATUS_ERROR) {
    774           job_details->status = PRINT_JOB_STATUS_ERROR;
    775         } else {
    776           job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
    777         }
    778         job_details->total_pages = job_info->TotalPages;
    779         job_details->pages_printed = job_info->PagesPrinted;
    780         ret = true;
    781       }
    782     }
    783   }
    784   return ret;
    785 }
    786 
    787 PrintSystem::PrintServerWatcher*
    788 PrintSystemWin::CreatePrintServerWatcher() {
    789   return new PrintServerWatcherWin();
    790 }
    791 
    792 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
    793     const std::string& printer_name) {
    794   DCHECK(!printer_name.empty());
    795   return new PrinterWatcherWin(printer_name);
    796 }
    797 
    798 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
    799   return new JobSpoolerWin();
    800 }
    801 
    802 bool PrintSystemWin::UseCddAndCjt() {
    803   return use_cdd_;
    804 }
    805 
    806 std::string PrintSystemWin::GetSupportedMimeTypes() {
    807   std::string result;
    808   if (!use_cdd_) {
    809     result = kContentTypeXPS;
    810     result += ",";
    811   }
    812   result += kContentTypePDF;
    813   return result;
    814 }
    815 
    816 std::string PrintSystemWin::GetPrinterDriverInfo(
    817     const std::string& printer_name) const {
    818   return print_backend_->GetPrinterDriverInfo(printer_name);
    819 }
    820 
    821 }  // namespace
    822 
    823 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
    824     const base::DictionaryValue* print_system_settings) {
    825   return new PrintSystemWin;
    826 }
    827 
    828 }  // namespace cloud_print
    829