Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: chrome/service/cloud_print/print_system_win.cc

Issue 6523040: Added support to the Windows cloud print proxy to print XPS documents directl... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fixed cleanup code Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/service/cloud_print/print_system.h" 5 #include "chrome/service/cloud_print/print_system.h"
6 6
7 #include <objidl.h> 7 #include <objidl.h>
8 #include <winspool.h> 8 #include <winspool.h>
9 #if defined(_WIN32_WINNT)
10 #undef _WIN32_WINNT
11 #endif // defined(_WIN32_WINNT)
12 #define _WIN32_WINNT _WIN32_WINNT_WIN7
13 #include <xpsprint.h>
9 14
10 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/file_util.h"
11 #include "base/scoped_ptr.h" 17 #include "base/scoped_ptr.h"
12 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
13 #include "base/win/object_watcher.h" 19 #include "base/win/object_watcher.h"
14 #include "base/win/scoped_bstr.h" 20 #include "base/win/scoped_bstr.h"
15 #include "base/win/scoped_comptr.h" 21 #include "base/win/scoped_comptr.h"
16 #include "base/win/scoped_hdc.h" 22 #include "base/win/scoped_hdc.h"
17 #include "chrome/service/cloud_print/cloud_print_consts.h" 23 #include "chrome/service/cloud_print/cloud_print_consts.h"
18 #include "chrome/service/service_process.h" 24 #include "chrome/service/service_process.h"
19 #include "chrome/service/service_utility_process_host.h" 25 #include "chrome/service/service_utility_process_host.h"
20 #include "grit/generated_resources.h" 26 #include "grit/generated_resources.h"
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 const std::vector<std::string>& tags, 365 const std::vector<std::string>& tags,
360 JobSpooler::Delegate* delegate) { 366 JobSpooler::Delegate* delegate) {
361 // TODO(gene): add tags handling. 367 // TODO(gene): add tags handling.
362 return core_->Spool(print_ticket, print_data_file_path, 368 return core_->Spool(print_ticket, print_data_file_path,
363 print_data_mime_type, printer_name, job_title, 369 print_data_mime_type, printer_name, job_title,
364 delegate); 370 delegate);
365 } 371 }
366 private: 372 private:
367 // We use a Core class because we want a separate RefCountedThreadSafe 373 // We use a Core class because we want a separate RefCountedThreadSafe
368 // implementation for ServiceUtilityProcessHost::Client. 374 // implementation for ServiceUtilityProcessHost::Client.
369 class Core : public ServiceUtilityProcessHost::Client { 375 class Core : public ServiceUtilityProcessHost::Client,
376 public base::win::ObjectWatcher::Delegate {
370 public: 377 public:
371 Core() 378 Core()
372 : last_page_printed_(-1), job_id_(-1), delegate_(NULL), saved_dc_(0) { 379 : last_page_printed_(-1),
380 job_id_(-1),
381 delegate_(NULL),
382 saved_dc_(0),
383 should_couninit_(false) {
373 } 384 }
374 ~Core() { 385 ~Core() {
375 } 386 }
376 bool Spool(const std::string& print_ticket, 387 bool Spool(const std::string& print_ticket,
377 const FilePath& print_data_file_path, 388 const FilePath& print_data_file_path,
378 const std::string& print_data_mime_type, 389 const std::string& print_data_mime_type,
379 const std::string& printer_name, 390 const std::string& printer_name,
380 const std::string& job_title, 391 const std::string& job_title,
381 JobSpooler::Delegate* delegate) { 392 JobSpooler::Delegate* delegate) {
382 if (delegate_) { 393 if (delegate_) {
383 // We are already in the process of printing. 394 // We are already in the process of printing.
384 NOTREACHED(); 395 NOTREACHED();
385 return false; 396 return false;
386 } 397 }
387 last_page_printed_ = -1; 398 last_page_printed_ = -1;
388 // We only support PDFs for now. 399 // We only support PDF and XPS documents for now.
389 if (print_data_mime_type != "application/pdf") { 400 if (print_data_mime_type == "application/pdf") {
401 DevMode pt_dev_mode;
402 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket,
403 &pt_dev_mode);
404 if (FAILED(hr)) {
405 NOTREACHED();
406 return false;
407 }
408
409 HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(),
410 NULL, pt_dev_mode.dm_);
411 if (!dc) {
412 NOTREACHED();
413 return false;
414 }
415 hr = E_FAIL;
416 DOCINFO di = {0};
417 di.cbSize = sizeof(DOCINFO);
418 std::wstring doc_name = UTF8ToWide(job_title);
419 di.lpszDocName = doc_name.c_str();
420 job_id_ = StartDoc(dc, &di);
421 if (job_id_ <= 0)
422 return false;
423
424 printer_dc_.Set(dc);
425 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
426 saved_dc_ = SaveDC(printer_dc_.Get());
427 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
428 XFORM xform = {0};
429 xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) /
430 static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX));
431 ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY);
432 print_data_file_path_ = print_data_file_path;
433 delegate_ = delegate;
434 RenderNextPDFPages();
435 } else if (print_data_mime_type == "application/vnd.ms-xpsdocument") {
436 bool ret = PrintXPSDocument(printer_name,
437 job_title,
438 print_data_file_path,
439 print_ticket);
440 if (ret)
441 delegate_ = delegate;
442 return ret;
443 } else {
390 NOTREACHED(); 444 NOTREACHED();
391 return false; 445 return false;
392 } 446 }
393
394 DevMode pt_dev_mode;
395 HRESULT hr = PrintTicketToDevMode(printer_name, print_ticket,
396 &pt_dev_mode);
397 if (FAILED(hr)) {
398 NOTREACHED();
399 return false;
400 }
401
402 HDC dc = CreateDC(L"WINSPOOL", UTF8ToWide(printer_name).c_str(),
403 NULL, pt_dev_mode.dm_);
404 if (!dc) {
405 NOTREACHED();
406 return false;
407 }
408 hr = E_FAIL;
409 DOCINFO di = {0};
410 di.cbSize = sizeof(DOCINFO);
411 std::wstring doc_name = UTF8ToWide(job_title);
412 di.lpszDocName = doc_name.c_str();
413 job_id_ = StartDoc(dc, &di);
414 if (job_id_ <= 0)
415 return false;
416
417 printer_dc_.Set(dc);
418
419 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX);
420 saved_dc_ = SaveDC(printer_dc_.Get());
421 SetGraphicsMode(printer_dc_.Get(), GM_ADVANCED);
422 XFORM xform = {0};
423 xform.eM11 = xform.eM22 = static_cast<float>(printer_dpi) /
424 static_cast<float>(GetDeviceCaps(GetDC(NULL), LOGPIXELSX));
425 ModifyWorldTransform(printer_dc_.Get(), &xform, MWT_LEFTMULTIPLY);
426 print_data_file_path_ = print_data_file_path;
427 delegate_ = delegate;
428 RenderNextPDFPages();
429 return true; 447 return true;
430 } 448 }
431 449
432 // ServiceUtilityProcessHost::Client implementation. 450 // ServiceUtilityProcessHost::Client implementation.
433 virtual void OnRenderPDFPagesToMetafileSucceeded( 451 virtual void OnRenderPDFPagesToMetafileSucceeded(
434 const printing::NativeMetafile& metafile, 452 const printing::NativeMetafile& metafile,
435 int highest_rendered_page_number) { 453 int highest_rendered_page_number) {
436 metafile.SafePlayback(printer_dc_.Get()); 454 metafile.SafePlayback(printer_dc_.Get());
437 bool done_printing = (highest_rendered_page_number != 455 bool done_printing = (highest_rendered_page_number !=
438 last_page_printed_ + kPageCountPerBatch); 456 last_page_printed_ + kPageCountPerBatch);
439 last_page_printed_ = highest_rendered_page_number; 457 last_page_printed_ = highest_rendered_page_number;
440 if (done_printing) 458 if (done_printing)
441 PrintJobDone(); 459 PrintJobDone();
442 else 460 else
443 RenderNextPDFPages(); 461 RenderNextPDFPages();
444 } 462 }
463
464 // base::win::ObjectWatcher::Delegate inplementation.
465 virtual void OnObjectSignaled(HANDLE object) {
466 DCHECK(xps_print_job_);
467 if (!delegate_)
468 return;
469 XPS_JOB_STATUS job_status = {0};
470 xps_print_job_->GetJobStatus(&job_status);
471 bool done = false;
472 if ((job_status.completion == XPS_JOB_CANCELLED) ||
473 (job_status.completion == XPS_JOB_FAILED)) {
474 delegate_->OnJobSpoolFailed();
475 done = true;
476 } else if (job_status.jobId) {
477 delegate_->OnJobSpoolSucceeded(job_status.jobId);
478 done = true;
479 } else {
480 ResetEvent(job_progress_event_.Get());
481 job_progress_watcher_.StopWatching();
482 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this);
483 }
484 if (done && should_couninit_) {
485 CoUninitialize();
486 should_couninit_ = false;
487 }
488 }
489
445 virtual void OnRenderPDFPagesToMetafileFailed() { 490 virtual void OnRenderPDFPagesToMetafileFailed() {
446 PrintJobDone(); 491 PrintJobDone();
447 } 492 }
448 virtual void OnChildDied() { 493 virtual void OnChildDied() {
449 PrintJobDone(); 494 PrintJobDone();
450 } 495 }
451 private: 496 private:
452 void PrintJobDone() { 497 void PrintJobDone() {
453 // If there is no delegate, then there is nothing pending to process. 498 // If there is no delegate, then there is nothing pending to process.
454 if (!delegate_) 499 if (!delegate_)
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 scoped_ptr<ServiceUtilityProcessHost> utility_host( 541 scoped_ptr<ServiceUtilityProcessHost> utility_host(
497 new ServiceUtilityProcessHost(this, client_message_loop_proxy)); 542 new ServiceUtilityProcessHost(this, client_message_loop_proxy));
498 if (utility_host->StartRenderPDFPagesToMetafile(pdf_path, 543 if (utility_host->StartRenderPDFPagesToMetafile(pdf_path,
499 render_area, 544 render_area,
500 render_dpi, 545 render_dpi,
501 page_ranges)) { 546 page_ranges)) {
502 // The object will self-destruct when the child process dies. 547 // The object will self-destruct when the child process dies.
503 utility_host.release(); 548 utility_host.release();
504 } 549 }
505 } 550 }
551 bool PrintXPSDocument(const std::string& printer_name,
552 const std::string& job_title,
553 const FilePath& print_data_file_path,
554 const std::string& print_ticket) {
555 if (!printing::XPSPrintModule::Init())
556 return false;
557 job_progress_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
558 if (!job_progress_event_.Get())
559 return false;
560 should_couninit_ = SUCCEEDED(CoInitializeEx(NULL,
561 COINIT_MULTITHREADED));
562 ScopedComPtr<IXpsPrintJobStream> doc_stream;
563 ScopedComPtr<IXpsPrintJobStream> print_ticket_stream;
564 bool ret = false;
565 // Use nested SUCCEEDED checks because we want a common return point.
566 if (SUCCEEDED(printing::XPSPrintModule::StartXpsPrintJob(
567 UTF8ToWide(printer_name).c_str(),
568 UTF8ToWide(job_title).c_str(),
569 NULL,
570 job_progress_event_.Get(),
571 NULL,
572 NULL,
573 NULL,
574 xps_print_job_.Receive(),
575 doc_stream.Receive(),
576 print_ticket_stream.Receive()))) {
577 ULONG bytes_written = 0;
578 if (SUCCEEDED(print_ticket_stream->Write(print_ticket.c_str(),
579 print_ticket.length(),
580 &bytes_written))) {
581 DCHECK(bytes_written == print_ticket.length());
582 if (SUCCEEDED(print_ticket_stream->Close())) {
583 std::string document_data;
584 file_util::ReadFileToString(print_data_file_path, &document_data);
Scott Byer 2011/02/17 00:31:02 Does this function need to check that it's being c
sanjeevr 2011/02/17 00:53:52 This is the service process and not the browser pr
585 bytes_written = 0;
586 if (SUCCEEDED(doc_stream->Write(document_data.c_str(),
587 document_data.length(),
588 &bytes_written))) {
589 DCHECK(bytes_written == document_data.length());
590 if (SUCCEEDED(doc_stream->Close())) {
591 job_progress_watcher_.StartWatching(job_progress_event_.Get(),
592 this);
593 ret = true;
594 }
595 }
596 }
597 }
598 }
599 if (!ret) {
600 if (xps_print_job_) {
601 xps_print_job_->Cancel();
602 xps_print_job_.Release();
603 }
604 if (should_couninit_) {
605 CoUninitialize();
606 should_couninit_ = false;
607 }
608 }
609 return ret;
610 }
611
506 // Some Cairo-generated PDFs from Chrome OS result in huge metafiles. 612 // Some Cairo-generated PDFs from Chrome OS result in huge metafiles.
507 // So the PageCountPerBatch is set to 1 for now. 613 // So the PageCountPerBatch is set to 1 for now.
508 // TODO(sanjeevr): Figure out a smarter way to determine the pages per 614 // TODO(sanjeevr): Figure out a smarter way to determine the pages per
509 // batch. Filed a bug to track this at 615 // batch. Filed a bug to track this at
510 // http://code.google.com/p/chromium/issues/detail?id=57350. 616 // http://code.google.com/p/chromium/issues/detail?id=57350.
511 static const int kPageCountPerBatch = 1; 617 static const int kPageCountPerBatch = 1;
512 int last_page_printed_; 618 int last_page_printed_;
513 PlatformJobId job_id_; 619 PlatformJobId job_id_;
514 PrintSystem::JobSpooler::Delegate* delegate_; 620 PrintSystem::JobSpooler::Delegate* delegate_;
515 int saved_dc_; 621 int saved_dc_;
516 base::win::ScopedHDC printer_dc_; 622 base::win::ScopedHDC printer_dc_;
517 FilePath print_data_file_path_; 623 FilePath print_data_file_path_;
624 base::win::ScopedHandle job_progress_event_;
625 base::win::ObjectWatcher job_progress_watcher_;
626 ScopedComPtr<IXpsPrintJob> xps_print_job_;
627 bool should_couninit_;
518 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core); 628 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin::Core);
519 }; 629 };
520 scoped_refptr<Core> core_; 630 scoped_refptr<Core> core_;
521 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin); 631 DISALLOW_COPY_AND_ASSIGN(JobSpoolerWin);
522 }; 632 };
523 633
524 // A helper class to handle the response from the utility process to the 634 // A helper class to handle the response from the utility process to the
525 // request to fetch printer capabilities and defaults. 635 // request to fetch printer capabilities and defaults.
526 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client { 636 class PrinterCapsHandler : public ServiceUtilityProcessHost::Client {
527 public: 637 public:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 691
582 std::string printer_name_; 692 std::string printer_name_;
583 scoped_ptr<PrinterCapsAndDefaultsCallback> callback_; 693 scoped_ptr<PrinterCapsAndDefaultsCallback> callback_;
584 }; 694 };
585 695
586 696
587 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); 697 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
588 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( 698 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
589 const std::string& printer_name); 699 const std::string& printer_name);
590 virtual PrintSystem::JobSpooler* CreateJobSpooler(); 700 virtual PrintSystem::JobSpooler* CreateJobSpooler();
701 virtual std::string GetSupportedMimeTypes();
702
591 703
592 private: 704 private:
593 scoped_refptr<printing::PrintBackend> print_backend_; 705 scoped_refptr<printing::PrintBackend> print_backend_;
594 }; 706 };
595 707
596 PrintSystemWin::PrintSystemWin() { 708 PrintSystemWin::PrintSystemWin() {
597 print_backend_ = printing::PrintBackend::CreateInstance(NULL); 709 print_backend_ = printing::PrintBackend::CreateInstance(NULL);
598 } 710 }
599 711
600 PrintSystem::PrintSystemResult PrintSystemWin::Init() { 712 PrintSystem::PrintSystemResult PrintSystemWin::Init() {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 const std::string& printer_name) { 833 const std::string& printer_name) {
722 DCHECK(!printer_name.empty()); 834 DCHECK(!printer_name.empty());
723 return new PrinterWatcherWin(printer_name); 835 return new PrinterWatcherWin(printer_name);
724 } 836 }
725 837
726 PrintSystem::JobSpooler* 838 PrintSystem::JobSpooler*
727 PrintSystemWin::CreateJobSpooler() { 839 PrintSystemWin::CreateJobSpooler() {
728 return new JobSpoolerWin(); 840 return new JobSpoolerWin();
729 } 841 }
730 842
843 std::string PrintSystemWin::GetSupportedMimeTypes() {
844 if (printing::XPSPrintModule::Init())
845 return "application/vnd.ms-xpsdocument,application/pdf";
846 return "application/pdf";
847 }
848
849
731 std::string PrintSystem::GenerateProxyId() { 850 std::string PrintSystem::GenerateProxyId() {
732 GUID proxy_id = {0}; 851 GUID proxy_id = {0};
733 HRESULT hr = UuidCreate(&proxy_id); 852 HRESULT hr = UuidCreate(&proxy_id);
734 DCHECK(SUCCEEDED(hr)); 853 DCHECK(SUCCEEDED(hr));
735 wchar_t* proxy_id_as_string = NULL; 854 wchar_t* proxy_id_as_string = NULL;
736 UuidToString(&proxy_id, reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); 855 UuidToString(&proxy_id, reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string));
737 DCHECK(proxy_id_as_string); 856 DCHECK(proxy_id_as_string);
738 std::string ret; 857 std::string ret;
739 WideToUTF8(proxy_id_as_string, wcslen(proxy_id_as_string), &ret); 858 WideToUTF8(proxy_id_as_string, wcslen(proxy_id_as_string), &ret);
740 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string)); 859 RpcStringFree(reinterpret_cast<RPC_WSTR *>(&proxy_id_as_string));
741 return ret; 860 return ret;
742 } 861 }
743 862
744 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( 863 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
745 const DictionaryValue* print_system_settings) { 864 const DictionaryValue* print_system_settings) {
746 return new PrintSystemWin; 865 return new PrintSystemWin;
747 } 866 }
748 867
749 } // namespace cloud_print 868 } // namespace cloud_print
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698