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