Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |