Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / service / cloud_print / print_system_win.cc
blob30fb0b48523b560b3ce3ada8e036de2bd5183a86
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/win/object_watcher.h"
13 #include "base/win/scoped_bstr.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_hdc.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
18 #include "chrome/common/cloud_print/cloud_print_constants.h"
19 #include "chrome/common/crash_keys.h"
20 #include "chrome/service/cloud_print/cdd_conversion_win.h"
21 #include "chrome/service/service_process.h"
22 #include "chrome/service/service_utility_process_host.h"
23 #include "printing/backend/win_helper.h"
24 #include "printing/emf_win.h"
25 #include "printing/page_range.h"
26 #include "printing/pdf_render_settings.h"
27 #include "printing/printing_utils.h"
28 #include "ui/gfx/geometry/rect.h"
30 namespace cloud_print {
32 namespace {
34 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate {
35 public:
36 PrintSystemWatcherWin()
37 : delegate_(NULL),
38 did_signal_(false) {
40 ~PrintSystemWatcherWin() {
41 Stop();
44 class Delegate {
45 public:
46 virtual ~Delegate() {}
47 virtual void OnPrinterAdded() = 0;
48 virtual void OnPrinterDeleted() = 0;
49 virtual void OnPrinterChanged() = 0;
50 virtual void OnJobChanged() = 0;
53 bool Start(const std::string& printer_name, Delegate* delegate) {
54 scoped_refptr<printing::PrintBackend> print_backend(
55 printing::PrintBackend::CreateInstance(NULL));
56 printer_info_ = print_backend->GetPrinterDriverInfo(printer_name);
57 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
59 delegate_ = delegate;
60 // An empty printer name means watch the current server, we need to pass
61 // NULL to OpenPrinter.
62 LPTSTR printer_name_to_use = NULL;
63 std::wstring printer_name_wide;
64 if (!printer_name.empty()) {
65 printer_name_wide = base::UTF8ToWide(printer_name);
66 printer_name_to_use = const_cast<LPTSTR>(printer_name_wide.c_str());
68 bool ret = false;
69 if (printer_.OpenPrinter(printer_name_to_use)) {
70 printer_change_.Set(FindFirstPrinterChangeNotification(
71 printer_.Get(), PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB, 0, NULL));
72 if (printer_change_.IsValid()) {
73 ret = watcher_.StartWatching(printer_change_.Get(), this);
76 if (!ret) {
77 Stop();
79 return ret;
82 bool Stop() {
83 watcher_.StopWatching();
84 printer_.Close();
85 printer_change_.Close();
86 return true;
89 // base::ObjectWatcher::Delegate method
90 virtual void OnObjectSignaled(HANDLE object) {
91 crash_keys::ScopedPrinterInfo crash_key(printer_info_);
92 DWORD change = 0;
93 FindNextPrinterChangeNotification(object, &change, NULL, NULL);
95 if (change != ((PRINTER_CHANGE_PRINTER|PRINTER_CHANGE_JOB) &
96 (~PRINTER_CHANGE_FAILED_CONNECTION_PRINTER))) {
97 // For printer connections, we get spurious change notifications with
98 // all flags set except PRINTER_CHANGE_FAILED_CONNECTION_PRINTER.
99 // Ignore these.
100 if (change & PRINTER_CHANGE_ADD_PRINTER) {
101 delegate_->OnPrinterAdded();
102 } else if (change & PRINTER_CHANGE_DELETE_PRINTER) {
103 delegate_->OnPrinterDeleted();
104 } else if (change & PRINTER_CHANGE_SET_PRINTER) {
105 delegate_->OnPrinterChanged();
107 if (change & PRINTER_CHANGE_JOB) {
108 delegate_->OnJobChanged();
111 watcher_.StartWatching(printer_change_.Get(), this);
114 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
115 DCHECK(printer_info);
116 return InitBasicPrinterInfo(printer_.Get(), printer_info);
119 private:
120 base::win::ObjectWatcher watcher_;
121 printing::ScopedPrinterHandle printer_; // The printer being watched
122 // Returned by FindFirstPrinterChangeNotifier.
123 printing::ScopedPrinterChangeHandle printer_change_;
124 Delegate* delegate_; // Delegate to notify
125 bool did_signal_; // DoneWaiting was called
126 std::string printer_info_; // For crash reporting.
129 class PrintServerWatcherWin
130 : public PrintSystem::PrintServerWatcher,
131 public PrintSystemWatcherWin::Delegate {
132 public:
133 PrintServerWatcherWin() : delegate_(NULL) {}
135 // PrintSystem::PrintServerWatcher implementation.
136 virtual bool StartWatching(
137 PrintSystem::PrintServerWatcher::Delegate* delegate) override{
138 delegate_ = delegate;
139 return watcher_.Start(std::string(), this);
142 virtual bool StopWatching() override{
143 bool ret = watcher_.Stop();
144 delegate_ = NULL;
145 return ret;
148 // PrintSystemWatcherWin::Delegate implementation.
149 virtual void OnPrinterAdded() override {
150 delegate_->OnPrinterAdded();
152 virtual void OnPrinterDeleted() override {}
153 virtual void OnPrinterChanged() override {}
154 virtual void OnJobChanged() override {}
156 protected:
157 virtual ~PrintServerWatcherWin() {}
159 private:
160 PrintSystem::PrintServerWatcher::Delegate* delegate_;
161 PrintSystemWatcherWin watcher_;
163 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherWin);
166 class PrinterWatcherWin
167 : public PrintSystem::PrinterWatcher,
168 public PrintSystemWatcherWin::Delegate {
169 public:
170 explicit PrinterWatcherWin(const std::string& printer_name)
171 : printer_name_(printer_name),
172 delegate_(NULL) {
175 // PrintSystem::PrinterWatcher implementation.
176 virtual bool StartWatching(
177 PrintSystem::PrinterWatcher::Delegate* delegate) override {
178 delegate_ = delegate;
179 return watcher_.Start(printer_name_, this);
182 virtual bool StopWatching() override {
183 bool ret = watcher_.Stop();
184 delegate_ = NULL;
185 return ret;
188 virtual bool GetCurrentPrinterInfo(
189 printing::PrinterBasicInfo* printer_info) override {
190 return watcher_.GetCurrentPrinterInfo(printer_info);
193 // PrintSystemWatcherWin::Delegate implementation.
194 virtual void OnPrinterAdded() override {
195 NOTREACHED();
197 virtual void OnPrinterDeleted() override {
198 delegate_->OnPrinterDeleted();
200 virtual void OnPrinterChanged() override {
201 delegate_->OnPrinterChanged();
203 virtual void OnJobChanged() override {
204 delegate_->OnJobChanged();
207 protected:
208 virtual ~PrinterWatcherWin() {}
210 private:
211 std::string printer_name_;
212 PrintSystem::PrinterWatcher::Delegate* delegate_;
213 PrintSystemWatcherWin watcher_;
215 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherWin);
218 class JobSpoolerWin : public PrintSystem::JobSpooler {
219 public:
220 JobSpoolerWin() : core_(new Core) {}
222 // PrintSystem::JobSpooler implementation.
223 virtual bool Spool(const std::string& print_ticket,
224 const std::string& print_ticket_mime_type,
225 const base::FilePath& print_data_file_path,
226 const std::string& print_data_mime_type,
227 const std::string& printer_name,
228 const std::string& job_title,
229 const std::vector<std::string>& tags,
230 JobSpooler::Delegate* delegate) override {
231 // TODO(gene): add tags handling.
232 scoped_refptr<printing::PrintBackend> print_backend(
233 printing::PrintBackend::CreateInstance(NULL));
234 crash_keys::ScopedPrinterInfo crash_key(
235 print_backend->GetPrinterDriverInfo(printer_name));
236 return core_->Spool(print_ticket, print_ticket_mime_type,
237 print_data_file_path, print_data_mime_type,
238 printer_name, job_title, delegate);
241 protected:
242 virtual ~JobSpoolerWin() {}
244 private:
245 // We use a Core class because we want a separate RefCountedThreadSafe
246 // implementation for ServiceUtilityProcessHost::Client.
247 class Core : public ServiceUtilityProcessHost::Client,
248 public base::win::ObjectWatcher::Delegate {
249 public:
250 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {}
252 ~Core() {}
254 bool Spool(const std::string& print_ticket,
255 const std::string& print_ticket_mime_type,
256 const base::FilePath& print_data_file_path,
257 const std::string& print_data_mime_type,
258 const std::string& printer_name,
259 const std::string& job_title,
260 JobSpooler::Delegate* delegate) {
261 if (delegate_) {
262 // We are already in the process of printing.
263 NOTREACHED();
264 return false;
266 base::string16 printer_wide = base::UTF8ToWide(printer_name);
267 // We only support PDF and XPS documents for now.
268 if (print_data_mime_type == kContentTypePDF) {
269 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode;
270 if (print_ticket_mime_type == kContentTypeJSON) {
271 dev_mode = CjtToDevMode(printer_wide, print_ticket);
272 } else {
273 DCHECK(print_ticket_mime_type == kContentTypeXML);
274 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket);
277 if (!dev_mode) {
278 NOTREACHED();
279 return false;
282 HDC dc = CreateDC(L"WINSPOOL", printer_wide.c_str(), NULL,
283 dev_mode.get());
284 if (!dc) {
285 NOTREACHED();
286 return false;
288 DOCINFO di = {0};
289 di.cbSize = sizeof(DOCINFO);
290 base::string16 doc_name = base::UTF8ToUTF16(job_title);
291 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name);
292 di.lpszDocName = doc_name.c_str();
293 job_id_ = StartDoc(dc, &di);
294 if (job_id_ <= 0)
295 return false;
297 printer_dc_.Set(dc);
298 saved_dc_ = SaveDC(printer_dc_.Get());
299 print_data_file_path_ = print_data_file_path;
300 delegate_ = delegate;
301 RenderPDFPages();
302 } else if (print_data_mime_type == kContentTypeXPS) {
303 DCHECK(print_ticket_mime_type == kContentTypeXML);
304 bool ret = PrintXPSDocument(printer_name,
305 job_title,
306 print_data_file_path,
307 print_ticket);
308 if (ret)
309 delegate_ = delegate;
310 return ret;
311 } else {
312 NOTREACHED();
313 return false;
315 return true;
318 void PreparePageDCForPrinting(HDC, float scale_factor) {
319 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
320 // Setup the matrix to translate and scale to the right place. Take in
321 // account the scale factor.
322 // Note that the printing output is relative to printable area of
323 // the page. That is 0,0 is offset by PHYSICALOFFSETX/Y from the page.
324 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX);
325 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY);
326 XFORM xform = {0};
327 xform.eDx = static_cast<float>(-offset_x);
328 xform.eDy = static_cast<float>(-offset_y);
329 xform.eM11 = xform.eM22 = 1.0f / scale_factor;
330 SetWorldTransform(printer_dc_.Get(), &xform);
333 // ServiceUtilityProcessHost::Client implementation.
334 virtual void OnRenderPDFPagesToMetafilePageDone(
335 float scale_factor,
336 const printing::MetafilePlayer& emf) override {
337 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor);
338 ::StartPage(printer_dc_.Get());
339 emf.SafePlayback(printer_dc_.Get());
340 ::EndPage(printer_dc_.Get());
343 // ServiceUtilityProcessHost::Client implementation.
344 virtual void OnRenderPDFPagesToMetafileDone(bool success) override {
345 PrintJobDone(success);
348 virtual void OnChildDied() override { PrintJobDone(false); }
350 // base::win::ObjectWatcher::Delegate implementation.
351 virtual void OnObjectSignaled(HANDLE object) override {
352 DCHECK(xps_print_job_.get());
353 DCHECK(object == job_progress_event_.Get());
354 ResetEvent(job_progress_event_.Get());
355 if (!delegate_)
356 return;
357 XPS_JOB_STATUS job_status = {0};
358 xps_print_job_->GetJobStatus(&job_status);
359 if ((job_status.completion == XPS_JOB_CANCELLED) ||
360 (job_status.completion == XPS_JOB_FAILED)) {
361 delegate_->OnJobSpoolFailed();
362 } else if (job_status.jobId ||
363 (job_status.completion == XPS_JOB_COMPLETED)) {
364 // Note: In the case of the XPS document being printed to the
365 // Microsoft XPS Document Writer, it seems to skip spooling the job
366 // and goes to the completed state without ever assigning a job id.
367 delegate_->OnJobSpoolSucceeded(job_status.jobId);
368 } else {
369 job_progress_watcher_.StopWatching();
370 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
374 private:
375 // Helper class to allow PrintXPSDocument() to have multiple exits.
376 class PrintJobCanceler {
377 public:
378 explicit PrintJobCanceler(
379 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr)
380 : job_ptr_(job_ptr) {
382 ~PrintJobCanceler() {
383 if (job_ptr_ && job_ptr_->get()) {
384 (*job_ptr_)->Cancel();
385 job_ptr_->Release();
389 void reset() { job_ptr_ = NULL; }
391 private:
392 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_;
394 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler);
397 void PrintJobDone(bool success) {
398 // If there is no delegate, then there is nothing pending to process.
399 if (!delegate_)
400 return;
401 RestoreDC(printer_dc_.Get(), saved_dc_);
402 EndDoc(printer_dc_.Get());
403 if (success) {
404 delegate_->OnJobSpoolSucceeded(job_id_);
405 } else {
406 delegate_->OnJobSpoolFailed();
408 delegate_ = NULL;
411 void RenderPDFPages() {
412 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
413 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
414 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
415 gfx::Rect render_area(0, 0, dc_width, dc_height);
416 g_service_process->io_thread()->message_loop_proxy()->PostTask(
417 FROM_HERE,
418 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox,
419 this,
420 print_data_file_path_,
421 render_area,
422 printer_dpi,
423 base::MessageLoopProxy::current()));
426 // Called on the service process IO thread.
427 void RenderPDFPagesInSandbox(const base::FilePath& pdf_path,
428 const gfx::Rect& render_area,
429 int render_dpi,
430 const scoped_refptr<base::MessageLoopProxy>&
431 client_message_loop_proxy) {
432 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
433 BelongsToCurrentThread());
434 scoped_ptr<ServiceUtilityProcessHost> utility_host(
435 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
436 // TODO(gene): For now we disabling autorotation for CloudPrinting.
437 // Landscape/Portrait setting is passed in the print ticket and
438 // server is generating portrait PDF always.
439 // We should enable autorotation once server will be able to generate
440 // PDF that matches paper size and orientation.
441 if (utility_host->StartRenderPDFPagesToMetafile(
442 pdf_path,
443 printing::PdfRenderSettings(render_area, render_dpi, false))) {
444 // The object will self-destruct when the child process dies.
445 utility_host.release();
446 } else {
447 client_message_loop_proxy->PostTask(
448 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
452 bool PrintXPSDocument(const std::string& printer_name,
453 const std::string& job_title,
454 const base::FilePath& print_data_file_path,
455 const std::string& print_ticket) {
456 if (!printing::XPSPrintModule::Init())
457 return false;
459 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
460 if (!job_progress_event_.Get())
461 return false;
463 PrintJobCanceler job_canceler(&xps_print_job_);
464 base::win::ScopedComPtr<IXpsPrintJobStream> doc_stream;
465 base::win::ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
466 if (FAILED(printing::XPSPrintModule::StartXpsPrintJob(
467 base::UTF8ToWide(printer_name).c_str(),
468 base::UTF8ToWide(job_title).c_str(),
469 NULL, job_progress_event_.Get(), NULL, NULL, NULL,
470 xps_print_job_.Receive(), doc_stream.Receive(),
471 print_ticket_stream.Receive())))
472 return false;
474 ULONG print_bytes_written = 0;
475 if (FAILED(print_ticket_stream->Write(print_ticket.c_str(),
476 print_ticket.length(),
477 &print_bytes_written)))
478 return false;
479 DCHECK_EQ(print_ticket.length(), print_bytes_written);
480 if (FAILED(print_ticket_stream->Close()))
481 return false;
483 std::string document_data;
484 base::ReadFileToString(print_data_file_path, &document_data);
485 ULONG doc_bytes_written = 0;
486 if (FAILED(doc_stream->Write(document_data.c_str(),
487 document_data.length(),
488 &doc_bytes_written)))
489 return false;
490 DCHECK_EQ(document_data.length(), doc_bytes_written);
491 if (FAILED(doc_stream->Close()))
492 return false;
494 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
495 job_canceler.reset();
496 return true;
499 PlatformJobId job_id_;
500 PrintSystem::JobSpooler::Delegate* delegate_;
501 int saved_dc_;
502 base::win::ScopedCreateDC printer_dc_;
503 base::FilePath print_data_file_path_;
504 base::win::ScopedHandle job_progress_event_;
505 base::win::ObjectWatcher job_progress_watcher_;
506 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_;
508 DISALLOW_COPY_AND_ASSIGN(Core);
510 scoped_refptr<Core> core_;
512 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
515 // A helper class to handle the response from the utility process to the
516 // request to fetch printer capabilities and defaults.
517 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
518 public:
519 PrinterCapsHandler(
520 const std::string& printer_name,
521 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)
522 : printer_name_(printer_name), callback_(callback) {
525 // ServiceUtilityProcessHost::Client implementation.
526 virtual void OnChildDied() override {
527 OnGetPrinterCapsAndDefaults(false, printer_name_,
528 printing::PrinterCapsAndDefaults());
531 virtual void OnGetPrinterCapsAndDefaults(
532 bool succeeded,
533 const std::string& printer_name,
534 const printing::PrinterCapsAndDefaults& caps_and_defaults) override {
535 callback_.Run(succeeded, printer_name, caps_and_defaults);
536 callback_.Reset();
537 Release();
540 virtual void OnGetPrinterSemanticCapsAndDefaults(
541 bool succeeded,
542 const std::string& printer_name,
543 const printing::PrinterSemanticCapsAndDefaults& semantic_info) override {
544 printing::PrinterCapsAndDefaults printer_info;
545 if (succeeded) {
546 printer_info.caps_mime_type = kContentTypeJSON;
547 scoped_ptr<base::DictionaryValue> description(
548 PrinterSemanticCapsAndDefaultsToCdd(semantic_info));
549 if (description) {
550 base::JSONWriter::WriteWithOptions(
551 description.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT,
552 &printer_info.printer_capabilities);
555 callback_.Run(succeeded, printer_name, printer_info);
556 callback_.Reset();
557 Release();
560 void StartGetPrinterCapsAndDefaults() {
561 g_service_process->io_thread()->message_loop_proxy()->PostTask(
562 FROM_HERE,
563 base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
564 base::MessageLoopProxy::current()));
567 void StartGetPrinterSemanticCapsAndDefaults() {
568 g_service_process->io_thread()->message_loop_proxy()->PostTask(
569 FROM_HERE,
570 base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
571 this, base::MessageLoopProxy::current()));
574 private:
575 void GetPrinterCapsAndDefaultsImpl(
576 const scoped_refptr<base::MessageLoopProxy>&
577 client_message_loop_proxy) {
578 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
579 BelongsToCurrentThread());
580 scoped_ptr<ServiceUtilityProcessHost> utility_host(
581 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
582 if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
583 // The object will self-destruct when the child process dies.
584 utility_host.release();
585 } else {
586 client_message_loop_proxy->PostTask(
587 FROM_HERE,
588 base::Bind(&PrinterCapsHandler::OnChildDied, this));
592 void GetPrinterSemanticCapsAndDefaultsImpl(
593 const scoped_refptr<base::MessageLoopProxy>&
594 client_message_loop_proxy) {
595 DCHECK(g_service_process->io_thread()->message_loop_proxy()->
596 BelongsToCurrentThread());
597 scoped_ptr<ServiceUtilityProcessHost> utility_host(
598 new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
599 if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
600 // The object will self-destruct when the child process dies.
601 utility_host.release();
602 } else {
603 client_message_loop_proxy->PostTask(
604 FROM_HERE,
605 base::Bind(&PrinterCapsHandler::OnChildDied, this));
609 std::string printer_name_;
610 PrintSystem::PrinterCapsAndDefaultsCallback callback_;
613 class PrintSystemWin : public PrintSystem {
614 public:
615 PrintSystemWin();
617 // PrintSystem implementation.
618 virtual PrintSystemResult Init() override;
619 virtual PrintSystem::PrintSystemResult EnumeratePrinters(
620 printing::PrinterList* printer_list) override;
621 virtual void GetPrinterCapsAndDefaults(
622 const std::string& printer_name,
623 const PrinterCapsAndDefaultsCallback& callback) override;
624 virtual bool IsValidPrinter(const std::string& printer_name) override;
625 virtual bool ValidatePrintTicket(
626 const std::string& printer_name,
627 const std::string& print_ticket_data,
628 const std::string& print_ticket_data_mime_type) override;
629 virtual bool GetJobDetails(const std::string& printer_name,
630 PlatformJobId job_id,
631 PrintJobDetails *job_details) override;
632 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher() override;
633 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
634 const std::string& printer_name) override;
635 virtual PrintSystem::JobSpooler* CreateJobSpooler() override;
636 virtual bool UseCddAndCjt() override;
637 virtual std::string GetSupportedMimeTypes() override;
639 private:
640 std::string PrintSystemWin::GetPrinterDriverInfo(
641 const std::string& printer_name) const;
643 scoped_refptr<printing::PrintBackend> print_backend_;
644 bool use_cdd_;
645 DISALLOW_COPY_AND_ASSIGN(PrintSystemWin);
648 PrintSystemWin::PrintSystemWin() : use_cdd_(true) {
649 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
652 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
653 use_cdd_ = !base::CommandLine::ForCurrentProcess()->HasSwitch(
654 switches::kEnableCloudPrintXps);
656 if (!use_cdd_)
657 use_cdd_ = !printing::XPSModule::Init();
659 if (!use_cdd_) {
660 HPTPROVIDER provider = NULL;
661 HRESULT hr = printing::XPSModule::OpenProvider(L"", 1, &provider);
662 if (provider)
663 printing::XPSModule::CloseProvider(provider);
664 // Use cdd if error is different from expected.
665 use_cdd_ = (hr != HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME));
668 return PrintSystemResult(true, std::string());
671 PrintSystem::PrintSystemResult PrintSystemWin::EnumeratePrinters(
672 printing::PrinterList* printer_list) {
673 bool ret = print_backend_->EnumeratePrinters(printer_list);
674 return PrintSystemResult(ret, std::string());
677 void PrintSystemWin::GetPrinterCapsAndDefaults(
678 const std::string& printer_name,
679 const PrinterCapsAndDefaultsCallback& callback) {
680 // Launch as child process to retrieve the capabilities and defaults because
681 // this involves invoking a printer driver DLL and crashes have been known to
682 // occur.
683 PrinterCapsHandler* handler = new PrinterCapsHandler(printer_name, callback);
684 handler->AddRef();
685 if (use_cdd_)
686 handler->StartGetPrinterSemanticCapsAndDefaults();
687 else
688 handler->StartGetPrinterCapsAndDefaults();
691 bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) {
692 return print_backend_->IsValidPrinter(printer_name);
695 bool PrintSystemWin::ValidatePrintTicket(
696 const std::string& printer_name,
697 const std::string& print_ticket_data,
698 const std::string& print_ticket_data_mime_type) {
699 crash_keys::ScopedPrinterInfo crash_key(GetPrinterDriverInfo(printer_name));
701 if (use_cdd_) {
702 return print_ticket_data_mime_type == kContentTypeJSON &&
703 IsValidCjt(print_ticket_data);
705 DCHECK(print_ticket_data_mime_type == kContentTypeXML);
707 printing::ScopedXPSInitializer xps_initializer;
708 if (!xps_initializer.initialized()) {
709 // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
710 return false;
712 bool ret = false;
713 HPTPROVIDER provider = NULL;
714 printing::XPSModule::OpenProvider(base::UTF8ToWide(printer_name), 1,
715 &provider);
716 if (provider) {
717 base::win::ScopedComPtr<IStream> print_ticket_stream;
718 CreateStreamOnHGlobal(NULL, TRUE, print_ticket_stream.Receive());
719 ULONG bytes_written = 0;
720 print_ticket_stream->Write(print_ticket_data.c_str(),
721 print_ticket_data.length(),
722 &bytes_written);
723 DCHECK(bytes_written == print_ticket_data.length());
724 LARGE_INTEGER pos = {0};
725 ULARGE_INTEGER new_pos = {0};
726 print_ticket_stream->Seek(pos, STREAM_SEEK_SET, &new_pos);
727 base::win::ScopedBstr error;
728 base::win::ScopedComPtr<IStream> result_ticket_stream;
729 CreateStreamOnHGlobal(NULL, TRUE, result_ticket_stream.Receive());
730 ret = SUCCEEDED(printing::XPSModule::MergeAndValidatePrintTicket(
731 provider,
732 print_ticket_stream.get(),
733 NULL,
734 kPTJobScope,
735 result_ticket_stream.get(),
736 error.Receive()));
737 printing::XPSModule::CloseProvider(provider);
739 return ret;
742 bool PrintSystemWin::GetJobDetails(const std::string& printer_name,
743 PlatformJobId job_id,
744 PrintJobDetails *job_details) {
745 crash_keys::ScopedPrinterInfo crash_key(
746 print_backend_->GetPrinterDriverInfo(printer_name));
747 DCHECK(job_details);
748 printing::ScopedPrinterHandle printer_handle;
749 std::wstring printer_name_wide = base::UTF8ToWide(printer_name);
750 printer_handle.OpenPrinter(printer_name_wide.c_str());
751 DCHECK(printer_handle.IsValid());
752 bool ret = false;
753 if (printer_handle.IsValid()) {
754 DWORD bytes_needed = 0;
755 GetJob(printer_handle.Get(), job_id, 1, NULL, 0, &bytes_needed);
756 DWORD last_error = GetLastError();
757 if (ERROR_INVALID_PARAMETER != last_error) {
758 // ERROR_INVALID_PARAMETER normally means that the job id is not valid.
759 DCHECK(last_error == ERROR_INSUFFICIENT_BUFFER);
760 scoped_ptr<BYTE[]> job_info_buffer(new BYTE[bytes_needed]);
761 if (GetJob(printer_handle.Get(), job_id, 1, job_info_buffer.get(),
762 bytes_needed, &bytes_needed)) {
763 JOB_INFO_1 *job_info =
764 reinterpret_cast<JOB_INFO_1 *>(job_info_buffer.get());
765 if (job_info->pStatus) {
766 base::WideToUTF8(job_info->pStatus, wcslen(job_info->pStatus),
767 &job_details->status_message);
769 job_details->platform_status_flags = job_info->Status;
770 if ((job_info->Status & JOB_STATUS_COMPLETE) ||
771 (job_info->Status & JOB_STATUS_PRINTED)) {
772 job_details->status = PRINT_JOB_STATUS_COMPLETED;
773 } else if (job_info->Status & JOB_STATUS_ERROR) {
774 job_details->status = PRINT_JOB_STATUS_ERROR;
775 } else {
776 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
778 job_details->total_pages = job_info->TotalPages;
779 job_details->pages_printed = job_info->PagesPrinted;
780 ret = true;
784 return ret;
787 PrintSystem::PrintServerWatcher*
788 PrintSystemWin::CreatePrintServerWatcher() {
789 return new PrintServerWatcherWin();
792 PrintSystem::PrinterWatcher* PrintSystemWin::CreatePrinterWatcher(
793 const std::string& printer_name) {
794 DCHECK(!printer_name.empty());
795 return new PrinterWatcherWin(printer_name);
798 PrintSystem::JobSpooler* PrintSystemWin::CreateJobSpooler() {
799 return new JobSpoolerWin();
802 bool PrintSystemWin::UseCddAndCjt() {
803 return use_cdd_;
806 std::string PrintSystemWin::GetSupportedMimeTypes() {
807 std::string result;
808 if (!use_cdd_) {
809 result = kContentTypeXPS;
810 result += ",";
812 result += kContentTypePDF;
813 return result;
816 std::string PrintSystemWin::GetPrinterDriverInfo(
817 const std::string& printer_name) const {
818 return print_backend_->GetPrinterDriverInfo(printer_name);
821 } // namespace
823 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
824 const base::DictionaryValue* print_system_settings) {
825 return new PrintSystemWin;
828 } // namespace cloud_print