OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/win/object_watcher.h" | 12 #include "base/win/object_watcher.h" |
13 #include "base/win/scoped_bstr.h" | 13 #include "base/win/scoped_bstr.h" |
14 #include "base/win/scoped_comptr.h" | 14 #include "base/win/scoped_comptr.h" |
15 #include "base/win/scoped_hdc.h" | 15 #include "base/win/scoped_hdc.h" |
16 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h" | 17 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h" |
18 #include "chrome/common/cloud_print/cloud_print_constants.h" | 18 #include "chrome/common/cloud_print/cloud_print_constants.h" |
19 #include "chrome/common/crash_keys.h" | 19 #include "chrome/common/crash_keys.h" |
20 #include "chrome/service/cloud_print/cdd_conversion_win.h" | 20 #include "chrome/service/cloud_print/cdd_conversion_win.h" |
21 #include "chrome/service/service_process.h" | 21 #include "chrome/service/service_process.h" |
22 #include "chrome/service/service_utility_process_host.h" | 22 #include "chrome/service/service_utility_process_host.h" |
23 #include "printing/backend/win_helper.h" | 23 #include "printing/backend/win_helper.h" |
24 #include "printing/emf_win.h" | 24 #include "printing/emf_win.h" |
25 #include "printing/page_range.h" | 25 #include "printing/page_range.h" |
| 26 #include "printing/pdf_render_settings.h" |
26 #include "printing/printing_utils.h" | 27 #include "printing/printing_utils.h" |
| 28 #include "ui/gfx/geometry/rect.h" |
27 | 29 |
28 namespace cloud_print { | 30 namespace cloud_print { |
29 | 31 |
30 namespace { | 32 namespace { |
31 | 33 |
32 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate { | 34 class PrintSystemWatcherWin : public base::win::ObjectWatcher::Delegate { |
33 public: | 35 public: |
34 PrintSystemWatcherWin() | 36 PrintSystemWatcherWin() |
35 : delegate_(NULL), | 37 : delegate_(NULL), |
36 did_signal_(false) { | 38 did_signal_(false) { |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 | 240 |
239 protected: | 241 protected: |
240 virtual ~JobSpoolerWin() {} | 242 virtual ~JobSpoolerWin() {} |
241 | 243 |
242 private: | 244 private: |
243 // We use a Core class because we want a separate RefCountedThreadSafe | 245 // We use a Core class because we want a separate RefCountedThreadSafe |
244 // implementation for ServiceUtilityProcessHost::Client. | 246 // implementation for ServiceUtilityProcessHost::Client. |
245 class Core : public ServiceUtilityProcessHost::Client, | 247 class Core : public ServiceUtilityProcessHost::Client, |
246 public base::win::ObjectWatcher::Delegate { | 248 public base::win::ObjectWatcher::Delegate { |
247 public: | 249 public: |
248 Core() | 250 Core() : job_id_(-1), delegate_(NULL), saved_dc_(0) {} |
249 : last_page_printed_(-1), | |
250 job_id_(-1), | |
251 delegate_(NULL), | |
252 saved_dc_(0) { | |
253 } | |
254 | 251 |
255 ~Core() {} | 252 ~Core() {} |
256 | 253 |
257 bool Spool(const std::string& print_ticket, | 254 bool Spool(const std::string& print_ticket, |
258 const std::string& print_ticket_mime_type, | 255 const std::string& print_ticket_mime_type, |
259 const base::FilePath& print_data_file_path, | 256 const base::FilePath& print_data_file_path, |
260 const std::string& print_data_mime_type, | 257 const std::string& print_data_mime_type, |
261 const std::string& printer_name, | 258 const std::string& printer_name, |
262 const std::string& job_title, | 259 const std::string& job_title, |
263 JobSpooler::Delegate* delegate) { | 260 JobSpooler::Delegate* delegate) { |
264 if (delegate_) { | 261 if (delegate_) { |
265 // We are already in the process of printing. | 262 // We are already in the process of printing. |
266 NOTREACHED(); | 263 NOTREACHED(); |
267 return false; | 264 return false; |
268 } | 265 } |
269 base::string16 printer_wide = base::UTF8ToWide(printer_name); | 266 base::string16 printer_wide = base::UTF8ToWide(printer_name); |
270 last_page_printed_ = -1; | |
271 // We only support PDF and XPS documents for now. | 267 // We only support PDF and XPS documents for now. |
272 if (print_data_mime_type == kContentTypePDF) { | 268 if (print_data_mime_type == kContentTypePDF) { |
273 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode; | 269 scoped_ptr<DEVMODE, base::FreeDeleter> dev_mode; |
274 if (print_ticket_mime_type == kContentTypeJSON) { | 270 if (print_ticket_mime_type == kContentTypeJSON) { |
275 dev_mode = CjtToDevMode(printer_wide, print_ticket); | 271 dev_mode = CjtToDevMode(printer_wide, print_ticket); |
276 } else { | 272 } else { |
277 DCHECK(print_ticket_mime_type == kContentTypeXML); | 273 DCHECK(print_ticket_mime_type == kContentTypeXML); |
278 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket); | 274 dev_mode = printing::XpsTicketToDevMode(printer_wide, print_ticket); |
279 } | 275 } |
280 | 276 |
(...skipping 14 matching lines...) Expand all Loading... |
295 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name); | 291 DCHECK(printing::SimplifyDocumentTitle(doc_name) == doc_name); |
296 di.lpszDocName = doc_name.c_str(); | 292 di.lpszDocName = doc_name.c_str(); |
297 job_id_ = StartDoc(dc, &di); | 293 job_id_ = StartDoc(dc, &di); |
298 if (job_id_ <= 0) | 294 if (job_id_ <= 0) |
299 return false; | 295 return false; |
300 | 296 |
301 printer_dc_.Set(dc); | 297 printer_dc_.Set(dc); |
302 saved_dc_ = SaveDC(printer_dc_.Get()); | 298 saved_dc_ = SaveDC(printer_dc_.Get()); |
303 print_data_file_path_ = print_data_file_path; | 299 print_data_file_path_ = print_data_file_path; |
304 delegate_ = delegate; | 300 delegate_ = delegate; |
305 RenderNextPDFPages(); | 301 RenderPDFPages(); |
306 } else if (print_data_mime_type == kContentTypeXPS) { | 302 } else if (print_data_mime_type == kContentTypeXPS) { |
307 DCHECK(print_ticket_mime_type == kContentTypeXML); | 303 DCHECK(print_ticket_mime_type == kContentTypeXML); |
308 bool ret = PrintXPSDocument(printer_name, | 304 bool ret = PrintXPSDocument(printer_name, |
309 job_title, | 305 job_title, |
310 print_data_file_path, | 306 print_data_file_path, |
311 print_ticket); | 307 print_ticket); |
312 if (ret) | 308 if (ret) |
313 delegate_ = delegate; | 309 delegate_ = delegate; |
314 return ret; | 310 return ret; |
315 } else { | 311 } else { |
(...skipping 12 matching lines...) Expand all Loading... |
328 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX); | 324 int offset_x = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETX); |
329 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY); | 325 int offset_y = ::GetDeviceCaps(printer_dc_.Get(), PHYSICALOFFSETY); |
330 XFORM xform = {0}; | 326 XFORM xform = {0}; |
331 xform.eDx = static_cast<float>(-offset_x); | 327 xform.eDx = static_cast<float>(-offset_x); |
332 xform.eDy = static_cast<float>(-offset_y); | 328 xform.eDy = static_cast<float>(-offset_y); |
333 xform.eM11 = xform.eM22 = 1.0 / scale_factor; | 329 xform.eM11 = xform.eM22 = 1.0 / scale_factor; |
334 SetWorldTransform(printer_dc_.Get(), &xform); | 330 SetWorldTransform(printer_dc_.Get(), &xform); |
335 } | 331 } |
336 | 332 |
337 // ServiceUtilityProcessHost::Client implementation. | 333 // ServiceUtilityProcessHost::Client implementation. |
338 virtual void OnRenderPDFPagesToMetafileSucceeded( | 334 virtual void OnRenderPDFPagesToMetafilePageDone( |
339 const printing::MetafilePlayer& metafile, | 335 double scale_factor, |
340 int highest_rendered_page_number, | 336 const printing::MetafilePlayer& emf) OVERRIDE { |
341 double scale_factor) OVERRIDE { | |
342 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor); | 337 PreparePageDCForPrinting(printer_dc_.Get(), scale_factor); |
343 metafile.SafePlayback(printer_dc_.Get()); | 338 emf.SafePlayback(printer_dc_.Get()); |
344 bool done_printing = (highest_rendered_page_number != | |
345 last_page_printed_ + kPageCountPerBatch); | |
346 last_page_printed_ = highest_rendered_page_number; | |
347 if (done_printing) | |
348 PrintJobDone(); | |
349 else | |
350 RenderNextPDFPages(); | |
351 } | 339 } |
352 | 340 |
| 341 // ServiceUtilityProcessHost::Client implementation. |
| 342 virtual void OnRenderPDFPagesToMetafileDone(bool success) OVERRIDE { |
| 343 PrintJobDone(success); |
| 344 } |
| 345 |
| 346 virtual void OnChildDied() OVERRIDE { PrintJobDone(false); } |
| 347 |
353 // base::win::ObjectWatcher::Delegate implementation. | 348 // base::win::ObjectWatcher::Delegate implementation. |
354 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { | 349 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { |
355 DCHECK(xps_print_job_); | 350 DCHECK(xps_print_job_); |
356 DCHECK(object == job_progress_event_.Get()); | 351 DCHECK(object == job_progress_event_.Get()); |
357 ResetEvent(job_progress_event_.Get()); | 352 ResetEvent(job_progress_event_.Get()); |
358 if (!delegate_) | 353 if (!delegate_) |
359 return; | 354 return; |
360 XPS_JOB_STATUS job_status = {0}; | 355 XPS_JOB_STATUS job_status = {0}; |
361 xps_print_job_->GetJobStatus(&job_status); | 356 xps_print_job_->GetJobStatus(&job_status); |
362 if ((job_status.completion == XPS_JOB_CANCELLED) || | 357 if ((job_status.completion == XPS_JOB_CANCELLED) || |
363 (job_status.completion == XPS_JOB_FAILED)) { | 358 (job_status.completion == XPS_JOB_FAILED)) { |
364 delegate_->OnJobSpoolFailed(); | 359 delegate_->OnJobSpoolFailed(); |
365 } else if (job_status.jobId || | 360 } else if (job_status.jobId || |
366 (job_status.completion == XPS_JOB_COMPLETED)) { | 361 (job_status.completion == XPS_JOB_COMPLETED)) { |
367 // Note: In the case of the XPS document being printed to the | 362 // Note: In the case of the XPS document being printed to the |
368 // Microsoft XPS Document Writer, it seems to skip spooling the job | 363 // Microsoft XPS Document Writer, it seems to skip spooling the job |
369 // and goes to the completed state without ever assigning a job id. | 364 // and goes to the completed state without ever assigning a job id. |
370 delegate_->OnJobSpoolSucceeded(job_status.jobId); | 365 delegate_->OnJobSpoolSucceeded(job_status.jobId); |
371 } else { | 366 } else { |
372 job_progress_watcher_.StopWatching(); | 367 job_progress_watcher_.StopWatching(); |
373 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); | 368 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); |
374 } | 369 } |
375 } | 370 } |
376 | 371 |
377 virtual void OnRenderPDFPagesToMetafileFailed() OVERRIDE { | |
378 PrintJobDone(); | |
379 } | |
380 | |
381 virtual void OnChildDied() OVERRIDE { | |
382 PrintJobDone(); | |
383 } | |
384 | |
385 private: | 372 private: |
386 // Helper class to allow PrintXPSDocument() to have multiple exits. | 373 // Helper class to allow PrintXPSDocument() to have multiple exits. |
387 class PrintJobCanceler { | 374 class PrintJobCanceler { |
388 public: | 375 public: |
389 explicit PrintJobCanceler( | 376 explicit PrintJobCanceler( |
390 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr) | 377 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr) |
391 : job_ptr_(job_ptr) { | 378 : job_ptr_(job_ptr) { |
392 } | 379 } |
393 ~PrintJobCanceler() { | 380 ~PrintJobCanceler() { |
394 if (job_ptr_ && *job_ptr_) { | 381 if (job_ptr_ && *job_ptr_) { |
395 (*job_ptr_)->Cancel(); | 382 (*job_ptr_)->Cancel(); |
396 job_ptr_->Release(); | 383 job_ptr_->Release(); |
397 } | 384 } |
398 } | 385 } |
399 | 386 |
400 void reset() { job_ptr_ = NULL; } | 387 void reset() { job_ptr_ = NULL; } |
401 | 388 |
402 private: | 389 private: |
403 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_; | 390 base::win::ScopedComPtr<IXpsPrintJob>* job_ptr_; |
404 | 391 |
405 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler); | 392 DISALLOW_COPY_AND_ASSIGN(PrintJobCanceler); |
406 }; | 393 }; |
407 | 394 |
408 void PrintJobDone() { | 395 void PrintJobDone(bool success) { |
409 // If there is no delegate, then there is nothing pending to process. | 396 // If there is no delegate, then there is nothing pending to process. |
410 if (!delegate_) | 397 if (!delegate_) |
411 return; | 398 return; |
412 RestoreDC(printer_dc_.Get(), saved_dc_); | 399 RestoreDC(printer_dc_.Get(), saved_dc_); |
413 EndDoc(printer_dc_.Get()); | 400 EndDoc(printer_dc_.Get()); |
414 if (-1 == last_page_printed_) { | 401 if (success) { |
| 402 delegate_->OnJobSpoolSucceeded(job_id_); |
| 403 } else { |
415 delegate_->OnJobSpoolFailed(); | 404 delegate_->OnJobSpoolFailed(); |
416 } else { | |
417 delegate_->OnJobSpoolSucceeded(job_id_); | |
418 } | 405 } |
419 delegate_ = NULL; | 406 delegate_ = NULL; |
420 } | 407 } |
421 | 408 |
422 void RenderNextPDFPages() { | 409 void RenderPDFPages() { |
423 printing::PageRange range; | |
424 // Render 10 pages at a time. | |
425 range.from = last_page_printed_ + 1; | |
426 range.to = last_page_printed_ + kPageCountPerBatch; | |
427 std::vector<printing::PageRange> page_ranges; | |
428 page_ranges.push_back(range); | |
429 | |
430 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); | 410 int printer_dpi = ::GetDeviceCaps(printer_dc_.Get(), LOGPIXELSX); |
431 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH); | 411 int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH); |
432 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT); | 412 int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT); |
433 gfx::Rect render_area(0, 0, dc_width, dc_height); | 413 gfx::Rect render_area(0, 0, dc_width, dc_height); |
434 g_service_process->io_thread()->message_loop_proxy()->PostTask( | 414 g_service_process->io_thread()->message_loop_proxy()->PostTask( |
435 FROM_HERE, | 415 FROM_HERE, |
436 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this, | 416 base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, |
437 print_data_file_path_, render_area, printer_dpi, | 417 this, |
438 page_ranges, base::MessageLoopProxy::current())); | 418 print_data_file_path_, |
| 419 render_area, |
| 420 printer_dpi, |
| 421 base::MessageLoopProxy::current())); |
439 } | 422 } |
440 | 423 |
441 // Called on the service process IO thread. | 424 // Called on the service process IO thread. |
442 void RenderPDFPagesInSandbox( | 425 void RenderPDFPagesInSandbox(const base::FilePath& pdf_path, |
443 const base::FilePath& pdf_path, const gfx::Rect& render_area, | 426 const gfx::Rect& render_area, |
444 int render_dpi, const std::vector<printing::PageRange>& page_ranges, | 427 int render_dpi, |
445 const scoped_refptr<base::MessageLoopProxy>& | 428 const scoped_refptr<base::MessageLoopProxy>& |
446 client_message_loop_proxy) { | 429 client_message_loop_proxy) { |
447 DCHECK(g_service_process->io_thread()->message_loop_proxy()-> | 430 DCHECK(g_service_process->io_thread()->message_loop_proxy()-> |
448 BelongsToCurrentThread()); | 431 BelongsToCurrentThread()); |
449 scoped_ptr<ServiceUtilityProcessHost> utility_host( | 432 scoped_ptr<ServiceUtilityProcessHost> utility_host( |
450 new ServiceUtilityProcessHost(this, client_message_loop_proxy)); | 433 new ServiceUtilityProcessHost(this, client_message_loop_proxy)); |
451 // TODO(gene): For now we disabling autorotation for CloudPrinting. | 434 // TODO(gene): For now we disabling autorotation for CloudPrinting. |
452 // Landscape/Portrait setting is passed in the print ticket and | 435 // Landscape/Portrait setting is passed in the print ticket and |
453 // server is generating portrait PDF always. | 436 // server is generating portrait PDF always. |
454 // We should enable autorotation once server will be able to generate | 437 // We should enable autorotation once server will be able to generate |
455 // PDF that matches paper size and orientation. | 438 // PDF that matches paper size and orientation. |
456 if (utility_host->StartRenderPDFPagesToMetafile( | 439 if (utility_host->StartRenderPDFPagesToMetafile( |
457 pdf_path, | 440 pdf_path, |
458 printing::PdfRenderSettings(render_area, render_dpi, false), | 441 printing::PdfRenderSettings(render_area, render_dpi, false))) { |
459 page_ranges)) { | |
460 // The object will self-destruct when the child process dies. | 442 // The object will self-destruct when the child process dies. |
461 utility_host.release(); | 443 utility_host.release(); |
| 444 } else { |
| 445 client_message_loop_proxy->PostTask( |
| 446 FROM_HERE, base::Bind(&Core::PrintJobDone, this, false)); |
462 } | 447 } |
463 } | 448 } |
464 | 449 |
465 bool PrintXPSDocument(const std::string& printer_name, | 450 bool PrintXPSDocument(const std::string& printer_name, |
466 const std::string& job_title, | 451 const std::string& job_title, |
467 const base::FilePath& print_data_file_path, | 452 const base::FilePath& print_data_file_path, |
468 const std::string& print_ticket) { | 453 const std::string& print_ticket) { |
469 if (!printing::XPSPrintModule::Init()) | 454 if (!printing::XPSPrintModule::Init()) |
470 return false; | 455 return false; |
471 | 456 |
(...skipping 30 matching lines...) Expand all Loading... |
502 return false; | 487 return false; |
503 DCHECK_EQ(document_data.length(), doc_bytes_written); | 488 DCHECK_EQ(document_data.length(), doc_bytes_written); |
504 if (FAILED(doc_stream->Close())) | 489 if (FAILED(doc_stream->Close())) |
505 return false; | 490 return false; |
506 | 491 |
507 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); | 492 job_progress_watcher_.StartWatching(job_progress_event_.Get(), this); |
508 job_canceler.reset(); | 493 job_canceler.reset(); |
509 return true; | 494 return true; |
510 } | 495 } |
511 | 496 |
512 // Some Cairo-generated PDFs from Chrome OS result in huge metafiles. | |
513 // So the PageCountPerBatch is set to 1 for now. | |
514 // TODO(sanjeevr): Figure out a smarter way to determine the pages per | |
515 // batch. Filed a bug to track this at | |
516 // http://code.google.com/p/chromium/issues/detail?id=57350. | |
517 static const int kPageCountPerBatch = 1; | |
518 | |
519 int last_page_printed_; | |
520 PlatformJobId job_id_; | 497 PlatformJobId job_id_; |
521 PrintSystem::JobSpooler::Delegate* delegate_; | 498 PrintSystem::JobSpooler::Delegate* delegate_; |
522 int saved_dc_; | 499 int saved_dc_; |
523 base::win::ScopedCreateDC printer_dc_; | 500 base::win::ScopedCreateDC printer_dc_; |
524 base::FilePath print_data_file_path_; | 501 base::FilePath print_data_file_path_; |
525 base::win::ScopedHandle job_progress_event_; | 502 base::win::ScopedHandle job_progress_event_; |
526 base::win::ObjectWatcher job_progress_watcher_; | 503 base::win::ObjectWatcher job_progress_watcher_; |
527 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_; | 504 base::win::ScopedComPtr<IXpsPrintJob> xps_print_job_; |
528 | 505 |
529 DISALLOW_COPY_AND_ASSIGN(Core); | 506 DISALLOW_COPY_AND_ASSIGN(Core); |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 } | 817 } |
841 | 818 |
842 } // namespace | 819 } // namespace |
843 | 820 |
844 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( | 821 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( |
845 const base::DictionaryValue* print_system_settings) { | 822 const base::DictionaryValue* print_system_settings) { |
846 return new PrintSystemWin; | 823 return new PrintSystemWin; |
847 } | 824 } |
848 | 825 |
849 } // namespace cloud_print | 826 } // namespace cloud_print |
OLD | NEW |