Avoid crashing when going back/forward to debug URLs on a sad WebUI tab.
[chromium-blink-merge.git] / chrome / service / cloud_print / print_system_win.cc
blobe4a62626659af2118da8258b18aa6cacc7ab41e6
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/service/cloud_print/print_system.h"
7 #include "base/command_line.h"
8 #include "base/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/thread_task_runner_handle.h"
13 #include "base/win/object_watcher.h"
14 #include "base/win/scoped_bstr.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/scoped_hdc.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
19 #include "chrome/common/cloud_print/cloud_print_constants.h"
20 #include "chrome/common/crash_keys.h"
21 #include "chrome/service/cloud_print/cdd_conversion_win.h"
22 #include "chrome/service/service_process.h"
23 #include "chrome/service/service_utility_process_host.h"
24 #include "printing/backend/win_helper.h"
25 #include "printing/emf_win.h"
26 #include "printing/page_range.h"
27 #include "printing/pdf_render_settings.h"
28 #include "printing/printing_utils.h"
29 #include "ui/gfx/geometry/rect.h"
31 namespace cloud_print {
33 namespace {
35 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
36 public:
37 PrintSystemWatcherWin()
38 : delegate_(NULL) {
40 ~PrintSystemWatcherWin() override { Stop(); }
42 class Delegate {
43 public:
44 virtual ~Delegate() {}
45 virtual void OnPrinterAdded() = 0;
46 virtual void OnPrinterDeleted() = 0;
47 virtual void OnPrinterChanged() = 0;
48 virtual void OnJobChanged() = 0;
51 bool Start(const std::string& printer_name, Delegate* delegate) {
52 scoped_refptr<printing::PrintBackend> print_backend(
53 printing::PrintBackend::CreateInstance(NULL));
54 printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
55 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
57 delegate_ = delegate;
58 // An empty printer name means watch the current server, we need to pass
59 // NULL to OpenPrinter.
60 LPTSTR printer_name_to_use = NULL;
61 std::wstring printer_name_wide;
62 if (!printer_name.empty()) {
63 printer_name_wide = base::UTF8ToWide(printer_name);
64 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
66 bool ret = false;
67 if (printer_.OpenPrinter(printer_name_to_use)) {
68 printer_change_.Set(FindFirstPrinterChangeNotification(
69 printer_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
70 if (printer_change_.IsValid()) {
71 ret = watcher_.StartWatching(printer_change_.Get(), this);
74 if (!ret) {
75 Stop();
77 return ret;
80 bool Stop() {
81 watcher_.StopWatching();
82 printer_.Close();
83 printer_change_.Close();
84 return true;
87 // base::ObjectWatcher::Delegate method
88 void OnObjectSignaled(HANDLE object) override {
89 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
90 DWORD change = 0;
91 FindNextPrinterChangeNotification(object, &change, NULL, NULL);
93 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
94 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
95 // For printer connections, we get spurious change notifications with
96 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
97 // Ignore these.
98 if (change & PRINTER_CHANGE_ADD_PRINTER) {
99 delegate_->OnPrinterAdded();
100 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
101 delegate_->OnPrinterDeleted();
102 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
103 delegate_->OnPrinterChanged();
105 if (change & PRINTER_CHANGE_JOB) {
106 delegate_->OnJobChanged();
109 watcher_.StartWatching(printer_change_.Get(), this);
112 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
113 DCHECK(printer_info);
114 return InitBasicPrinterInfo(printer_.Get(), printer_info);
117 private:
118 base::win::ObjectWatcher watcher_;
119 printing::ScopedPrinterHandle printer_; // The printer being watched
120 // Returned by FindFirstPrinterChangeNotifier.
121 printing::ScopedPrinterChangeHandle printer_change_;
122 Delegate* delegate_; // Delegate to notify
123 std::string printer_info_; // For crash reporting.
126 class PrintServerWatcherWin
127 : public PrintSystem::PrintServerWatcher,
128 public PrintSystemWatcherWin::Delegate {
129 public:
130 PrintServerWatcherWin() : delegate_(NULL) {}
132 // PrintSystem::PrintServerWatcher implementation.
133 bool StartWatching(
134 PrintSystem::PrintServerWatcher::Delegate* delegate) override {
135 delegate_ = delegate;
136 return watcher_.Start(std::string(), this);
139 bool StopWatching() override {
140 bool ret = watcher_.Stop();
141 delegate_ = NULL;
142 return ret;
145 // PrintSystemWatcherWin::Delegate implementation.
146 void OnPrinterAdded() override {
147 delegate_->OnPrinterAdded();
149 void OnPrinterDeleted() override {}
150 void OnPrinterChanged() override {}
151 void OnJobChanged() override {}
153 protected:
154 ~PrintServerWatcherWin() override {}
156 private:
157 PrintSystem::PrintServerWatcher::Delegate* delegate_;
158 PrintSystemWatcherWin watcher_;
160 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
163 class PrinterWatcherWin
164 : public PrintSystem::PrinterWatcher,
165 public PrintSystemWatcherWin::Delegate {
166 public:
167 explicit PrinterWatcherWin(const std::string& printer_name)
168 : printer_name_(printer_name),
169 delegate_(NULL) {
172 // PrintSystem::PrinterWatcher implementation.
173 bool StartWatching(PrintSystem::PrinterWatcher::Delegate* delegate) override {
174 delegate_ = delegate;
175 return watcher_.Start(printer_name_, this);
178 bool StopWatching() override {
179 bool ret = watcher_.Stop();
180 delegate_ = NULL;
181 return ret;
184 bool GetCurrentPrinterInfo(
185 printing::PrinterBasicInfo* printer_info) override {
186 return watcher_.GetCurrentPrinterInfo(printer_info);
189 // PrintSystemWatcherWin::Delegate implementation.
190 void OnPrinterAdded() override {
191 NOTREACHED();
193 void OnPrinterDeleted() override {
194 delegate_->OnPrinterDeleted();
196 void OnPrinterChanged() override {
197 delegate_->OnPrinterChanged();
199 void OnJobChanged() override {
200 delegate_->OnJobChanged();
203 protected:
204 ~PrinterWatcherWin() override {}
206 private:
207 std::string printer_name_;
208 PrintSystem::PrinterWatcher::Delegate* delegate_;
209 PrintSystemWatcherWin watcher_;
211 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
214 class JobSpoolerWin : public PrintSystem::JobSpooler {
215 public:
216 JobSpoolerWin() : core_(new Core) {}
218 // PrintSystem::JobSpooler implementation.
219 bool Spool(const std::string& print_ticket,
220 const std::string& print_ticket_mime_type,
221 const base::FilePath& print_data_file_path,
222 const std::string& print_data_mime_type,
223 const std::string& printer_name,
224 const std::string& job_title,
225 const std::vector<std::string>& tags,
226 JobSpooler::Delegate* delegate) override {
227 // TODO(gene): add tags handling.
228 scoped_refptr<printing::PrintBackend> print_backend(
229 printing::PrintBackend::CreateInstance(NULL));
230 crash_keys::ScopedPrinterInfo crash_key(
231 print_backend->GetPrinterDriverInfo(printer_name));
232 return core_->Spool(print_ticket, print_ticket_mime_type,
233 print_data_file_path, print_data_mime_type,
234 printer_name, job_title, delegate);
237 protected:
238 ~JobSpoolerWin() override {}
240 private:
241 // We use a Core class because we want a separate RefCountedThreadSafe
242 // implementation for ServiceUtilityProcessHost::Client.
243 class Core : public ServiceUtilityProcessHost::Client,
244 public base::win::ObjectWatcher::Delegate {
245 public:
246 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
248 bool Spool(const std::string& print_ticket,
249 const std::string& print_ticket_mime_type,
250 const base::FilePath& print_data_file_path,
251 const std::string& print_data_mime_type,
252 const std::string& printer_name,
253 const std::string& job_title,
254 JobSpooler::Delegate* delegate) {
255 if (delegate_) {
256 // We are already in the process of printing.
257 NOTREACHED();
258 return false;
260 base::string16 printer_wide = base::UTF8ToWide(printer_name);
261 // We only support PDF and XPS documents for now.
262 if (print_data_mime_type == kContentTypePDF) {
263 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
264 if (print_ticket_mime_type == kContentTypeJSON) {
265 dev_mode = CjtToDevMode(printer_wide, print_ticket);
266 } else {
267 DCHECK(print_ticket_mime_type == kContentTypeXML);
268 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
271 if (!dev_mode) {
272 NOTREACHED();
273 return false;
276 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
277 dev_mode.get());
278 if (!dc) {
279 NOTREACHED();
280 return false;
282 DOCINFO di = {0};
283 di.cbSize = sizeof(DOCINFO);
284 base::string16 doc_name = base::UTF8ToUTF16(job_title);
285 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
286 di.lpszDocName = doc_name.c_str();
287 job_id_ = StartDoc(dc, &di);
288 if (job_id_ <= 0)
289 return false;
291 printer_dc_.Set(dc);
292 saved_dc_ = SaveDC(printer_dc_.Get());
293 print_data_file_path_ = print_data_file_path;
294 delegate_ = delegate;
295 RenderPDFPages();
296 } else if (print_data_mime_type == kContentTypeXPS) {
297 DCHECK(print_ticket_mime_type == kContentTypeXML);
298 bool ret = PrintXPSDocument(printer_name,
299 job_title,
300 print_data_file_path,
301 print_ticket);
302 if (ret)
303 delegate_ = delegate;
304 return ret;
305 } else {
306 NOTREACHED();
307 return false;
309 return true;
312 void PreparePageDCForPrinting(HDC, float scale_factor) {
313 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
314 // Setup the matrix to translate and scale to the right place. Take in
315 // account the scale factor.
316 // Note that the printing output is relative to printable area of
317 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
318 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
319 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
320 XFORM xform = {0};
321 xform.eDx = static_cast<float>(-offset_x);
322 xform.eDy = static_cast<float>(-offset_y);
323 xform.eM11 = xform.eM22 = 1.0f / scale_factor;
324 SetWorldTransform(printer_dc_.Get(), &xform);
327 // ServiceUtilityProcessHost::Client implementation.
328 void OnRenderPDFPagesToMetafilePageDone(
329 float scale_factor,
330 const printing::MetafilePlayer& emf) override {
331 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
332 ::StartPage(printer_dc_.Get());
333 emf.SafePlayback(printer_dc_.Get());
334 ::EndPage(printer_dc_.Get());
337 // ServiceUtilityProcessHost::Client implementation.
338 void OnRenderPDFPagesToMetafileDone(bool success) override {
339 PrintJobDone(success);
342 void OnChildDied() override { PrintJobDone(false); }
344 // base::win::ObjectWatcher::Delegate implementation.
345 void OnObjectSignaled(HANDLE object) override {
346 DCHECK(xps_print_job_.get());
347 DCHECK(object == job_progress_event_.Get());
348 ResetEvent(job_progress_event_.Get());
349 if (!delegate_)
350 return;
351 XPS_JOB_STATUS job_status = {0};
352 xps_print_job_->GetJobStatus(&job_status);
353 if ((job_status.completion == XPS_JOB_CANCELLED) ||
354 (job_status.completion == XPS_JOB_FAILED)) {
355 delegate_->OnJobSpoolFailed();
356 } else if (job_status.jobId ||
357 (job_status.completion == XPS_JOB_COMPLETED)) {
358 // Note: In the case of the XPS document being printed to the
359 // Microsoft XPS Document Writer, it seems to skip spooling the job
360 // and goes to the completed state without ever assigning a job id.
361 delegate_->OnJobSpoolSucceeded(job_status.jobId);
362 } else {
363 job_progress_watcher_.StopWatching();
364 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
368 private:
369 ~Core() override {}
371 // Helper class to allow PrintXPSDocument() to have multiple exits.
372 class PrintJobCanceler {
373 public:
374 explicit PrintJobCanceler(
375 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
376 : job_ptr_(job_ptr) {
378 ~PrintJobCanceler() {
379 if (job_ptr_ && job_ptr_->get()) {
380 (*job_ptr_)->Cancel();
381 job_ptr_->Release();
385 void reset() { job_ptr_ = NULL; }
387 private:
388 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
390 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
393 void PrintJobDone(bool success) {
394 // If there is no delegate, then there is nothing pending to process.
395 if (!delegate_)
396 return;
397 RestoreDC(printer_dc_.Get(), saved_dc_);
398 EndDoc(printer_dc_.Get());
399 if (success) {
400 delegate_->OnJobSpoolSucceeded(job_id_);
401 } else {
402 delegate_->OnJobSpoolFailed();
404 delegate_ = NULL;
407 void RenderPDFPages() {
408 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
409 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
410 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
411 gfx::Rect render_area(0, 0, dc_width, dc_height);
412 g_service_process->io_task_runner()->PostTask(
413 FROM_HERE,
414 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this,
415 print_data_file_path_, render_area, printer_dpi,
416 base::ThreadTaskRunnerHandle::Get()));
419 // Called on the service process IO thread.
420 void RenderPDFPagesInSandbox(
421 const base::FilePath& pdf_path,
422 const gfx::Rect& render_area,
423 int render_dpi,
424 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
425 DCHECK(g_service_process->io_task_runner()->BelongsToCurrentThread());
426 scoped_ptr<ServiceUtilityProcessHost> utility_host(
427 new ServiceUtilityProcessHost(this, client_task_runner.get()));
428 // TODO(gene): For now we disabling autorotation for CloudPrinting.
429 // Landscape/Portrait setting is passed in the print ticket and
430 // server is generating portrait PDF always.
431 // We should enable autorotation once server will be able to generate
432 // PDF that matches paper size and orientation.
433 if (utility_host->StartRenderPDFPagesToMetafile(
434 pdf_path,
435 printing::PdfRenderSettings(render_area, render_dpi, false))) {
436 // The object will self-destruct when the child process dies.
437 utility_host.release();
438 } else {
439 client_task_runner->PostTask(
440 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
444 bool PrintXPSDocument(const std::string& printer_name,
445 const std::string& job_title,
446 const base::FilePath& print_data_file_path,
447 const std::string& print_ticket) {
448 if (!printing::XPSPrintModule::Init())
449 return false;
451 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
452 if (!job_progress_event_.Get())
453 return false;
455 PrintJobCanceler job_canceler(&xps_print_job_);
456 base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
457 base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
458 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
459 base::UTF8ToWide(printer_name).c_str(),
460 base::UTF8ToWide(job_title).c_str(),
461 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
462 xps_print_job_.Receive(), doc_stream.Receive(),
463 print_ticket_stream.Receive())))
464 return false;
466 ULONG print_bytes_written = 0;
467 if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
468 print_ticket.length(),
469 &print_bytes_written)))
470 return false;
471 DCHECK_EQ(print_ticket.length(), print_bytes_written);
472 if (FAILED(print_ticket_stream->Close()))
473 return false;
475 std::string document_data;
476 base::ReadFileToString(print_data_file_path, &document_data);
477 ULONG doc_bytes_written = 0;
478 if (FAILED(doc_stream->Write(document_data.c_str(),
479 document_data.length(),
480 &doc_bytes_written)))
481 return false;
482 DCHECK_EQ(document_data.length(), doc_bytes_written);
483 if (FAILED(doc_stream->Close()))
484 return false;
486 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
487 job_canceler.reset();
488 return true;
491 PlatformJobId job_id_;
492 PrintSystem::JobSpooler::Delegate* delegate_;
493 int saved_dc_;
494 base::win::ScopedCreateDC printer_dc_;
495 base::FilePath print_data_file_path_;
496 base::win::ScopedHandle job_progress_event_;
497 base::win::ObjectWatcher job_progress_watcher_;
498 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
500 DISALLOW_COPY_AND_ASSIGN(Core);
502 scoped_refptr<Core> core_;
504 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
507 // A helper class to handle the response from the utility process to the
508 // request to fetch printer capabilities and defaults.
509 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
510 public:
511 PrinterCapsHandler(
512 const std::string& printer_name,
513 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
514 : printer_name_(printer_name), callback_(callback) {
517 // ServiceUtilityProcessHost::Client implementation.
518 void OnChildDied() override {
519 OnGetPrinterCapsAndDefaults(false, printer_name_,
520 printing::PrinterCapsAndDefaults());
523 void OnGetPrinterCapsAndDefaults(
524 bool succeeded,
525 const std::string& printer_name,
526 const printing::PrinterCapsAndDefaults& caps_and_defaults) override {
527 callback_.Run(succeeded, printer_name, caps_and_defaults);
528 callback_.Reset();
529 Release();
532 void OnGetPrinterSemanticCapsAndDefaults(
533 bool succeeded,
534 const std::string& printer_name,
535 const printing::PrinterSemanticCapsAndDefaults& semantic_info) override {
536 printing::PrinterCapsAndDefaults printer_info;
537 if (succeeded) {
538 printer_info.caps_mime_type = kContentTypeJSON;
539 scoped_ptr<base::DictionaryValue> description(
540 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
541 if (description) {
542 base::JSONWriter::WriteWithOptions(
543 *description, base::JSONWriter::OPTIONS_PRETTY_PRINT,
544 &printer_info.printer_capabilities);
547 callback_.Run(succeeded, printer_name, printer_info);
548 callback_.Reset();
549 Release();
552 void StartGetPrinterCapsAndDefaults() {
553 g_service_process->io_task_runner()->PostTask(
554 FROM_HERE,
555 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
556 base::ThreadTaskRunnerHandle::Get()));
559 void StartGetPrinterSemanticCapsAndDefaults() {
560 g_service_process->io_task_runner()->PostTask(
561 FROM_HERE,
562 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
563 this, base::ThreadTaskRunnerHandle::Get()));
566 private:
567 ~PrinterCapsHandler() override {}
569 void GetPrinterCapsAndDefaultsImpl(
570 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
571 DCHECK(g_service_process->io_task_runner()->BelongsToCurrentThread());
572 scoped_ptr<ServiceUtilityProcessHost> utility_host(
573 new ServiceUtilityProcessHost(this, client_task_runner.get()));
574 if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
575 // The object will self-destruct when the child process dies.
576 utility_host.release();
577 } else {
578 client_task_runner->PostTask(
579 FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
583 void GetPrinterSemanticCapsAndDefaultsImpl(
584 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
585 DCHECK(g_service_process->io_task_runner()->BelongsToCurrentThread());
586 scoped_ptr<ServiceUtilityProcessHost> utility_host(
587 new ServiceUtilityProcessHost(this, client_task_runner.get()));
588 if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
589 // The object will self-destruct when the child process dies.
590 utility_host.release();
591 } else {
592 client_task_runner->PostTask(
593 FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
597 std::string printer_name_;
598 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
601 class PrintSystemWin : public PrintSystem {
602 public:
603 PrintSystemWin();
605 // PrintSystem implementation.
606 PrintSystemResult Init() override;
607 PrintSystem::PrintSystemResult EnumeratePrinters(
608 printing::PrinterList* printer_list) override;
609 void GetPrinterCapsAndDefaults(
610 const std::string& printer_name,
611 const PrinterCapsAndDefaultsCallback& callback) override;
612 bool IsValidPrinter(const std::string& printer_name) override;
613 bool ValidatePrintTicket(
614 const std::string& printer_name,
615 const std::string& print_ticket_data,
616 const std::string& print_ticket_data_mime_type) override;
617 bool GetJobDetails(const std::string& printer_name,
618 PlatformJobId job_id,
619 PrintJobDetails* job_details) override;
620 PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() override;
621 PrintSystem::PrinterWatcher* CreatePrinterWatcher(
622 const std::string& printer_name) override;
623 PrintSystem::JobSpooler* CreateJobSpooler() override;
624 bool UseCddAndCjt() override;
625 std::string GetSupportedMimeTypes() override;
627 private:
628 ~PrintSystemWin() override {}
630 std::string GetPrinterDriverInfo(const std::string& printer_name) const;
632 scoped_refptr<printing::PrintBackend> print_backend_;
633 bool use_cdd_;
634 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
637 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
638 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
641 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
642 use_cdd_ = !base::CommandLine::ForCurrentProcess()->HasSwitch(
643 switches::kEnableCloudPrintXps);
645 if (!use_cdd_)
646 use_cdd_ = !printing::XPSModule::Init();
648 if (!use_cdd_) {
649 HPTPROVIDER provider = NULL;
650 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
651 if (provider)
652 printing::XPSModule::CloseProvider(provider);
653 // Use cdd if error is different from expected.
654 use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
657 return PrintSystemResult(true, std::string());
660 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
661 printing::PrinterList* printer_list) {
662 bool ret = print_backend_->EnumeratePrinters(printer_list);
663 return PrintSystemResult(ret, std::string());
666 void PrintSystemWin::GetPrinterCapsAndDefaults(
667 const std::string& printer_name,
668 const PrinterCapsAndDefaultsCallback& callback) {
669 // Launch as child process to retrieve the capabilities and defaults because
670 // this involves invoking a printer driver DLL and crashes have been known to
671 // occur.
672 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
673 handler->AddRef();
674 if (use_cdd_)
675 handler->StartGetPrinterSemanticCapsAndDefaults();
676 else
677 handler->StartGetPrinterCapsAndDefaults();
680 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
681 return print_backend_->IsValidPrinter(printer_name);
684 bool PrintSystemWin::ValidatePrintTicket(
685 const std::string& printer_name,
686 const std::string& print_ticket_data,
687 const std::string& print_ticket_data_mime_type) {
688 crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
690 if (use_cdd_) {
691 return print_ticket_data_mime_type == kContentTypeJSON &&
692 IsValidCjt(print_ticket_data);
694 DCHECK(print_ticket_data_mime_type == kContentTypeXML);
696 printing::ScopedXPSInitializer xps_initializer;
697 if (!xps_initializer.initialized()) {
698 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
699 return false;
701 bool ret = false;
702 HPTPROVIDER provider = NULL;
703 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
704 &provider);
705 if (provider) {
706 base::win::ScopedComPtr<IStream> print_ticket_stream;
707 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
708 ULONG bytes_written = 0;
709 print_ticket_stream->Write(print_ticket_data.c_str(),
710 print_ticket_data.length(),
711 &bytes_written);
712 DCHECK(bytes_written == print_ticket_data.length());
713 LARGE_INTEGER pos = {};
714 ULARGE_INTEGER new_pos = {};
715 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
716 base::win::ScopedBstr error;
717 base::win::ScopedComPtr<IStream> result_ticket_stream;
718 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
719 ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
720 provider,
721 print_ticket_stream.get(),
722 NULL,
723 kPTJobScope,
724 result_ticket_stream.get(),
725 error.Receive()));
726 printing::XPSModule::CloseProvider(provider);
728 return ret;
731 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
732 PlatformJobId job_id,
733 PrintJobDetails *job_details) {
734 crash_keys::ScopedPrinterInfo crash_key(
735 print_backend_->GetPrinterDriverInfo(printer_name));
736 DCHECK(job_details);
737 printing::ScopedPrinterHandle printer_handle;
738 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
739 printer_handle.OpenPrinter(printer_name_wide.c_str());
740 DCHECK(printer_handle.IsValid());
741 bool ret = false;
742 if (printer_handle.IsValid()) {
743 DWORD bytes_needed = 0;
744 GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
745 DWORD last_error = GetLastError();
746 if (ERROR_INVALID_PARAMETER != last_error) {
747 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
748 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
749 scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
750 if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
751 bytes_needed, &bytes_needed)) {
752 JOB_INFO_1 *job_info =
753 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
754 if (job_info->pStatus) {
755 base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
756 &job_details->status_message);
758 job_details->platform_status_flags = job_info->Status;
759 if ((job_info->Status & JOB_STATUS_COMPLETE) ||
760 (job_info->Status & JOB_STATUS_PRINTED)) {
761 job_details->status = PRINT_JOB_STATUS_COMPLETED;
762 } else if (job_info->Status & JOB_STATUS_ERROR) {
763 job_details->status = PRINT_JOB_STATUS_ERROR;
764 } else {
765 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
767 job_details->total_pages = job_info->TotalPages;
768 job_details->pages_printed = job_info->PagesPrinted;
769 ret = true;
773 return ret;
776 PrintSystem::PrintServerWatcher*
777 PrintSystemWin::CreatePrintServerWatcher() {
778 return new PrintServerWatcherWin();
781 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
782 const std::string& printer_name) {
783 DCHECK(!printer_name.empty());
784 return new PrinterWatcherWin(printer_name);
787 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
788 return new JobSpoolerWin();
791 bool PrintSystemWin::UseCddAndCjt() {
792 return use_cdd_;
795 std::string PrintSystemWin::GetSupportedMimeTypes() {
796 std::string result;
797 if (!use_cdd_) {
798 result = kContentTypeXPS;
799 result += ",";
801 result += kContentTypePDF;
802 return result;
805 std::string PrintSystemWin::GetPrinterDriverInfo(
806 const std::string& printer_name) const {
807 return print_backend_->GetPrinterDriverInfo(printer_name);
810 } // namespace
812 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
813 const base::DictionaryValue* print_system_settings) {
814 return new PrintSystemWin;
817 } // namespace cloud_print