[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / chrome / service / cloud_print / print_system_win.cc
blob58b52311057e020f24f30abf7865f266b4dd6cef
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),
39 did_signal_(false) {
41 ~PrintSystemWatcherWin() override { Stop(); }
43 class Delegate {
44 public:
45 virtual ~Delegate() {}
46 virtual void OnPrinterAdded() = 0;
47 virtual void OnPrinterDeleted() = 0;
48 virtual void OnPrinterChanged() = 0;
49 virtual void OnJobChanged() = 0;
52 bool Start(const std::string& printer_name, Delegate* delegate) {
53 scoped_refptr<printing::PrintBackend> print_backend(
54 printing::PrintBackend::CreateInstance(NULL));
55 printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
56 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
58 delegate_ = delegate;
59 // An empty printer name means watch the current server, we need to pass
60 // NULL to OpenPrinter.
61 LPTSTR printer_name_to_use = NULL;
62 std::wstring printer_name_wide;
63 if (!printer_name.empty()) {
64 printer_name_wide = base::UTF8ToWide(printer_name);
65 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
67 bool ret = false;
68 if (printer_.OpenPrinter(printer_name_to_use)) {
69 printer_change_.Set(FindFirstPrinterChangeNotification(
70 printer_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
71 if (printer_change_.IsValid()) {
72 ret = watcher_.StartWatching(printer_change_.Get(), this);
75 if (!ret) {
76 Stop();
78 return ret;
81 bool Stop() {
82 watcher_.StopWatching();
83 printer_.Close();
84 printer_change_.Close();
85 return true;
88 // base::ObjectWatcher::Delegate method
89 void OnObjectSignaled(HANDLE object) override {
90 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
91 DWORD change = 0;
92 FindNextPrinterChangeNotification(object, &change, NULL, NULL);
94 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
95 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
96 // For printer connections, we get spurious change notifications with
97 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
98 // Ignore these.
99 if (change & PRINTER_CHANGE_ADD_PRINTER) {
100 delegate_->OnPrinterAdded();
101 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
102 delegate_->OnPrinterDeleted();
103 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
104 delegate_->OnPrinterChanged();
106 if (change & PRINTER_CHANGE_JOB) {
107 delegate_->OnJobChanged();
110 watcher_.StartWatching(printer_change_.Get(), this);
113 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
114 DCHECK(printer_info);
115 return InitBasicPrinterInfo(printer_.Get(), printer_info);
118 private:
119 base::win::ObjectWatcher watcher_;
120 printing::ScopedPrinterHandle printer_; // The printer being watched
121 // Returned by FindFirstPrinterChangeNotifier.
122 printing::ScopedPrinterChangeHandle printer_change_;
123 Delegate* delegate_; // Delegate to notify
124 bool did_signal_; // DoneWaiting was called
125 std::string printer_info_; // For crash reporting.
128 class PrintServerWatcherWin
129 : public PrintSystem::PrintServerWatcher,
130 public PrintSystemWatcherWin::Delegate {
131 public:
132 PrintServerWatcherWin() : delegate_(NULL) {}
134 // PrintSystem::PrintServerWatcher implementation.
135 bool StartWatching(
136 PrintSystem::PrintServerWatcher::Delegate* delegate) override {
137 delegate_ = delegate;
138 return watcher_.Start(std::string(), this);
141 bool StopWatching() override {
142 bool ret = watcher_.Stop();
143 delegate_ = NULL;
144 return ret;
147 // PrintSystemWatcherWin::Delegate implementation.
148 void OnPrinterAdded() override {
149 delegate_->OnPrinterAdded();
151 void OnPrinterDeleted() override {}
152 void OnPrinterChanged() override {}
153 void OnJobChanged() override {}
155 protected:
156 ~PrintServerWatcherWin() override {}
158 private:
159 PrintSystem::PrintServerWatcher::Delegate* delegate_;
160 PrintSystemWatcherWin watcher_;
162 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
165 class PrinterWatcherWin
166 : public PrintSystem::PrinterWatcher,
167 public PrintSystemWatcherWin::Delegate {
168 public:
169 explicit PrinterWatcherWin(const std::string& printer_name)
170 : printer_name_(printer_name),
171 delegate_(NULL) {
174 // PrintSystem::PrinterWatcher implementation.
175 bool StartWatching(PrintSystem::PrinterWatcher::Delegate* delegate) override {
176 delegate_ = delegate;
177 return watcher_.Start(printer_name_, this);
180 bool StopWatching() override {
181 bool ret = watcher_.Stop();
182 delegate_ = NULL;
183 return ret;
186 bool GetCurrentPrinterInfo(
187 printing::PrinterBasicInfo* printer_info) override {
188 return watcher_.GetCurrentPrinterInfo(printer_info);
191 // PrintSystemWatcherWin::Delegate implementation.
192 void OnPrinterAdded() override {
193 NOTREACHED();
195 void OnPrinterDeleted() override {
196 delegate_->OnPrinterDeleted();
198 void OnPrinterChanged() override {
199 delegate_->OnPrinterChanged();
201 void OnJobChanged() override {
202 delegate_->OnJobChanged();
205 protected:
206 ~PrinterWatcherWin() override {}
208 private:
209 std::string printer_name_;
210 PrintSystem::PrinterWatcher::Delegate* delegate_;
211 PrintSystemWatcherWin watcher_;
213 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
216 class JobSpoolerWin : public PrintSystem::JobSpooler {
217 public:
218 JobSpoolerWin() : core_(new Core) {}
220 // PrintSystem::JobSpooler implementation.
221 bool Spool(const std::string& print_ticket,
222 const std::string& print_ticket_mime_type,
223 const base::FilePath& print_data_file_path,
224 const std::string& print_data_mime_type,
225 const std::string& printer_name,
226 const std::string& job_title,
227 const std::vector<std::string>& tags,
228 JobSpooler::Delegate* delegate) override {
229 // TODO(gene): add tags handling.
230 scoped_refptr<printing::PrintBackend> print_backend(
231 printing::PrintBackend::CreateInstance(NULL));
232 crash_keys::ScopedPrinterInfo crash_key(
233 print_backend->GetPrinterDriverInfo(printer_name));
234 return core_->Spool(print_ticket, print_ticket_mime_type,
235 print_data_file_path, print_data_mime_type,
236 printer_name, job_title, delegate);
239 protected:
240 ~JobSpoolerWin() override {}
242 private:
243 // We use a Core class because we want a separate RefCountedThreadSafe
244 // implementation for ServiceUtilityProcessHost::Client.
245 class Core : public ServiceUtilityProcessHost::Client,
246 public base::win::ObjectWatcher::Delegate {
247 public:
248 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
250 bool Spool(const std::string& print_ticket,
251 const std::string& print_ticket_mime_type,
252 const base::FilePath& print_data_file_path,
253 const std::string& print_data_mime_type,
254 const std::string& printer_name,
255 const std::string& job_title,
256 JobSpooler::Delegate* delegate) {
257 if (delegate_) {
258 // We are already in the process of printing.
259 NOTREACHED();
260 return false;
262 base::string16 printer_wide = base::UTF8ToWide(printer_name);
263 // We only support PDF and XPS documents for now.
264 if (print_data_mime_type == kContentTypePDF) {
265 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
266 if (print_ticket_mime_type == kContentTypeJSON) {
267 dev_mode = CjtToDevMode(printer_wide, print_ticket);
268 } else {
269 DCHECK(print_ticket_mime_type == kContentTypeXML);
270 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
273 if (!dev_mode) {
274 NOTREACHED();
275 return false;
278 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
279 dev_mode.get());
280 if (!dc) {
281 NOTREACHED();
282 return false;
284 DOCINFO di = {0};
285 di.cbSize = sizeof(DOCINFO);
286 base::string16 doc_name = base::UTF8ToUTF16(job_title);
287 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
288 di.lpszDocName = doc_name.c_str();
289 job_id_ = StartDoc(dc, &di);
290 if (job_id_ <= 0)
291 return false;
293 printer_dc_.Set(dc);
294 saved_dc_ = SaveDC(printer_dc_.Get());
295 print_data_file_path_ = print_data_file_path;
296 delegate_ = delegate;
297 RenderPDFPages();
298 } else if (print_data_mime_type == kContentTypeXPS) {
299 DCHECK(print_ticket_mime_type == kContentTypeXML);
300 bool ret = PrintXPSDocument(printer_name,
301 job_title,
302 print_data_file_path,
303 print_ticket);
304 if (ret)
305 delegate_ = delegate;
306 return ret;
307 } else {
308 NOTREACHED();
309 return false;
311 return true;
314 void PreparePageDCForPrinting(HDC, float scale_factor) {
315 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
316 // Setup the matrix to translate and scale to the right place. Take in
317 // account the scale factor.
318 // Note that the printing output is relative to printable area of
319 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
320 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
321 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
322 XFORM xform = {0};
323 xform.eDx = static_cast<float>(-offset_x);
324 xform.eDy = static_cast<float>(-offset_y);
325 xform.eM11 = xform.eM22 = 1.0f / scale_factor;
326 SetWorldTransform(printer_dc_.Get(), &xform);
329 // ServiceUtilityProcessHost::Client implementation.
330 void OnRenderPDFPagesToMetafilePageDone(
331 float scale_factor,
332 const printing::MetafilePlayer& emf) override {
333 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
334 ::StartPage(printer_dc_.Get());
335 emf.SafePlayback(printer_dc_.Get());
336 ::EndPage(printer_dc_.Get());
339 // ServiceUtilityProcessHost::Client implementation.
340 void OnRenderPDFPagesToMetafileDone(bool success) override {
341 PrintJobDone(success);
344 void OnChildDied() override { PrintJobDone(false); }
346 // base::win::ObjectWatcher::Delegate implementation.
347 void OnObjectSignaled(HANDLE object) override {
348 DCHECK(xps_print_job_.get());
349 DCHECK(object == job_progress_event_.Get());
350 ResetEvent(job_progress_event_.Get());
351 if (!delegate_)
352 return;
353 XPS_JOB_STATUS job_status = {0};
354 xps_print_job_->GetJobStatus(&job_status);
355 if ((job_status.completion == XPS_JOB_CANCELLED) ||
356 (job_status.completion == XPS_JOB_FAILED)) {
357 delegate_->OnJobSpoolFailed();
358 } else if (job_status.jobId ||
359 (job_status.completion == XPS_JOB_COMPLETED)) {
360 // Note: In the case of the XPS document being printed to the
361 // Microsoft XPS Document Writer, it seems to skip spooling the job
362 // and goes to the completed state without ever assigning a job id.
363 delegate_->OnJobSpoolSucceeded(job_status.jobId);
364 } else {
365 job_progress_watcher_.StopWatching();
366 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
370 private:
371 ~Core() override {}
373 // Helper class to allow PrintXPSDocument() to have multiple exits.
374 class PrintJobCanceler {
375 public:
376 explicit PrintJobCanceler(
377 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
378 : job_ptr_(job_ptr) {
380 ~PrintJobCanceler() {
381 if (job_ptr_ && job_ptr_->get()) {
382 (*job_ptr_)->Cancel();
383 job_ptr_->Release();
387 void reset() { job_ptr_ = NULL; }
389 private:
390 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
392 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
395 void PrintJobDone(bool success) {
396 // If there is no delegate, then there is nothing pending to process.
397 if (!delegate_)
398 return;
399 RestoreDC(printer_dc_.Get(), saved_dc_);
400 EndDoc(printer_dc_.Get());
401 if (success) {
402 delegate_->OnJobSpoolSucceeded(job_id_);
403 } else {
404 delegate_->OnJobSpoolFailed();
406 delegate_ = NULL;
409 void RenderPDFPages() {
410 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
411 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
412 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
413 gfx::Rect render_area(0, 0, dc_width, dc_height);
414 g_service_process->io_thread()->task_runner()->PostTask(
415 FROM_HERE,
416 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this,
417 print_data_file_path_, render_area, printer_dpi,
418 base::ThreadTaskRunnerHandle::Get()));
421 // Called on the service process IO thread.
422 void RenderPDFPagesInSandbox(
423 const base::FilePath& pdf_path,
424 const gfx::Rect& render_area,
425 int render_dpi,
426 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
427 DCHECK(g_service_process->io_thread()
428 ->task_runner()
429 ->BelongsToCurrentThread());
430 scoped_ptr<ServiceUtilityProcessHost> utility_host(
431 new ServiceUtilityProcessHost(this, client_task_runner.get()));
432 // TODO(gene): For now we disabling autorotation for CloudPrinting.
433 // Landscape/Portrait setting is passed in the print ticket and
434 // server is generating portrait PDF always.
435 // We should enable autorotation once server will be able to generate
436 // PDF that matches paper size and orientation.
437 if (utility_host->StartRenderPDFPagesToMetafile(
438 pdf_path,
439 printing::PdfRenderSettings(render_area, render_dpi, false))) {
440 // The object will self-destruct when the child process dies.
441 utility_host.release();
442 } else {
443 client_task_runner->PostTask(
444 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
448 bool PrintXPSDocument(const std::string& printer_name,
449 const std::string& job_title,
450 const base::FilePath& print_data_file_path,
451 const std::string& print_ticket) {
452 if (!printing::XPSPrintModule::Init())
453 return false;
455 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
456 if (!job_progress_event_.Get())
457 return false;
459 PrintJobCanceler job_canceler(&xps_print_job_);
460 base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
461 base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
462 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
463 base::UTF8ToWide(printer_name).c_str(),
464 base::UTF8ToWide(job_title).c_str(),
465 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
466 xps_print_job_.Receive(), doc_stream.Receive(),
467 print_ticket_stream.Receive())))
468 return false;
470 ULONG print_bytes_written = 0;
471 if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
472 print_ticket.length(),
473 &print_bytes_written)))
474 return false;
475 DCHECK_EQ(print_ticket.length(), print_bytes_written);
476 if (FAILED(print_ticket_stream->Close()))
477 return false;
479 std::string document_data;
480 base::ReadFileToString(print_data_file_path, &document_data);
481 ULONG doc_bytes_written = 0;
482 if (FAILED(doc_stream->Write(document_data.c_str(),
483 document_data.length(),
484 &doc_bytes_written)))
485 return false;
486 DCHECK_EQ(document_data.length(), doc_bytes_written);
487 if (FAILED(doc_stream->Close()))
488 return false;
490 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
491 job_canceler.reset();
492 return true;
495 PlatformJobId job_id_;
496 PrintSystem::JobSpooler::Delegate* delegate_;
497 int saved_dc_;
498 base::win::ScopedCreateDC printer_dc_;
499 base::FilePath print_data_file_path_;
500 base::win::ScopedHandle job_progress_event_;
501 base::win::ObjectWatcher job_progress_watcher_;
502 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
504 DISALLOW_COPY_AND_ASSIGN(Core);
506 scoped_refptr<Core> core_;
508 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
511 // A helper class to handle the response from the utility process to the
512 // request to fetch printer capabilities and defaults.
513 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
514 public:
515 PrinterCapsHandler(
516 const std::string& printer_name,
517 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
518 : printer_name_(printer_name), callback_(callback) {
521 // ServiceUtilityProcessHost::Client implementation.
522 void OnChildDied() override {
523 OnGetPrinterCapsAndDefaults(false, printer_name_,
524 printing::PrinterCapsAndDefaults());
527 void OnGetPrinterCapsAndDefaults(
528 bool succeeded,
529 const std::string& printer_name,
530 const printing::PrinterCapsAndDefaults& caps_and_defaults) override {
531 callback_.Run(succeeded, printer_name, caps_and_defaults);
532 callback_.Reset();
533 Release();
536 void OnGetPrinterSemanticCapsAndDefaults(
537 bool succeeded,
538 const std::string& printer_name,
539 const printing::PrinterSemanticCapsAndDefaults& semantic_info) override {
540 printing::PrinterCapsAndDefaults printer_info;
541 if (succeeded) {
542 printer_info.caps_mime_type = kContentTypeJSON;
543 scoped_ptr<base::DictionaryValue> description(
544 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
545 if (description) {
546 base::JSONWriter::WriteWithOptions(
547 *description, base::JSONWriter::OPTIONS_PRETTY_PRINT,
548 &printer_info.printer_capabilities);
551 callback_.Run(succeeded, printer_name, printer_info);
552 callback_.Reset();
553 Release();
556 void StartGetPrinterCapsAndDefaults() {
557 g_service_process->io_thread()->task_runner()->PostTask(
558 FROM_HERE,
559 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
560 base::ThreadTaskRunnerHandle::Get()));
563 void StartGetPrinterSemanticCapsAndDefaults() {
564 g_service_process->io_thread()->task_runner()->PostTask(
565 FROM_HERE,
566 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
567 this, base::ThreadTaskRunnerHandle::Get()));
570 private:
571 ~PrinterCapsHandler() override {}
573 void GetPrinterCapsAndDefaultsImpl(
574 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
575 DCHECK(g_service_process->io_thread()
576 ->task_runner()
577 ->BelongsToCurrentThread());
578 scoped_ptr<ServiceUtilityProcessHost> utility_host(
579 new ServiceUtilityProcessHost(this, client_task_runner.get()));
580 if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
581 // The object will self-destruct when the child process dies.
582 utility_host.release();
583 } else {
584 client_task_runner->PostTask(
585 FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
589 void GetPrinterSemanticCapsAndDefaultsImpl(
590 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
591 DCHECK(g_service_process->io_thread()
592 ->task_runner()
593 ->BelongsToCurrentThread());
594 scoped_ptr<ServiceUtilityProcessHost> utility_host(
595 new ServiceUtilityProcessHost(this, client_task_runner.get()));
596 if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
597 // The object will self-destruct when the child process dies.
598 utility_host.release();
599 } else {
600 client_task_runner->PostTask(
601 FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
605 std::string printer_name_;
606 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
609 class PrintSystemWin : public PrintSystem {
610 public:
611 PrintSystemWin();
613 // PrintSystem implementation.
614 PrintSystemResult Init() override;
615 PrintSystem::PrintSystemResult EnumeratePrinters(
616 printing::PrinterList* printer_list) override;
617 void GetPrinterCapsAndDefaults(
618 const std::string& printer_name,
619 const PrinterCapsAndDefaultsCallback& callback) override;
620 bool IsValidPrinter(const std::string& printer_name) override;
621 bool ValidatePrintTicket(
622 const std::string& printer_name,
623 const std::string& print_ticket_data,
624 const std::string& print_ticket_data_mime_type) override;
625 bool GetJobDetails(const std::string& printer_name,
626 PlatformJobId job_id,
627 PrintJobDetails* job_details) override;
628 PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() override;
629 PrintSystem::PrinterWatcher* CreatePrinterWatcher(
630 const std::string& printer_name) override;
631 PrintSystem::JobSpooler* CreateJobSpooler() override;
632 bool UseCddAndCjt() override;
633 std::string GetSupportedMimeTypes() override;
635 private:
636 ~PrintSystemWin() override {}
638 std::string PrintSystemWin::GetPrinterDriverInfo(
639 const std::string& printer_name) const;
641 scoped_refptr<printing::PrintBackend> print_backend_;
642 bool use_cdd_;
643 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
646 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
647 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
650 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
651 use_cdd_ = !base::CommandLine::ForCurrentProcess()->HasSwitch(
652 switches::kEnableCloudPrintXps);
654 if (!use_cdd_)
655 use_cdd_ = !printing::XPSModule::Init();
657 if (!use_cdd_) {
658 HPTPROVIDER provider = NULL;
659 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
660 if (provider)
661 printing::XPSModule::CloseProvider(provider);
662 // Use cdd if error is different from expected.
663 use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
666 return PrintSystemResult(true, std::string());
669 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
670 printing::PrinterList* printer_list) {
671 bool ret = print_backend_->EnumeratePrinters(printer_list);
672 return PrintSystemResult(ret, std::string());
675 void PrintSystemWin::GetPrinterCapsAndDefaults(
676 const std::string& printer_name,
677 const PrinterCapsAndDefaultsCallback& callback) {
678 // Launch as child process to retrieve the capabilities and defaults because
679 // this involves invoking a printer driver DLL and crashes have been known to
680 // occur.
681 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
682 handler->AddRef();
683 if (use_cdd_)
684 handler->StartGetPrinterSemanticCapsAndDefaults();
685 else
686 handler->StartGetPrinterCapsAndDefaults();
689 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
690 return print_backend_->IsValidPrinter(printer_name);
693 bool PrintSystemWin::ValidatePrintTicket(
694 const std::string& printer_name,
695 const std::string& print_ticket_data,
696 const std::string& print_ticket_data_mime_type) {
697 crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
699 if (use_cdd_) {
700 return print_ticket_data_mime_type == kContentTypeJSON &&
701 IsValidCjt(print_ticket_data);
703 DCHECK(print_ticket_data_mime_type == kContentTypeXML);
705 printing::ScopedXPSInitializer xps_initializer;
706 if (!xps_initializer.initialized()) {
707 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
708 return false;
710 bool ret = false;
711 HPTPROVIDER provider = NULL;
712 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
713 &provider);
714 if (provider) {
715 base::win::ScopedComPtr<IStream> print_ticket_stream;
716 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
717 ULONG bytes_written = 0;
718 print_ticket_stream->Write(print_ticket_data.c_str(),
719 print_ticket_data.length(),
720 &bytes_written);
721 DCHECK(bytes_written == print_ticket_data.length());
722 LARGE_INTEGER pos = {0};
723 ULARGE_INTEGER new_pos = {0};
724 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
725 base::win::ScopedBstr error;
726 base::win::ScopedComPtr<IStream> result_ticket_stream;
727 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
728 ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
729 provider,
730 print_ticket_stream.get(),
731 NULL,
732 kPTJobScope,
733 result_ticket_stream.get(),
734 error.Receive()));
735 printing::XPSModule::CloseProvider(provider);
737 return ret;
740 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
741 PlatformJobId job_id,
742 PrintJobDetails *job_details) {
743 crash_keys::ScopedPrinterInfo crash_key(
744 print_backend_->GetPrinterDriverInfo(printer_name));
745 DCHECK(job_details);
746 printing::ScopedPrinterHandle printer_handle;
747 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
748 printer_handle.OpenPrinter(printer_name_wide.c_str());
749 DCHECK(printer_handle.IsValid());
750 bool ret = false;
751 if (printer_handle.IsValid()) {
752 DWORD bytes_needed = 0;
753 GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
754 DWORD last_error = GetLastError();
755 if (ERROR_INVALID_PARAMETER != last_error) {
756 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
757 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
758 scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
759 if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
760 bytes_needed, &bytes_needed)) {
761 JOB_INFO_1 *job_info =
762 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
763 if (job_info->pStatus) {
764 base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
765 &job_details->status_message);
767 job_details->platform_status_flags = job_info->Status;
768 if ((job_info->Status & JOB_STATUS_COMPLETE) ||
769 (job_info->Status & JOB_STATUS_PRINTED)) {
770 job_details->status = PRINT_JOB_STATUS_COMPLETED;
771 } else if (job_info->Status & JOB_STATUS_ERROR) {
772 job_details->status = PRINT_JOB_STATUS_ERROR;
773 } else {
774 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
776 job_details->total_pages = job_info->TotalPages;
777 job_details->pages_printed = job_info->PagesPrinted;
778 ret = true;
782 return ret;
785 PrintSystem::PrintServerWatcher*
786 PrintSystemWin::CreatePrintServerWatcher() {
787 return new PrintServerWatcherWin();
790 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
791 const std::string& printer_name) {
792 DCHECK(!printer_name.empty());
793 return new PrinterWatcherWin(printer_name);
796 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
797 return new JobSpoolerWin();
800 bool PrintSystemWin::UseCddAndCjt() {
801 return use_cdd_;
804 std::string PrintSystemWin::GetSupportedMimeTypes() {
805 std::string result;
806 if (!use_cdd_) {
807 result = kContentTypeXPS;
808 result += ",";
810 result += kContentTypePDF;
811 return result;
814 std::string PrintSystemWin::GetPrinterDriverInfo(
815 const std::string& printer_name) const {
816 return print_backend_->GetPrinterDriverInfo(printer_name);
819 } // namespace
821 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
822 const base::DictionaryValue* print_system_settings) {
823 return new PrintSystemWin;
826 } // namespace cloud_print