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 <objidl.h>
      8 #include <winspool.h>
      9 #include <xpsprint.h>
     10 
     11 #include "base/bind.h"
     12 #include "base/file_util.h"
     13 #include "base/files/file_path.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "base/win/object_watcher.h"
     17 #include "base/win/scoped_bstr.h"
     18 #include "base/win/scoped_com_initializer.h"
     19 #include "base/win/scoped_comptr.h"
     20 #include "base/win/scoped_hdc.h"
     21 #include "chrome/common/child_process_logging.h"
     22 #include "chrome/service/service_process.h"
     23 #include "chrome/service/service_utility_process_host.h"
     24 #include "grit/generated_resources.h"
     25 #include "printing/backend/print_backend.h"
     26 #include "printing/backend/print_backend_consts.h"
     27 #include "printing/backend/win_helper.h"
     28 #include "printing/emf_win.h"
     29 #include "printing/page_range.h"
     30 #include "printing/pdf_render_settings.h"
     31 #include "ui/base/l10n/l10n_util.h"
     32 #include "ui/gfx/rect.h"
     33 
     34 #pragma comment(lib, "rpcrt4.lib")  // for UuidToString & Co.
     35 
     36 namespace {
     37 
     38 class PrinterChangeHandleTraits {
     39  public:
     40   typedef HANDLE Handle;
     41 
     42   static bool CloseHandle(HANDLE handle) {
     43     ::FindClosePrinterChangeNotification(handle);
     44     return true;
     45   }
     46 
     47   static bool IsHandleValid(HANDLE handle) {
     48     return handle != NULL;
     49   }
     50 
     51   static HANDLE NullHandle() {
     52     return NULL;
     53   }
     54 
     55  private:
     56   DISALLOW_IMPLICIT_CONSTRUCTORS(PrinterChangeHandleTraits);
     57 };
     58 
     59 typedef base::win::GenericScopedHandle<PrinterChangeHandleTraits,
     60                                        base::win::DummyVerifierTraits>
     61     ScopedPrinterChangeHandle;
     62 
     63 class DevMode {
     64  public:
     65   DevMode() : dm_(NULL) {}
     66   ~DevMode() { Free(); }
     67 
     68   void Allocate(int size) {
     69     Free();
     70     dm_ = reinterpret_cast<DEVMODE*>(new char[size]);
     71   }
     72 
     73   void Free() {
     74     if (dm_)
     75       delete [] dm_;
     76     dm_ = NULL;
     77   }
     78 
     79   DEVMODE* dm_;
     80 
     81  private:
     82   DISALLOW_COPY_AND_ASSIGN(DevMode);
     83 };
     84 
     85 inline HRESULT GetLastErrorHR() {
     86   LONG error = GetLastError();
     87   return HRESULT_FROM_WIN32(error);
     88 }
     89 
     90 HRESULT StreamFromPrintTicket(const std::string& print_ticket,
     91                               IStream** stream) {
     92   DCHECK(stream);
     93   HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
     94   if (FAILED(hr)) {
     95     return hr;
     96   }
     97   ULONG bytes_written = 0;
     98   (*stream)->Write(print_ticket.c_str(), print_ticket.length(), &bytes_written);
     99   DCHECK(bytes_written == print_ticket.length());
    100   LARGE_INTEGER pos = {0};
    101   ULARGE_INTEGER new_pos = {0};
    102   (*stream)->Seek(pos, STREAM_SEEK_SET, &new_pos);
    103   return S_OK;
    104 }
    105 
    106 HRESULT PrintTicketToDevMode(const std::string& printer_name,
    107                              const std::string& print_ticket,
    108                              DevMode* dev_mode) {
    109   DCHECK(dev_mode);
    110   printing::ScopedXPSInitializer xps_initializer;
    111   if (!xps_initializer.initialized()) {
    112     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    113     return E_FAIL;
    114   }
    115 
    116   base::win::ScopedComPtr<IStream> pt_stream;
    117   HRESULT hr = StreamFromPrintTicket(print_ticket, pt_stream.Receive());
    118   if (FAILED(hr))
    119     return hr;
    120 
    121   HPTPROVIDER provider = NULL;
    122   hr = printing::XPSModule::OpenProvider(UTF8ToWide(printer_name),
    123                                          1,
    124                                          &provider);
    125   if (SUCCEEDED(hr)) {
    126     ULONG size = 0;
    127     DEVMODE* dm = NULL;
    128     // Use kPTJobScope, because kPTDocumentScope breaks duplex.
    129     hr = printing::XPSModule::ConvertPrintTicketToDevMode(provider,
    130                                                           pt_stream,
    131                                                           kUserDefaultDevmode,
    132                                                           kPTJobScope,
    133                                                           &size,
    134                                                           &dm,
    135                                                           NULL);
    136     if (SUCCEEDED(hr)) {
    137       dev_mode->Allocate(size);
    138       memcpy(dev_mode->dm_, dm, size);
    139       printing::XPSModule::ReleaseMemory(dm);
    140     }
    141     printing::XPSModule::CloseProvider(provider);
    142   }
    143   return hr;
    144 }
    145 
    146 }  // namespace
    147 
    148 namespace cloud_print {
    149 
    150 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
    151  public:
    152   PrintSystemWatcherWin()
    153       : delegate_(NULL),
    154         did_signal_(false) {
    155   }
    156   ~PrintSystemWatcherWin() {
    157     Stop();
    158   }
    159 
    160   class Delegate {
    161    public:
    162     virtual ~Delegate() {}
    163     virtual void OnPrinterAdded() = 0;
    164     virtual void OnPrinterDeleted() = 0;
    165     virtual void OnPrinterChanged() = 0;
    166     virtual void OnJobChanged() = 0;
    167   };
    168 
    169   bool Start(const std::string& printer_name, Delegate* delegate) {
    170     scoped_refptr<printing::PrintBackend> print_backend(
    171         printing::PrintBackend::CreateInstance(NULL));
    172     printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
    173     child_process_logging::ScopedPrinterInfoSetter prn_info(printer_info_);
    174 
    175     delegate_ = delegate;
    176     // An empty printer name means watch the current server, we need to pass
    177     // NULL to OpenPrinter.
    178     LPTSTR printer_name_to_use = NULL;
    179     std::wstring printer_name_wide;
    180     if (!printer_name.empty()) {
    181       printer_name_wide = UTF8ToWide(printer_name);
    182       printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
    183     }
    184     bool ret = false;
    185     if (printer_.OpenPrinter(printer_name_to_use)) {
    186       printer_change_.Set(FindFirstPrinterChangeNotification(
    187           printer_, PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
    188       if (printer_change_.IsValid()) {
    189         ret = watcher_.StartWatching(printer_change_, this);
    190       }
    191     }
    192     if (!ret) {
    193       Stop();
    194     }
    195     return ret;
    196   }
    197   bool Stop() {
    198     watcher_.StopWatching();
    199     printer_.Close();
    200     printer_change_.Close();
    201     return true;
    202   }
    203 
    204   // base::ObjectWatcher::Delegate method
    205   virtual void OnObjectSignaled(HANDLE object) {
    206     child_process_logging::ScopedPrinterInfoSetter prn_info(printer_info_);
    207     DWORD change = 0;
    208     FindNextPrinterChangeNotification(object, &change, NULL, NULL);
    209 
    210     if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
    211                   (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
    212       // For printer connections, we get spurious change notifications with
    213       // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
    214       // Ignore these.
    215       if (change & PRINTER_CHANGE_ADD_PRINTER) {
    216         delegate_->OnPrinterAdded();
    217       } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
    218         delegate_->OnPrinterDeleted();
    219       } else if (change & PRINTER_CHANGE_SET_PRINTER) {
    220         delegate_->OnPrinterChanged();
    221       }
    222       if (change & PRINTER_CHANGE_JOB) {
    223         delegate_->OnJobChanged();
    224       }
    225     }
    226     watcher_.StartWatching(printer_change_, this);
    227   }
    228 
    229   bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
    230     DCHECK(printer_info);
    231     return InitBasicPrinterInfo(printer_, printer_info);
    232   }
    233 
    234  private:
    235   base::win::ObjectWatcher watcher_;
    236   printing::ScopedPrinterHandle printer_;  // The printer being watched
    237   // Returned by FindFirstPrinterChangeNotifier.
    238   ScopedPrinterChangeHandle printer_change_;
    239   Delegate* delegate_;           // Delegate to notify
    240   bool did_signal_;              // DoneWaiting was called
    241   std::string printer_info_;     // For crash reporting.
    242 };
    243 
    244 // This typedef is to workaround the issue with certain versions of
    245 // Visual Studio where it gets confused between multiple Delegate.
    246 // In this case, some compilers get confused and inherit
    247 // PrintSystemWin watchers from wrong Delegate, giving C2664 and C2259 errors.
    248 typedef PrintSystemWatcherWin::Delegate PrintSystemWatcherWinDelegate;
    249 
    250 class PrintSystemWin : public PrintSystem {
    251  public:
    252   PrintSystemWin();
    253 
    254   // PrintSystem implementation.
    255   virtual PrintSystemResult Init() OVERRIDE;
    256   virtual PrintSystem::PrintSystemResult EnumeratePrinters(
    257       printing::PrinterList* printer_list) OVERRIDE;
    258   virtual void GetPrinterCapsAndDefaults(
    259       const std::string& printer_name,
    260       const PrinterCapsAndDefaultsCallback& callback) OVERRIDE;
    261   virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
    262   virtual bool ValidatePrintTicket(
    263       const std::string& printer_name,
    264       const std::string& print_ticket_data) OVERRIDE;
    265   virtual bool GetJobDetails(const std::string& printer_name,
    266                              PlatformJobId job_id,
    267                              PrintJobDetails *job_details) OVERRIDE;
    268 
    269   class PrintServerWatcherWin
    270     : public PrintSystem::PrintServerWatcher,
    271       public PrintSystemWatcherWinDelegate {
    272    public:
    273     PrintServerWatcherWin() : delegate_(NULL) {}
    274 
    275     // PrintSystem::PrintServerWatcher implementation.
    276     virtual bool StartWatching(
    277         PrintSystem::PrintServerWatcher::Delegate* delegate) OVERRIDE{
    278       delegate_ = delegate;
    279       return watcher_.Start(std::string(), this);
    280     }
    281 
    282     virtual bool StopWatching() OVERRIDE{
    283       bool ret = watcher_.Stop();
    284       delegate_ = NULL;
    285       return ret;
    286     }
    287 
    288     // PrintSystemWatcherWin::Delegate implementation.
    289     virtual void OnPrinterAdded() OVERRIDE {
    290       delegate_->OnPrinterAdded();
    291     }
    292     virtual void OnPrinterDeleted() OVERRIDE {}
    293     virtual void OnPrinterChanged() OVERRIDE {}
    294     virtual void OnJobChanged() OVERRIDE {}
    295 
    296    protected:
    297     virtual ~PrintServerWatcherWin() {}
    298 
    299    private:
    300     PrintSystem::PrintServerWatcher::Delegate* delegate_;
    301     PrintSystemWatcherWin watcher_;
    302 
    303     DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
    304   };
    305 
    306   class PrinterWatcherWin
    307       : public PrintSystem::PrinterWatcher,
    308         public PrintSystemWatcherWinDelegate {
    309    public:
    310      explicit PrinterWatcherWin(const std::string& printer_name)
    311          : printer_name_(printer_name),
    312            delegate_(NULL) {
    313      }
    314 
    315     // PrintSystem::PrinterWatcher implementation.
    316     virtual bool StartWatching(
    317         PrintSystem::PrinterWatcher::Delegate* delegate) OVERRIDE {
    318       delegate_ = delegate;
    319       return watcher_.Start(printer_name_, this);
    320     }
    321 
    322     virtual bool StopWatching() OVERRIDE {
    323       bool ret = watcher_.Stop();
    324       delegate_ = NULL;
    325       return ret;
    326     }
    327 
    328     virtual bool GetCurrentPrinterInfo(
    329         printing::PrinterBasicInfo* printer_info) OVERRIDE {
    330       return watcher_.GetCurrentPrinterInfo(printer_info);
    331     }
    332 
    333     // PrintSystemWatcherWin::Delegate implementation.
    334     virtual void OnPrinterAdded() OVERRIDE {
    335       NOTREACHED();
    336     }
    337     virtual void OnPrinterDeleted() OVERRIDE {
    338       delegate_->OnPrinterDeleted();
    339     }
    340     virtual void OnPrinterChanged() OVERRIDE {
    341       delegate_->OnPrinterChanged();
    342     }
    343     virtual void OnJobChanged() OVERRIDE {
    344       delegate_->OnJobChanged();
    345     }
    346 
    347    protected:
    348     virtual ~PrinterWatcherWin() {}
    349 
    350    private:
    351     std::string printer_name_;
    352     PrintSystem::PrinterWatcher::Delegate* delegate_;
    353     PrintSystemWatcherWin watcher_;
    354 
    355     DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
    356   };
    357 
    358   class JobSpoolerWin : public PrintSystem::JobSpooler {
    359    public:
    360     JobSpoolerWin() : core_(new Core) {}
    361 
    362     // PrintSystem::JobSpooler implementation.
    363     virtual bool Spool(const std::string& print_ticket,
    364                        const base::FilePath& print_data_file_path,
    365                        const std::string& print_data_mime_type,
    366                        const std::string& printer_name,
    367                        const std::string& job_title,
    368                        const std::vector<std::string>& tags,
    369                        JobSpooler::Delegate* delegate) OVERRIDE {
    370       // TODO(gene): add tags handling.
    371       scoped_refptr<printing::PrintBackend> print_backend(
    372           printing::PrintBackend::CreateInstance(NULL));
    373       child_process_logging::ScopedPrinterInfoSetter prn_info(
    374           print_backend->GetPrinterDriverInfo(printer_name));
    375       return core_->Spool(print_ticket, print_data_file_path,
    376                           print_data_mime_type, printer_name, job_title,
    377                           delegate);
    378     }
    379 
    380    protected:
    381     virtual ~JobSpoolerWin() {}
    382 
    383    private:
    384     // We use a Core class because we want a separate RefCountedThreadSafe
    385     // implementation for ServiceUtilityProcessHost::Client.
    386     class Core : public ServiceUtilityProcessHost::Client,
    387                  public base::win::ObjectWatcher::Delegate {
    388      public:
    389       Core()
    390           : last_page_printed_(-1),
    391             job_id_(-1),
    392             delegate_(NULL),
    393             saved_dc_(0) {
    394       }
    395 
    396       ~Core() {}
    397 
    398       bool Spool(const std::string& print_ticket,
    399                  const base::FilePath& print_data_file_path,
    400                  const std::string& print_data_mime_type,
    401                  const std::string& printer_name,
    402                  const std::string& job_title,
    403                  JobSpooler::Delegate* delegate) {
    404         scoped_refptr<printing::PrintBackend> print_backend(
    405             printing::PrintBackend::CreateInstance(NULL));
    406         child_process_logging::ScopedPrinterInfoSetter prn_info(
    407             print_backend->GetPrinterDriverInfo(printer_name));
    408         if (delegate_) {
    409           // We are already in the process of printing.
    410           NOTREACHED();
    411           return false;
    412         }
    413         last_page_printed_ = -1;
    414         // We only support PDF and XPS documents for now.
    415         if (print_data_mime_type == "application/pdf") {
    416           DevMode pt_dev_mode;
    417           HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket,
    418                                             &pt_dev_mode);
    419           if (FAILED(hr)) {
    420             NOTREACHED();
    421             return false;
    422           }
    423 
    424           HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(),
    425                             NULL, pt_dev_mode.dm_);
    426           if (!dc) {
    427             NOTREACHED();
    428             return false;
    429           }
    430           hr = E_FAIL;
    431           DOCINFO di = {0};
    432           di.cbSize = sizeof(DOCINFO);
    433           string16 doc_name = UTF8ToUTF16(job_title);
    434           DCHECK(printing::PrintBackend::SimplifyDocumentTitle(doc_name) ==
    435                  doc_name);
    436           di.lpszDocName = doc_name.c_str();
    437           job_id_ = StartDoc(dc, &di);
    438           if (job_id_ <= 0)
    439             return false;
    440 
    441           printer_dc_.Set(dc);
    442           saved_dc_ = SaveDC(printer_dc_.Get());
    443           print_data_file_path_ = print_data_file_path;
    444           delegate_ = delegate;
    445           RenderNextPDFPages();
    446         } else if (print_data_mime_type == "application/vnd.ms-xpsdocument") {
    447           bool ret = PrintXPSDocument(printer_name,
    448                                       job_title,
    449                                       print_data_file_path,
    450                                       print_ticket);
    451           if (ret)
    452             delegate_ = delegate;
    453           return ret;
    454         } else {
    455           NOTREACHED();
    456           return false;
    457         }
    458         return true;
    459       }
    460 
    461       void PreparePageDCForPrinting(HDC, double scale_factor) {
    462         SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
    463         // Setup the matrix to translate and scale to the right place. Take in
    464         // account the scale factor.
    465         // Note that the printing output is relative to printable area of
    466         // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
    467         int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
    468         int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
    469         XFORM xform = {0};
    470         xform.eDx = static_cast<float>(-offset_x);
    471         xform.eDy = static_cast<float>(-offset_y);
    472         xform.eM11 = xform.eM22 = 1.0 / scale_factor;
    473         SetWorldTransform(printer_dc_.Get(), &xform);
    474       }
    475 
    476       // ServiceUtilityProcessHost::Client implementation.
    477       virtual void OnRenderPDFPagesToMetafileSucceeded(
    478           const printing::Emf& metafile,
    479           int highest_rendered_page_number,
    480           double scale_factor) OVERRIDE {
    481         PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
    482         metafile.SafePlayback(printer_dc_.Get());
    483         bool done_printing = (highest_rendered_page_number !=
    484             last_page_printed_ + kPageCountPerBatch);
    485         last_page_printed_ = highest_rendered_page_number;
    486         if (done_printing)
    487           PrintJobDone();
    488         else
    489           RenderNextPDFPages();
    490       }
    491 
    492       // base::win::ObjectWatcher::Delegate implementation.
    493       virtual void OnObjectSignaled(HANDLE object) OVERRIDE {
    494         DCHECK(xps_print_job_);
    495         DCHECK(object == job_progress_event_.Get());
    496         ResetEvent(job_progress_event_.Get());
    497         if (!delegate_)
    498           return;
    499         XPS_JOB_STATUS job_status = {0};
    500         xps_print_job_->GetJobStatus(&job_status);
    501         bool done = false;
    502         if ((job_status.completion == XPS_JOB_CANCELLED) ||
    503             (job_status.completion == XPS_JOB_FAILED)) {
    504           delegate_->OnJobSpoolFailed();
    505           done = true;
    506         } else if (job_status.jobId ||
    507                    (job_status.completion == XPS_JOB_COMPLETED)) {
    508           // Note: In the case of the XPS document being printed to the
    509           // Microsoft XPS Document Writer, it seems to skip spooling the job
    510           // and goes to the completed state without ever assigning a job id.
    511           delegate_->OnJobSpoolSucceeded(job_status.jobId);
    512           done = true;
    513         } else {
    514           job_progress_watcher_.StopWatching();
    515           job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    516         }
    517         if (done)
    518           com_initializer_.reset();
    519       }
    520 
    521       virtual void OnRenderPDFPagesToMetafileFailed() OVERRIDE {
    522         PrintJobDone();
    523       }
    524 
    525       virtual void OnChildDied() OVERRIDE {
    526         PrintJobDone();
    527       }
    528 
    529      private:
    530       // Helper class to allow PrintXPSDocument() to have multiple exits.
    531       class PrintJobCanceler {
    532        public:
    533         explicit PrintJobCanceler(
    534             base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
    535             : job_ptr_(job_ptr) {
    536         }
    537         ~PrintJobCanceler() {
    538           if (job_ptr_ && *job_ptr_) {
    539             (*job_ptr_)->Cancel();
    540             job_ptr_->Release();
    541           }
    542         }
    543 
    544         void reset() { job_ptr_ = NULL; }
    545 
    546        private:
    547         base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
    548 
    549         DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
    550       };
    551 
    552       void PrintJobDone() {
    553         // If there is no delegate, then there is nothing pending to process.
    554         if (!delegate_)
    555           return;
    556         RestoreDC(printer_dc_.Get(), saved_dc_);
    557         EndDoc(printer_dc_.Get());
    558         if (-1 == last_page_printed_) {
    559           delegate_->OnJobSpoolFailed();
    560         } else {
    561           delegate_->OnJobSpoolSucceeded(job_id_);
    562         }
    563         delegate_ = NULL;
    564       }
    565 
    566       void RenderNextPDFPages() {
    567         printing::PageRange range;
    568         // Render 10 pages at a time.
    569         range.from = last_page_printed_ + 1;
    570         range.to = last_page_printed_ + kPageCountPerBatch;
    571         std::vector<printing::PageRange> page_ranges;
    572         page_ranges.push_back(range);
    573 
    574         int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
    575         int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
    576         int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
    577         gfx::Rect render_area(0, 0, dc_width, dc_height);
    578         g_service_process->io_thread()->message_loop_proxy()->PostTask(
    579             FROM_HERE,
    580             base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this,
    581                        print_data_file_path_, render_area, printer_dpi,
    582                        page_ranges, base::MessageLoopProxy::current()));
    583       }
    584 
    585       // Called on the service process IO thread.
    586       void RenderPDFPagesInSandbox(
    587           const base::FilePath& pdf_path, const gfx::Rect& render_area,
    588           int render_dpi, const std::vector<printing::PageRange>& page_ranges,
    589           const scoped_refptr<base::MessageLoopProxy>&
    590               client_message_loop_proxy) {
    591         DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    592             BelongsToCurrentThread());
    593         scoped_ptr<ServiceUtilityProcessHost> utility_host(
    594             new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    595         // TODO(gene): For now we disabling autorotation for CloudPrinting.
    596         // Landscape/Portrait setting is passed in the print ticket and
    597         // server is generating portrait PDF always.
    598         // We should enable autorotation once server will be able to generate
    599         // PDF that matches paper size and orientation.
    600         if (utility_host->StartRenderPDFPagesToMetafile(
    601                 pdf_path,
    602                 printing::PdfRenderSettings(render_area, render_dpi, false),
    603                 page_ranges)) {
    604           // The object will self-destruct when the child process dies.
    605           utility_host.release();
    606         }
    607       }
    608 
    609       bool PrintXPSDocument(const std::string& printer_name,
    610                             const std::string& job_title,
    611                             const base::FilePath& print_data_file_path,
    612                             const std::string& print_ticket) {
    613         if (!printing::XPSPrintModule::Init())
    614           return false;
    615 
    616         job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
    617         if (!job_progress_event_.Get())
    618           return false;
    619 
    620         scoped_ptr<base::win::ScopedCOMInitializer> com_initializer(
    621             new base::win::ScopedCOMInitializer(
    622                 base::win::ScopedCOMInitializer::kMTA));
    623         PrintJobCanceler job_canceler(&xps_print_job_);
    624         base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
    625         base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
    626         if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
    627                 UTF8ToWide(printer_name).c_str(), UTF8ToWide(job_title).c_str(),
    628                 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
    629                 xps_print_job_.Receive(), doc_stream.Receive(),
    630                 print_ticket_stream.Receive())))
    631           return false;
    632 
    633         ULONG print_bytes_written = 0;
    634         if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
    635                                               print_ticket.length(),
    636                                               &print_bytes_written)))
    637           return false;
    638         DCHECK_EQ(print_ticket.length(), print_bytes_written);
    639         if (FAILED(print_ticket_stream->Close()))
    640           return false;
    641 
    642         std::string document_data;
    643         file_util::ReadFileToString(print_data_file_path, &document_data);
    644         ULONG doc_bytes_written = 0;
    645         if (FAILED(doc_stream->Write(document_data.c_str(),
    646                                      document_data.length(),
    647                                      &doc_bytes_written)))
    648           return false;
    649         DCHECK_EQ(document_data.length(), doc_bytes_written);
    650         if (FAILED(doc_stream->Close()))
    651           return false;
    652 
    653         job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
    654         com_initializer_.swap(com_initializer);
    655         job_canceler.reset();
    656         return true;
    657       }
    658 
    659       // Some Cairo-generated PDFs from Chrome OS result in huge metafiles.
    660       // So the PageCountPerBatch is set to 1 for now.
    661       // TODO(sanjeevr): Figure out a smarter way to determine the pages per
    662       // batch. Filed a bug to track this at
    663       // http://code.google.com/p/chromium/issues/detail?id=57350.
    664       static const int kPageCountPerBatch = 1;
    665       int last_page_printed_;
    666       PlatformJobId job_id_;
    667       PrintSystem::JobSpooler::Delegate* delegate_;
    668       int saved_dc_;
    669       base::win::ScopedCreateDC printer_dc_;
    670       base::FilePath print_data_file_path_;
    671       base::win::ScopedHandle job_progress_event_;
    672       base::win::ObjectWatcher job_progress_watcher_;
    673       base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
    674       scoped_ptr<base::win::ScopedCOMInitializer> com_initializer_;
    675 
    676       DISALLOW_COPY_AND_ASSIGN(Core);
    677     };
    678     scoped_refptr<Core> core_;
    679 
    680     DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
    681   };
    682 
    683   // A helper class to handle the response from the utility process to the
    684   // request to fetch printer capabilities and defaults.
    685   class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
    686    public:
    687     PrinterCapsHandler(
    688         const std::string& printer_name,
    689         const PrinterCapsAndDefaultsCallback& callback)
    690             : printer_name_(printer_name), callback_(callback) {
    691     }
    692 
    693     // ServiceUtilityProcessHost::Client implementation.
    694     virtual void OnChildDied() OVERRIDE {
    695       OnGetPrinterCapsAndDefaultsFailed(printer_name_);
    696     }
    697 
    698     virtual void OnGetPrinterCapsAndDefaultsSucceeded(
    699         const std::string& printer_name,
    700         const printing::PrinterCapsAndDefaults& caps_and_defaults) OVERRIDE {
    701       callback_.Run(true, printer_name, caps_and_defaults);
    702       callback_.Reset();
    703       Release();
    704     }
    705 
    706     virtual void OnGetPrinterCapsAndDefaultsFailed(
    707         const std::string& printer_name) OVERRIDE {
    708       printing::PrinterCapsAndDefaults caps_and_defaults;
    709       callback_.Run(false, printer_name, caps_and_defaults);
    710       callback_.Reset();
    711       Release();
    712     }
    713 
    714     void Start() {
    715       g_service_process->io_thread()->message_loop_proxy()->PostTask(
    716           FROM_HERE,
    717           base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
    718                      base::MessageLoopProxy::current()));
    719     }
    720 
    721    private:
    722       // Called on the service process IO thread.
    723     void GetPrinterCapsAndDefaultsImpl(
    724         const scoped_refptr<base::MessageLoopProxy>&
    725             client_message_loop_proxy) {
    726       DCHECK(g_service_process->io_thread()->message_loop_proxy()->
    727           BelongsToCurrentThread());
    728       scoped_ptr<ServiceUtilityProcessHost> utility_host(
    729           new ServiceUtilityProcessHost(this, client_message_loop_proxy));
    730       if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
    731         // The object will self-destruct when the child process dies.
    732         utility_host.release();
    733       } else {
    734         client_message_loop_proxy->PostTask(
    735             FROM_HERE,
    736             base::Bind(&PrinterCapsHandler::OnGetPrinterCapsAndDefaultsFailed,
    737                        this, printer_name_));
    738       }
    739     }
    740 
    741     std::string printer_name_;
    742     PrinterCapsAndDefaultsCallback callback_;
    743   };
    744 
    745 
    746   virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() OVERRIDE;
    747   virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
    748       const std::string& printer_name) OVERRIDE;
    749   virtual PrintSystem::JobSpooler* CreateJobSpooler() OVERRIDE;
    750   virtual std::string GetSupportedMimeTypes() OVERRIDE;
    751 
    752  private:
    753   scoped_refptr<printing::PrintBackend> print_backend_;
    754 };
    755 
    756 PrintSystemWin::PrintSystemWin() {
    757   print_backend_ = printing::PrintBackend::CreateInstance(NULL);
    758 }
    759 
    760 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
    761   if (!printing::XPSModule::Init()) {
    762     std::string message = l10n_util::GetStringFUTF8(
    763         IDS_CLOUD_PRINT_XPS_UNAVAILABLE,
    764         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
    765     return PrintSystemResult(false, message);
    766   }
    767   return PrintSystemResult(true, std::string());
    768 }
    769 
    770 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
    771     printing::PrinterList* printer_list) {
    772   bool ret = print_backend_->EnumeratePrinters(printer_list);
    773   return PrintSystemResult(ret, std::string());
    774 }
    775 
    776 void PrintSystemWin::GetPrinterCapsAndDefaults(
    777     const std::string& printer_name,
    778     const PrinterCapsAndDefaultsCallback& callback) {
    779   // Launch as child process to retrieve the capabilities and defaults because
    780   // this involves invoking a printer driver DLL and crashes have been known to
    781   // occur.
    782   PrinterCapsHandler* handler =
    783       new PrinterCapsHandler(printer_name, callback);
    784   handler->AddRef();
    785   handler->Start();
    786 }
    787 
    788 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
    789   return print_backend_->IsValidPrinter(printer_name);
    790 }
    791 
    792 bool PrintSystemWin::ValidatePrintTicket(
    793     const std::string& printer_name,
    794     const std::string& print_ticket_data) {
    795   child_process_logging::ScopedPrinterInfoSetter prn_info(
    796       print_backend_->GetPrinterDriverInfo(printer_name));
    797   printing::ScopedXPSInitializer xps_initializer;
    798   if (!xps_initializer.initialized()) {
    799     // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    800     return false;
    801   }
    802   bool ret = false;
    803   HPTPROVIDER provider = NULL;
    804   printing::XPSModule::OpenProvider(UTF8ToWide(printer_name.c_str()),
    805                                     1,
    806                                     &provider);
    807   if (provider) {
    808     base::win::ScopedComPtr<IStream> print_ticket_stream;
    809     CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
    810     ULONG bytes_written = 0;
    811     print_ticket_stream->Write(print_ticket_data.c_str(),
    812                                print_ticket_data.length(),
    813                                &bytes_written);
    814     DCHECK(bytes_written == print_ticket_data.length());
    815     LARGE_INTEGER pos = {0};
    816     ULARGE_INTEGER new_pos = {0};
    817     print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
    818     base::win::ScopedBstr error;
    819     base::win::ScopedComPtr<IStream> result_ticket_stream;
    820     CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
    821     ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
    822         provider,
    823         print_ticket_stream.get(),
    824         NULL,
    825         kPTJobScope,
    826         result_ticket_stream.get(),
    827         error.Receive()));
    828     printing::XPSModule::CloseProvider(provider);
    829   }
    830   return ret;
    831 }
    832 
    833 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
    834                                    PlatformJobId job_id,
    835                                    PrintJobDetails *job_details) {
    836   child_process_logging::ScopedPrinterInfoSetter prn_info(
    837       print_backend_->GetPrinterDriverInfo(printer_name));
    838   DCHECK(job_details);
    839   printing::ScopedPrinterHandle printer_handle;
    840   std::wstring printer_name_wide = UTF8ToWide(printer_name);
    841   printer_handle.OpenPrinter(printer_name_wide.c_str());
    842   DCHECK(printer_handle.IsValid());
    843   bool ret = false;
    844   if (printer_handle.IsValid()) {
    845     DWORD bytes_needed = 0;
    846     GetJob(printer_handle, job_id, 1, NULL, 0, &bytes_needed);
    847     DWORD last_error = GetLastError();
    848     if (ERROR_INVALID_PARAMETER != last_error) {
    849       // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
    850       DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
    851       scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
    852       if (GetJob(printer_handle, job_id, 1, job_info_buffer.get(), bytes_needed,
    853                 &bytes_needed)) {
    854         JOB_INFO_1 *job_info =
    855             reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
    856         if (job_info->pStatus) {
    857           WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
    858                      &job_details->status_message);
    859         }
    860         job_details->platform_status_flags = job_info->Status;
    861         if ((job_info->Status & JOB_STATUS_COMPLETE) ||
    862             (job_info->Status & JOB_STATUS_PRINTED)) {
    863           job_details->status = PRINT_JOB_STATUS_COMPLETED;
    864         } else if (job_info->Status & JOB_STATUS_ERROR) {
    865           job_details->status = PRINT_JOB_STATUS_ERROR;
    866         } else {
    867           job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
    868         }
    869         job_details->total_pages = job_info->TotalPages;
    870         job_details->pages_printed = job_info->PagesPrinted;
    871         ret = true;
    872       }
    873     }
    874   }
    875   return ret;
    876 }
    877 
    878 PrintSystem::PrintServerWatcher*
    879 PrintSystemWin::CreatePrintServerWatcher() {
    880   return new PrintServerWatcherWin();
    881 }
    882 
    883 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
    884     const std::string& printer_name) {
    885   DCHECK(!printer_name.empty());
    886   return new PrinterWatcherWin(printer_name);
    887 }
    888 
    889 PrintSystem::JobSpooler*
    890 PrintSystemWin::CreateJobSpooler() {
    891   return new JobSpoolerWin();
    892 }
    893 
    894 std::string PrintSystemWin::GetSupportedMimeTypes() {
    895   if (printing::XPSPrintModule::Init())
    896     return "application/vnd.ms-xpsdocument,application/pdf";
    897   return "application/pdf";
    898 }
    899 
    900 
    901 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
    902     const base::DictionaryValue* print_system_settings) {
    903   return new PrintSystemWin;
    904 }
    905 
    906 }  // namespace cloud_print
    907