| 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/browser/printing/print_job.h" | 5 #include "chrome/browser/printing/print_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner, | 24 void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner, |
| 25 const base::Closure& callback) { | 25 const base::Closure& callback) { |
| 26 callback.Run(); | 26 callback.Run(); |
| 27 } | 27 } |
| 28 | 28 |
| 29 } // namespace | 29 } // namespace |
| 30 | 30 |
| 31 namespace printing { | 31 namespace printing { |
| 32 | 32 |
| 33 PrintJob::PrintJob() | 33 PrintJob::PrintJob() |
| 34 : ui_message_loop_(MessageLoop::current()), | 34 : ui_message_loop_(base::MessageLoop::current()), |
| 35 source_(NULL), | 35 source_(NULL), |
| 36 worker_(), | 36 worker_(), |
| 37 settings_(), | 37 settings_(), |
| 38 is_job_pending_(false), | 38 is_job_pending_(false), |
| 39 is_canceling_(false), | 39 is_canceling_(false), |
| 40 is_stopping_(false), | 40 is_stopping_(false), |
| 41 is_stopped_(false), | 41 is_stopped_(false), |
| 42 quit_factory_(this), | 42 quit_factory_(this), |
| 43 weak_ptr_factory_(this) { | 43 weak_ptr_factory_(this) { |
| 44 DCHECK(ui_message_loop_); | 44 DCHECK(ui_message_loop_); |
| 45 // This is normally a UI message loop, but in unit tests, the message loop is | 45 // This is normally a UI message loop, but in unit tests, the message loop is |
| 46 // of the 'default' type. | 46 // of the 'default' type. |
| 47 DCHECK(ui_message_loop_->type() == MessageLoop::TYPE_UI || | 47 DCHECK(ui_message_loop_->type() == base::MessageLoop::TYPE_UI || |
| 48 ui_message_loop_->type() == MessageLoop::TYPE_DEFAULT); | 48 ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT); |
| 49 ui_message_loop_->AddDestructionObserver(this); | 49 ui_message_loop_->AddDestructionObserver(this); |
| 50 } | 50 } |
| 51 | 51 |
| 52 PrintJob::~PrintJob() { | 52 PrintJob::~PrintJob() { |
| 53 ui_message_loop_->RemoveDestructionObserver(this); | 53 ui_message_loop_->RemoveDestructionObserver(this); |
| 54 // The job should be finished (or at least canceled) when it is destroyed. | 54 // The job should be finished (or at least canceled) when it is destroyed. |
| 55 DCHECK(!is_job_pending_); | 55 DCHECK(!is_job_pending_); |
| 56 DCHECK(!is_canceling_); | 56 DCHECK(!is_canceling_); |
| 57 if (worker_.get()) | 57 if (worker_.get()) |
| 58 DCHECK(worker_->message_loop() == NULL); | 58 DCHECK(worker_->message_loop() == NULL); |
| 59 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 59 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 60 } | 60 } |
| 61 | 61 |
| 62 void PrintJob::Initialize(PrintJobWorkerOwner* job, | 62 void PrintJob::Initialize(PrintJobWorkerOwner* job, |
| 63 PrintedPagesSource* source, | 63 PrintedPagesSource* source, |
| 64 int page_count) { | 64 int page_count) { |
| 65 DCHECK(!source_); | 65 DCHECK(!source_); |
| 66 DCHECK(!worker_.get()); | 66 DCHECK(!worker_.get()); |
| 67 DCHECK(!is_job_pending_); | 67 DCHECK(!is_job_pending_); |
| 68 DCHECK(!is_canceling_); | 68 DCHECK(!is_canceling_); |
| 69 DCHECK(!document_.get()); | 69 DCHECK(!document_.get()); |
| 70 source_ = source; | 70 source_ = source; |
| 71 worker_.reset(job->DetachWorker(this)); | 71 worker_.reset(job->DetachWorker(this)); |
| 72 settings_ = job->settings(); | 72 settings_ = job->settings(); |
| 73 | 73 |
| 74 PrintedDocument* new_doc = | 74 PrintedDocument* new_doc = |
| 75 new PrintedDocument(settings_, source_, job->cookie()); | 75 new PrintedDocument(settings_, source_, job->cookie()); |
| 76 new_doc->set_page_count(page_count); | 76 new_doc->set_page_count(page_count); |
| 77 UpdatePrintedDocument(new_doc); | 77 UpdatePrintedDocument(new_doc); |
| 78 | 78 |
| 79 // Don't forget to register to our own messages. | 79 // Don't forget to register to our own messages. |
| 80 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, | 80 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, |
| 81 content::Source<PrintJob>(this)); | 81 content::Source<PrintJob>(this)); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void PrintJob::Observe(int type, | 84 void PrintJob::Observe(int type, |
| 85 const content::NotificationSource& source, | 85 const content::NotificationSource& source, |
| 86 const content::NotificationDetails& details) { | 86 const content::NotificationDetails& details) { |
| 87 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 87 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 88 switch (type) { | 88 switch (type) { |
| 89 case chrome::NOTIFICATION_PRINT_JOB_EVENT: { | 89 case chrome::NOTIFICATION_PRINT_JOB_EVENT: { |
| 90 OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr()); | 90 OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr()); |
| 91 break; | 91 break; |
| 92 } | 92 } |
| 93 default: { | 93 default: { |
| 94 break; | 94 break; |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 } | 97 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 119 // Always use an invalid cookie in this case. | 119 // Always use an invalid cookie in this case. |
| 120 return 0; | 120 return 0; |
| 121 return document_->cookie(); | 121 return document_->cookie(); |
| 122 } | 122 } |
| 123 | 123 |
| 124 void PrintJob::WillDestroyCurrentMessageLoop() { | 124 void PrintJob::WillDestroyCurrentMessageLoop() { |
| 125 NOTREACHED(); | 125 NOTREACHED(); |
| 126 } | 126 } |
| 127 | 127 |
| 128 void PrintJob::StartPrinting() { | 128 void PrintJob::StartPrinting() { |
| 129 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 129 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 130 DCHECK(worker_->message_loop()); | 130 DCHECK(worker_->message_loop()); |
| 131 DCHECK(!is_job_pending_); | 131 DCHECK(!is_job_pending_); |
| 132 if (!worker_->message_loop() || is_job_pending_) | 132 if (!worker_->message_loop() || is_job_pending_) |
| 133 return; | 133 return; |
| 134 | 134 |
| 135 // Real work is done in PrintJobWorker::StartPrinting(). | 135 // Real work is done in PrintJobWorker::StartPrinting(). |
| 136 worker_->message_loop()->PostTask( | 136 worker_->message_loop()->PostTask( |
| 137 FROM_HERE, | 137 FROM_HERE, |
| 138 base::Bind(&HoldRefCallback, make_scoped_refptr(this), | 138 base::Bind(&HoldRefCallback, make_scoped_refptr(this), |
| 139 base::Bind(&PrintJobWorker::StartPrinting, | 139 base::Bind(&PrintJobWorker::StartPrinting, |
| 140 base::Unretained(worker_.get()), document_))); | 140 base::Unretained(worker_.get()), document_))); |
| 141 // Set the flag right now. | 141 // Set the flag right now. |
| 142 is_job_pending_ = true; | 142 is_job_pending_ = true; |
| 143 | 143 |
| 144 // Tell everyone! | 144 // Tell everyone! |
| 145 scoped_refptr<JobEventDetails> details( | 145 scoped_refptr<JobEventDetails> details( |
| 146 new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL)); | 146 new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL)); |
| 147 content::NotificationService::current()->Notify( | 147 content::NotificationService::current()->Notify( |
| 148 chrome::NOTIFICATION_PRINT_JOB_EVENT, | 148 chrome::NOTIFICATION_PRINT_JOB_EVENT, |
| 149 content::Source<PrintJob>(this), | 149 content::Source<PrintJob>(this), |
| 150 content::Details<JobEventDetails>(details.get())); | 150 content::Details<JobEventDetails>(details.get())); |
| 151 } | 151 } |
| 152 | 152 |
| 153 void PrintJob::Stop() { | 153 void PrintJob::Stop() { |
| 154 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 154 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 155 | 155 |
| 156 if (quit_factory_.HasWeakPtrs()) { | 156 if (quit_factory_.HasWeakPtrs()) { |
| 157 // In case we're running a nested message loop to wait for a job to finish, | 157 // In case we're running a nested message loop to wait for a job to finish, |
| 158 // and we finished before the timeout, quit the nested loop right away. | 158 // and we finished before the timeout, quit the nested loop right away. |
| 159 Quit(); | 159 Quit(); |
| 160 quit_factory_.InvalidateWeakPtrs(); | 160 quit_factory_.InvalidateWeakPtrs(); |
| 161 } | 161 } |
| 162 | 162 |
| 163 // Be sure to live long enough. | 163 // Be sure to live long enough. |
| 164 scoped_refptr<PrintJob> handle(this); | 164 scoped_refptr<PrintJob> handle(this); |
| 165 | 165 |
| 166 MessageLoop* worker_loop = worker_->message_loop(); | 166 base::MessageLoop* worker_loop = worker_->message_loop(); |
| 167 if (worker_loop) { | 167 if (worker_loop) { |
| 168 ControlledWorkerShutdown(); | 168 ControlledWorkerShutdown(); |
| 169 | 169 |
| 170 is_job_pending_ = false; | 170 is_job_pending_ = false; |
| 171 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, | 171 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, |
| 172 content::Source<PrintJob>(this)); | 172 content::Source<PrintJob>(this)); |
| 173 } | 173 } |
| 174 // Flush the cached document. | 174 // Flush the cached document. |
| 175 UpdatePrintedDocument(NULL); | 175 UpdatePrintedDocument(NULL); |
| 176 } | 176 } |
| 177 | 177 |
| 178 void PrintJob::Cancel() { | 178 void PrintJob::Cancel() { |
| 179 if (is_canceling_) | 179 if (is_canceling_) |
| 180 return; | 180 return; |
| 181 is_canceling_ = true; | 181 is_canceling_ = true; |
| 182 | 182 |
| 183 // Be sure to live long enough. | 183 // Be sure to live long enough. |
| 184 scoped_refptr<PrintJob> handle(this); | 184 scoped_refptr<PrintJob> handle(this); |
| 185 | 185 |
| 186 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 186 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 187 MessageLoop* worker_loop = worker_.get() ? worker_->message_loop() : NULL; | 187 base::MessageLoop* worker_loop = |
| 188 worker_.get() ? worker_->message_loop() : NULL; |
| 188 if (worker_loop) { | 189 if (worker_loop) { |
| 189 // Call this right now so it renders the context invalid. Do not use | 190 // Call this right now so it renders the context invalid. Do not use |
| 190 // InvokeLater since it would take too much time. | 191 // InvokeLater since it would take too much time. |
| 191 worker_->Cancel(); | 192 worker_->Cancel(); |
| 192 } | 193 } |
| 193 // Make sure a Cancel() is broadcast. | 194 // Make sure a Cancel() is broadcast. |
| 194 scoped_refptr<JobEventDetails> details( | 195 scoped_refptr<JobEventDetails> details( |
| 195 new JobEventDetails(JobEventDetails::FAILED, NULL, NULL)); | 196 new JobEventDetails(JobEventDetails::FAILED, NULL, NULL)); |
| 196 content::NotificationService::current()->Notify( | 197 content::NotificationService::current()->Notify( |
| 197 chrome::NOTIFICATION_PRINT_JOB_EVENT, | 198 chrome::NOTIFICATION_PRINT_JOB_EVENT, |
| 198 content::Source<PrintJob>(this), | 199 content::Source<PrintJob>(this), |
| 199 content::Details<JobEventDetails>(details.get())); | 200 content::Details<JobEventDetails>(details.get())); |
| 200 Stop(); | 201 Stop(); |
| 201 is_canceling_ = false; | 202 is_canceling_ = false; |
| 202 } | 203 } |
| 203 | 204 |
| 204 bool PrintJob::FlushJob(base::TimeDelta timeout) { | 205 bool PrintJob::FlushJob(base::TimeDelta timeout) { |
| 205 // Make sure the object outlive this message loop. | 206 // Make sure the object outlive this message loop. |
| 206 scoped_refptr<PrintJob> handle(this); | 207 scoped_refptr<PrintJob> handle(this); |
| 207 | 208 |
| 208 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 209 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 209 base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout); | 210 base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout); |
| 210 | 211 |
| 211 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); | 212 base::MessageLoop::ScopedNestableTaskAllower allow( |
| 212 MessageLoop::current()->Run(); | 213 base::MessageLoop::current()); |
| 214 base::MessageLoop::current()->Run(); |
| 213 | 215 |
| 214 return true; | 216 return true; |
| 215 } | 217 } |
| 216 | 218 |
| 217 void PrintJob::DisconnectSource() { | 219 void PrintJob::DisconnectSource() { |
| 218 source_ = NULL; | 220 source_ = NULL; |
| 219 if (document_.get()) | 221 if (document_.get()) |
| 220 document_->DisconnectSource(); | 222 document_->DisconnectSource(); |
| 221 } | 223 } |
| 222 | 224 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 case JobEventDetails::NEW_DOC: | 276 case JobEventDetails::NEW_DOC: |
| 275 case JobEventDetails::NEW_PAGE: | 277 case JobEventDetails::NEW_PAGE: |
| 276 case JobEventDetails::PAGE_DONE: | 278 case JobEventDetails::PAGE_DONE: |
| 277 case JobEventDetails::JOB_DONE: | 279 case JobEventDetails::JOB_DONE: |
| 278 case JobEventDetails::ALL_PAGES_REQUESTED: { | 280 case JobEventDetails::ALL_PAGES_REQUESTED: { |
| 279 // Don't care. | 281 // Don't care. |
| 280 break; | 282 break; |
| 281 } | 283 } |
| 282 case JobEventDetails::DOC_DONE: { | 284 case JobEventDetails::DOC_DONE: { |
| 283 // This will call Stop() and broadcast a JOB_DONE message. | 285 // This will call Stop() and broadcast a JOB_DONE message. |
| 284 MessageLoop::current()->PostTask( | 286 base::MessageLoop::current()->PostTask( |
| 285 FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this)); | 287 FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this)); |
| 286 break; | 288 break; |
| 287 } | 289 } |
| 288 default: { | 290 default: { |
| 289 NOTREACHED(); | 291 NOTREACHED(); |
| 290 break; | 292 break; |
| 291 } | 293 } |
| 292 } | 294 } |
| 293 } | 295 } |
| 294 | 296 |
| 295 void PrintJob::OnDocumentDone() { | 297 void PrintJob::OnDocumentDone() { |
| 296 // Be sure to live long enough. The instance could be destroyed by the | 298 // Be sure to live long enough. The instance could be destroyed by the |
| 297 // JOB_DONE broadcast. | 299 // JOB_DONE broadcast. |
| 298 scoped_refptr<PrintJob> handle(this); | 300 scoped_refptr<PrintJob> handle(this); |
| 299 | 301 |
| 300 // Stop the worker thread. | 302 // Stop the worker thread. |
| 301 Stop(); | 303 Stop(); |
| 302 | 304 |
| 303 scoped_refptr<JobEventDetails> details( | 305 scoped_refptr<JobEventDetails> details( |
| 304 new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL)); | 306 new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL)); |
| 305 content::NotificationService::current()->Notify( | 307 content::NotificationService::current()->Notify( |
| 306 chrome::NOTIFICATION_PRINT_JOB_EVENT, | 308 chrome::NOTIFICATION_PRINT_JOB_EVENT, |
| 307 content::Source<PrintJob>(this), | 309 content::Source<PrintJob>(this), |
| 308 content::Details<JobEventDetails>(details.get())); | 310 content::Details<JobEventDetails>(details.get())); |
| 309 } | 311 } |
| 310 | 312 |
| 311 void PrintJob::ControlledWorkerShutdown() { | 313 void PrintJob::ControlledWorkerShutdown() { |
| 312 DCHECK_EQ(ui_message_loop_, MessageLoop::current()); | 314 DCHECK_EQ(ui_message_loop_, base::MessageLoop::current()); |
| 313 | 315 |
| 314 // The deadlock this code works around is specific to window messaging on | 316 // The deadlock this code works around is specific to window messaging on |
| 315 // Windows, so we aren't likely to need it on any other platforms. | 317 // Windows, so we aren't likely to need it on any other platforms. |
| 316 #if defined(OS_WIN) | 318 #if defined(OS_WIN) |
| 317 // We could easily get into a deadlock case if worker_->Stop() is used; the | 319 // We could easily get into a deadlock case if worker_->Stop() is used; the |
| 318 // printer driver created a window as a child of the browser window. By | 320 // printer driver created a window as a child of the browser window. By |
| 319 // canceling the job, the printer driver initiated dialog box is destroyed, | 321 // canceling the job, the printer driver initiated dialog box is destroyed, |
| 320 // which sends a blocking message to its parent window. If the browser window | 322 // which sends a blocking message to its parent window. If the browser window |
| 321 // thread is not processing messages, a deadlock occurs. | 323 // thread is not processing messages, a deadlock occurs. |
| 322 // | 324 // |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 scoped_refptr<PrintJob>(this)), | 370 scoped_refptr<PrintJob>(this)), |
| 369 false); | 371 false); |
| 370 } | 372 } |
| 371 | 373 |
| 372 void PrintJob::HoldUntilStopIsCalled(const scoped_refptr<PrintJob>&) { | 374 void PrintJob::HoldUntilStopIsCalled(const scoped_refptr<PrintJob>&) { |
| 373 is_stopped_ = true; | 375 is_stopped_ = true; |
| 374 is_stopping_ = false; | 376 is_stopping_ = false; |
| 375 } | 377 } |
| 376 | 378 |
| 377 void PrintJob::Quit() { | 379 void PrintJob::Quit() { |
| 378 MessageLoop::current()->Quit(); | 380 base::MessageLoop::current()->Quit(); |
| 379 } | 381 } |
| 380 | 382 |
| 381 // Takes settings_ ownership and will be deleted in the receiving thread. | 383 // Takes settings_ ownership and will be deleted in the receiving thread. |
| 382 JobEventDetails::JobEventDetails(Type type, | 384 JobEventDetails::JobEventDetails(Type type, |
| 383 PrintedDocument* document, | 385 PrintedDocument* document, |
| 384 PrintedPage* page) | 386 PrintedPage* page) |
| 385 : document_(document), | 387 : document_(document), |
| 386 page_(page), | 388 page_(page), |
| 387 type_(type) { | 389 type_(type) { |
| 388 } | 390 } |
| 389 | 391 |
| 390 JobEventDetails::~JobEventDetails() { | 392 JobEventDetails::~JobEventDetails() { |
| 391 } | 393 } |
| 392 | 394 |
| 393 PrintedDocument* JobEventDetails::document() const { | 395 PrintedDocument* JobEventDetails::document() const { |
| 394 return document_; | 396 return document_; |
| 395 } | 397 } |
| 396 | 398 |
| 397 PrintedPage* JobEventDetails::page() const { | 399 PrintedPage* JobEventDetails::page() const { |
| 398 return page_; | 400 return page_; |
| 399 } | 401 } |
| 400 | 402 |
| 401 } // namespace printing | 403 } // namespace printing |
| OLD | NEW |