diff options
author | Ben Murdoch <benm@google.com> | 2010-07-29 17:14:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-04 14:29:45 +0100 |
commit | c407dc5cd9bdc5668497f21b26b09d988ab439de (patch) | |
tree | 7eaf8707c0309516bdb042ad976feedaf72b0bb1 /chrome/browser/printing/print_job_worker.cc | |
parent | 0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff) | |
download | external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.zip external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.gz external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.bz2 |
Merge Chromium src@r53293
Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
Diffstat (limited to 'chrome/browser/printing/print_job_worker.cc')
-rw-r--r-- | chrome/browser/printing/print_job_worker.cc | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc new file mode 100644 index 0000000..3a9ae03 --- /dev/null +++ b/chrome/browser/printing/print_job_worker.cc @@ -0,0 +1,328 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/printing/print_job_worker.h" + +#include "base/message_loop.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/printing/print_job.h" +#include "chrome/common/notification_service.h" +#include "printing/printed_document.h" +#include "printing/printed_page.h" + +namespace printing { + +class PrintJobWorker::NotificationTask : public Task { + public: + NotificationTask() : print_job_(NULL), details_(NULL) { + } + ~NotificationTask() { + } + + // Initializes the object. This object can't be initialized in the constructor + // since it is not created directly. + void Init(PrintJobWorkerOwner* print_job, + JobEventDetails::Type detail_type, + PrintedDocument* document, + PrintedPage* page) { + DCHECK(!print_job_); + DCHECK(!details_); + print_job_ = print_job; + details_ = new JobEventDetails(detail_type, document, page); + } + + virtual void Run() { + // Send the notification in the right thread. + NotificationService::current()->Notify( + NotificationType::PRINT_JOB_EVENT, + // We know that is is a PrintJob object in this circumstance. + Source<PrintJob>(static_cast<PrintJob*>(print_job_.get())), + Details<JobEventDetails>(details_)); + } + + // The job which originates this notification. + scoped_refptr<PrintJobWorkerOwner> print_job_; + scoped_refptr<JobEventDetails> details_; +}; + + +PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner) + : Thread("Printing_Worker"), + owner_(owner) { + // The object is created in the IO thread. + DCHECK_EQ(owner_->message_loop(), MessageLoop::current()); +} + +PrintJobWorker::~PrintJobWorker() { + // The object is deleted in the UI thread. + DCHECK_EQ(owner_->message_loop(), MessageLoop::current()); +} + +void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { + DCHECK(page_number_ == PageNumber::npos()); + owner_ = new_owner; +} + +void PrintJobWorker::GetSettings(bool ask_user_for_settings, + gfx::NativeView parent_view, + int document_page_count, + bool has_selection, + bool use_overlays) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(page_number_, PageNumber::npos()); + + // Recursive task processing is needed for the dialog in case it needs to be + // destroyed by a task. + MessageLoop::current()->SetNestableTasksAllowed(true); + printing_context_.SetUseOverlays(use_overlays); + + if (ask_user_for_settings) { +#if defined(OS_MACOSX) + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &PrintJobWorker::GetSettingsWithUI, + parent_view, document_page_count, + has_selection)); +#else + PrintingContext::Result result = printing_context_.AskUserForSettings( + parent_view, document_page_count, has_selection); + GetSettingsDone(result); +#endif + } else { + PrintingContext::Result result = printing_context_.UseDefaultSettings(); + GetSettingsDone(result); + } +} + +void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) { + // Most PrintingContext functions may start a message loop and process + // message recursively, so disable recursive task processing. + MessageLoop::current()->SetNestableTasksAllowed(false); + + // We can't use OnFailure() here since owner_ may not support notifications. + + // PrintJob will create the new PrintedDocument. + owner_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + owner_, + &PrintJobWorkerOwner::GetSettingsDone, + printing_context_.settings(), + result)); +} + +#if defined(OS_MACOSX) +void PrintJobWorker::GetSettingsWithUI(gfx::NativeView parent_view, + int document_page_count, + bool has_selection) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + PrintingContext::Result result = printing_context_.AskUserForSettings( + parent_view, document_page_count, has_selection); + message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &PrintJobWorker::GetSettingsDone, result)); +} +#endif + +void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(page_number_, PageNumber::npos()); + DCHECK_EQ(document_, new_document); + DCHECK(document_.get()); + DCHECK(new_document->settings().Equals(printing_context_.settings())); +#if !defined(OS_MACOSX) + DCHECK(printing_context_.context()); +#endif + if (!document_.get() || page_number_ != PageNumber::npos() || + document_ != new_document) { + return; + } + + PrintingContext::Result result = + printing_context_.NewDocument(document_->name()); + if (result != PrintingContext::OK) { + OnFailure(); + return; + } + + // Try to print already cached data. It may already have been generated for + // the print preview. + OnNewPage(); + // Don't touch this anymore since the instance could be destroyed. It happens + // if all the pages are printed a one sweep and the client doesn't have a + // handle to us anymore. There's a timing issue involved between the worker + // thread and the UI thread. Take no chance. +} + +void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(page_number_, PageNumber::npos()); + DCHECK(!new_document || + new_document->settings().Equals(printing_context_.settings())); +#if !defined(OS_MACOSX) + DCHECK(printing_context_.context()); +#endif + if (page_number_ != PageNumber::npos()) + return; + + document_ = new_document; +} + +void PrintJobWorker::OnNewPage() { + if (!document_.get()) { + // Spurious message. + return; + } + // message_loop() could return NULL when the print job is cancelled. + DCHECK_EQ(message_loop(), MessageLoop::current()); +#if !defined(OS_MACOSX) + DCHECK(printing_context_.context()); + if (!printing_context_.context()) + return; +#endif + + if (page_number_ == PageNumber::npos()) { + // Find first page to print. + int page_count = document_->page_count(); + if (!page_count) { + // We still don't know how many pages the document contains. We can't + // start to print the document yet since the header/footer may refer to + // the document's page count. + return; + } + // We have enough information to initialize page_number_. + page_number_.Init(document_->settings(), page_count); + } + DCHECK_NE(page_number_, PageNumber::npos()); + + for (;;) { + // Is the page available? + scoped_refptr<PrintedPage> page; + if (!document_->GetPage(page_number_.ToInt(), &page)) { + // We need to wait for the page to be available. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + NewRunnableMethod(this, &PrintJobWorker::OnNewPage), + 500); + break; + } + // The page is there, print it. + SpoolPage(*page); + ++page_number_; + if (page_number_ == PageNumber::npos()) { + OnDocumentDone(); + // Don't touch this anymore since the instance could be destroyed. + break; + } + } +} + +void PrintJobWorker::Cancel() { + // This is the only function that can be called from any thread. + printing_context_.Cancel(); + // Cannot touch any member variable since we don't know in which thread + // context we run. +} + +void PrintJobWorker::DismissDialog() { + printing_context_.DismissDialog(); +} + +void PrintJobWorker::OnDocumentDone() { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_EQ(page_number_, PageNumber::npos()); + DCHECK(document_.get()); +#if !defined(OS_MACOSX) + DCHECK(printing_context_.context()); +#endif + + if (printing_context_.DocumentDone() != PrintingContext::OK) { + OnFailure(); + return; + } + + // Tell everyone! + NotificationTask* task = new NotificationTask(); + task->Init(owner_, + JobEventDetails::DOC_DONE, + document_.get(), + NULL); + owner_->message_loop()->PostTask(FROM_HERE, task); + + // Makes sure the variables are reinitialized. + document_ = NULL; +} + +void PrintJobWorker::SpoolPage(PrintedPage& page) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + DCHECK_NE(page_number_, PageNumber::npos()); +#if !defined(OS_MACOSX) + DCHECK(printing_context_.context()); +#endif + // Signal everyone that the page is about to be printed. + NotificationTask* task = new NotificationTask(); + task->Init(owner_, + JobEventDetails::NEW_PAGE, + document_.get(), + &page); + owner_->message_loop()->PostTask(FROM_HERE, task); + + // Preprocess. + if (printing_context_.NewPage() != PrintingContext::OK) { + OnFailure(); + return; + } + +#if defined(OS_MACOSX) + // Context is only valid between NewPage and PageDone, so we only check here. + DCHECK(printing_context_.context()); +#endif + // Actual printing. + document_->RenderPrintedPage(page, printing_context_.context()); + + // Postprocess. + if (printing_context_.PageDone() != PrintingContext::OK) { + OnFailure(); + return; + } + + // Signal everyone that the page is printed. + task = new NotificationTask(); + task->Init(owner_, + JobEventDetails::PAGE_DONE, + document_.get(), + &page); + owner_->message_loop()->PostTask(FROM_HERE, task); +} + +void PrintJobWorker::OnFailure() { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // We may loose our last reference by broadcasting the FAILED event. + scoped_refptr<PrintJobWorkerOwner> handle(owner_); + + NotificationTask* task = new NotificationTask(); + task->Init(owner_, + JobEventDetails::FAILED, + document_.get(), + NULL); + owner_->message_loop()->PostTask(FROM_HERE, task); + Cancel(); + + // Makes sure the variables are reinitialized. + document_ = NULL; + page_number_ = PageNumber::npos(); +} + +} // namespace printing + +void RunnableMethodTraits<printing::PrintJobWorker>::RetainCallee( + printing::PrintJobWorker* obj) { + DCHECK(!owner_.get()); + owner_ = obj->owner_; +} + +void RunnableMethodTraits<printing::PrintJobWorker>::ReleaseCallee( + printing::PrintJobWorker* obj) { + DCHECK_EQ(owner_, obj->owner_); + owner_ = NULL; +} |