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 |