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_worker.h" | 5 #include "chrome/browser/printing/print_job_worker.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/callback.h" | 9 #include "base/callback.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 // We know that is is a PrintJob object in this circumstance. | 46 // We know that is is a PrintJob object in this circumstance. |
47 content::Source<PrintJob>(static_cast<PrintJob*>(print_job)), | 47 content::Source<PrintJob>(static_cast<PrintJob*>(print_job)), |
48 content::Details<JobEventDetails>(details)); | 48 content::Details<JobEventDetails>(details)); |
49 } | 49 } |
50 | 50 |
51 PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner) | 51 PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner) |
52 : Thread("Printing_Worker"), | 52 : Thread("Printing_Worker"), |
53 owner_(owner), | 53 owner_(owner), |
54 weak_factory_(this) { | 54 weak_factory_(this) { |
55 // The object is created in the IO thread. | 55 // The object is created in the IO thread. |
56 DCHECK_EQ(owner_->message_loop(), MessageLoop::current()); | 56 DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current()); |
57 | 57 |
58 printing_context_.reset(PrintingContext::Create( | 58 printing_context_.reset(PrintingContext::Create( |
59 g_browser_process->GetApplicationLocale())); | 59 g_browser_process->GetApplicationLocale())); |
60 } | 60 } |
61 | 61 |
62 PrintJobWorker::~PrintJobWorker() { | 62 PrintJobWorker::~PrintJobWorker() { |
63 // The object is normally deleted in the UI thread, but when the user | 63 // The object is normally deleted in the UI thread, but when the user |
64 // cancels printing or in the case of print preview, the worker is destroyed | 64 // cancels printing or in the case of print preview, the worker is destroyed |
65 // on the I/O thread. | 65 // on the I/O thread. |
66 DCHECK_EQ(owner_->message_loop(), MessageLoop::current()); | 66 DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current()); |
67 Stop(); | 67 Stop(); |
68 } | 68 } |
69 | 69 |
70 void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { | 70 void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { |
71 DCHECK(page_number_ == PageNumber::npos()); | 71 DCHECK(page_number_ == PageNumber::npos()); |
72 owner_ = new_owner; | 72 owner_ = new_owner; |
73 } | 73 } |
74 | 74 |
75 void PrintJobWorker::SetPrintDestination( | 75 void PrintJobWorker::SetPrintDestination( |
76 PrintDestinationInterface* destination) { | 76 PrintDestinationInterface* destination) { |
77 destination_ = destination; | 77 destination_ = destination; |
78 } | 78 } |
79 | 79 |
80 void PrintJobWorker::GetSettings(bool ask_user_for_settings, | 80 void PrintJobWorker::GetSettings(bool ask_user_for_settings, |
81 gfx::NativeView parent_view, | 81 gfx::NativeView parent_view, |
82 int document_page_count, | 82 int document_page_count, |
83 bool has_selection, | 83 bool has_selection, |
84 MarginType margin_type) { | 84 MarginType margin_type) { |
85 DCHECK_EQ(message_loop(), MessageLoop::current()); | 85 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
86 DCHECK_EQ(page_number_, PageNumber::npos()); | 86 DCHECK_EQ(page_number_, PageNumber::npos()); |
87 | 87 |
88 // Recursive task processing is needed for the dialog in case it needs to be | 88 // Recursive task processing is needed for the dialog in case it needs to be |
89 // destroyed by a task. | 89 // destroyed by a task. |
90 // TODO(thestig): This code is wrong. SetNestableTasksAllowed(true) is needed | 90 // TODO(thestig): This code is wrong. SetNestableTasksAllowed(true) is needed |
91 // on the thread where the PrintDlgEx is called, and definitely both calls | 91 // on the thread where the PrintDlgEx is called, and definitely both calls |
92 // should happen on the same thread. See http://crbug.com/73466 | 92 // should happen on the same thread. See http://crbug.com/73466 |
93 // MessageLoop::current()->SetNestableTasksAllowed(true); | 93 // MessageLoop::current()->SetNestableTasksAllowed(true); |
94 printing_context_->set_margin_type(margin_type); | 94 printing_context_->set_margin_type(margin_type); |
95 | 95 |
96 // When we delegate to a destination, we don't ask the user for settings. | 96 // When we delegate to a destination, we don't ask the user for settings. |
97 // TODO(mad): Ask the destination for settings. | 97 // TODO(mad): Ask the destination for settings. |
98 if (ask_user_for_settings && destination_.get() == NULL) { | 98 if (ask_user_for_settings && destination_.get() == NULL) { |
99 BrowserThread::PostTask( | 99 BrowserThread::PostTask( |
100 BrowserThread::UI, FROM_HERE, | 100 BrowserThread::UI, FROM_HERE, |
101 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), | 101 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), |
102 base::Bind(&PrintJobWorker::GetSettingsWithUI, | 102 base::Bind(&PrintJobWorker::GetSettingsWithUI, |
103 base::Unretained(this), parent_view, | 103 base::Unretained(this), parent_view, |
104 document_page_count, has_selection))); | 104 document_page_count, has_selection))); |
105 } else { | 105 } else { |
106 BrowserThread::PostTask( | 106 BrowserThread::PostTask( |
107 BrowserThread::UI, FROM_HERE, | 107 BrowserThread::UI, FROM_HERE, |
108 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), | 108 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), |
109 base::Bind(&PrintJobWorker::UseDefaultSettings, | 109 base::Bind(&PrintJobWorker::UseDefaultSettings, |
110 base::Unretained(this)))); | 110 base::Unretained(this)))); |
111 } | 111 } |
112 } | 112 } |
113 | 113 |
114 void PrintJobWorker::SetSettings(const DictionaryValue* const new_settings) { | 114 void PrintJobWorker::SetSettings(const DictionaryValue* const new_settings) { |
115 DCHECK_EQ(message_loop(), MessageLoop::current()); | 115 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
116 | 116 |
117 BrowserThread::PostTask( | 117 BrowserThread::PostTask( |
118 BrowserThread::UI, FROM_HERE, | 118 BrowserThread::UI, FROM_HERE, |
119 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), | 119 base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), |
120 base::Bind(&PrintJobWorker::UpdatePrintSettings, | 120 base::Bind(&PrintJobWorker::UpdatePrintSettings, |
121 base::Unretained(this), new_settings))); | 121 base::Unretained(this), new_settings))); |
122 } | 122 } |
123 | 123 |
124 void PrintJobWorker::UpdatePrintSettings( | 124 void PrintJobWorker::UpdatePrintSettings( |
125 const DictionaryValue* const new_settings) { | 125 const DictionaryValue* const new_settings) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 base::Bind(&PrintJobWorker::GetSettingsDone, | 187 base::Bind(&PrintJobWorker::GetSettingsDone, |
188 base::Unretained(this), result))); | 188 base::Unretained(this), result))); |
189 } | 189 } |
190 | 190 |
191 void PrintJobWorker::UseDefaultSettings() { | 191 void PrintJobWorker::UseDefaultSettings() { |
192 PrintingContext::Result result = printing_context_->UseDefaultSettings(); | 192 PrintingContext::Result result = printing_context_->UseDefaultSettings(); |
193 GetSettingsDone(result); | 193 GetSettingsDone(result); |
194 } | 194 } |
195 | 195 |
196 void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { | 196 void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { |
197 DCHECK_EQ(message_loop(), MessageLoop::current()); | 197 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
198 DCHECK_EQ(page_number_, PageNumber::npos()); | 198 DCHECK_EQ(page_number_, PageNumber::npos()); |
199 DCHECK_EQ(document_, new_document); | 199 DCHECK_EQ(document_, new_document); |
200 DCHECK(document_.get()); | 200 DCHECK(document_.get()); |
201 DCHECK(new_document->settings().Equals(printing_context_->settings())); | 201 DCHECK(new_document->settings().Equals(printing_context_->settings())); |
202 | 202 |
203 if (!document_.get() || page_number_ != PageNumber::npos() || | 203 if (!document_.get() || page_number_ != PageNumber::npos() || |
204 document_ != new_document) { | 204 document_ != new_document) { |
205 return; | 205 return; |
206 } | 206 } |
207 | 207 |
(...skipping 13 matching lines...) Expand all Loading... |
221 // Try to print already cached data. It may already have been generated for | 221 // Try to print already cached data. It may already have been generated for |
222 // the print preview. | 222 // the print preview. |
223 OnNewPage(); | 223 OnNewPage(); |
224 // Don't touch this anymore since the instance could be destroyed. It happens | 224 // Don't touch this anymore since the instance could be destroyed. It happens |
225 // if all the pages are printed a one sweep and the client doesn't have a | 225 // if all the pages are printed a one sweep and the client doesn't have a |
226 // handle to us anymore. There's a timing issue involved between the worker | 226 // handle to us anymore. There's a timing issue involved between the worker |
227 // thread and the UI thread. Take no chance. | 227 // thread and the UI thread. Take no chance. |
228 } | 228 } |
229 | 229 |
230 void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { | 230 void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { |
231 DCHECK_EQ(message_loop(), MessageLoop::current()); | 231 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
232 DCHECK_EQ(page_number_, PageNumber::npos()); | 232 DCHECK_EQ(page_number_, PageNumber::npos()); |
233 DCHECK(!new_document || | 233 DCHECK(!new_document || |
234 new_document->settings().Equals(printing_context_->settings())); | 234 new_document->settings().Equals(printing_context_->settings())); |
235 | 235 |
236 if (page_number_ != PageNumber::npos()) | 236 if (page_number_ != PageNumber::npos()) |
237 return; | 237 return; |
238 | 238 |
239 document_ = new_document; | 239 document_ = new_document; |
240 } | 240 } |
241 | 241 |
242 void PrintJobWorker::OnNewPage() { | 242 void PrintJobWorker::OnNewPage() { |
243 if (!document_.get()) // Spurious message. | 243 if (!document_.get()) // Spurious message. |
244 return; | 244 return; |
245 | 245 |
246 // message_loop() could return NULL when the print job is cancelled. | 246 // message_loop() could return NULL when the print job is cancelled. |
247 DCHECK_EQ(message_loop(), MessageLoop::current()); | 247 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
248 | 248 |
249 if (page_number_ == PageNumber::npos()) { | 249 if (page_number_ == PageNumber::npos()) { |
250 // Find first page to print. | 250 // Find first page to print. |
251 int page_count = document_->page_count(); | 251 int page_count = document_->page_count(); |
252 if (!page_count) { | 252 if (!page_count) { |
253 // We still don't know how many pages the document contains. We can't | 253 // We still don't know how many pages the document contains. We can't |
254 // start to print the document yet since the header/footer may refer to | 254 // start to print the document yet since the header/footer may refer to |
255 // the document's page count. | 255 // the document's page count. |
256 return; | 256 return; |
257 } | 257 } |
258 // We have enough information to initialize page_number_. | 258 // We have enough information to initialize page_number_. |
259 page_number_.Init(document_->settings(), page_count); | 259 page_number_.Init(document_->settings(), page_count); |
260 if (destination_.get() != NULL) | 260 if (destination_.get() != NULL) |
261 destination_->SetPageCount(page_count); | 261 destination_->SetPageCount(page_count); |
262 } | 262 } |
263 DCHECK_NE(page_number_, PageNumber::npos()); | 263 DCHECK_NE(page_number_, PageNumber::npos()); |
264 | 264 |
265 while (true) { | 265 while (true) { |
266 // Is the page available? | 266 // Is the page available? |
267 scoped_refptr<PrintedPage> page; | 267 scoped_refptr<PrintedPage> page; |
268 if (!document_->GetPage(page_number_.ToInt(), &page)) { | 268 if (!document_->GetPage(page_number_.ToInt(), &page)) { |
269 // We need to wait for the page to be available. | 269 // We need to wait for the page to be available. |
270 MessageLoop::current()->PostDelayedTask( | 270 base::MessageLoop::current()->PostDelayedTask( |
271 FROM_HERE, | 271 FROM_HERE, |
272 base::Bind(&PrintJobWorker::OnNewPage, weak_factory_.GetWeakPtr()), | 272 base::Bind(&PrintJobWorker::OnNewPage, weak_factory_.GetWeakPtr()), |
273 base::TimeDelta::FromMilliseconds(500)); | 273 base::TimeDelta::FromMilliseconds(500)); |
274 break; | 274 break; |
275 } | 275 } |
276 // The page is there, print it. | 276 // The page is there, print it. |
277 SpoolPage(page); | 277 SpoolPage(page); |
278 ++page_number_; | 278 ++page_number_; |
279 if (page_number_ == PageNumber::npos()) { | 279 if (page_number_ == PageNumber::npos()) { |
280 OnDocumentDone(); | 280 OnDocumentDone(); |
281 // Don't touch this anymore since the instance could be destroyed. | 281 // Don't touch this anymore since the instance could be destroyed. |
282 break; | 282 break; |
283 } | 283 } |
284 } | 284 } |
285 } | 285 } |
286 | 286 |
287 void PrintJobWorker::Cancel() { | 287 void PrintJobWorker::Cancel() { |
288 // This is the only function that can be called from any thread. | 288 // This is the only function that can be called from any thread. |
289 printing_context_->Cancel(); | 289 printing_context_->Cancel(); |
290 // Cannot touch any member variable since we don't know in which thread | 290 // Cannot touch any member variable since we don't know in which thread |
291 // context we run. | 291 // context we run. |
292 } | 292 } |
293 | 293 |
294 void PrintJobWorker::OnDocumentDone() { | 294 void PrintJobWorker::OnDocumentDone() { |
295 DCHECK_EQ(message_loop(), MessageLoop::current()); | 295 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
296 DCHECK_EQ(page_number_, PageNumber::npos()); | 296 DCHECK_EQ(page_number_, PageNumber::npos()); |
297 DCHECK(document_.get()); | 297 DCHECK(document_.get()); |
298 | 298 |
299 if (printing_context_->DocumentDone() != PrintingContext::OK) { | 299 if (printing_context_->DocumentDone() != PrintingContext::OK) { |
300 OnFailure(); | 300 OnFailure(); |
301 return; | 301 return; |
302 } | 302 } |
303 | 303 |
304 owner_->message_loop()->PostTask( | 304 owner_->message_loop()->PostTask( |
305 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), | 305 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), |
306 JobEventDetails::DOC_DONE, document_, | 306 JobEventDetails::DOC_DONE, document_, |
307 scoped_refptr<PrintedPage>())); | 307 scoped_refptr<PrintedPage>())); |
308 | 308 |
309 // Makes sure the variables are reinitialized. | 309 // Makes sure the variables are reinitialized. |
310 document_ = NULL; | 310 document_ = NULL; |
311 } | 311 } |
312 | 312 |
313 void PrintJobWorker::SpoolPage(PrintedPage* page) { | 313 void PrintJobWorker::SpoolPage(PrintedPage* page) { |
314 DCHECK_EQ(message_loop(), MessageLoop::current()); | 314 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
315 DCHECK_NE(page_number_, PageNumber::npos()); | 315 DCHECK_NE(page_number_, PageNumber::npos()); |
316 | 316 |
317 // Signal everyone that the page is about to be printed. | 317 // Signal everyone that the page is about to be printed. |
318 owner_->message_loop()->PostTask( | 318 owner_->message_loop()->PostTask( |
319 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), | 319 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), |
320 JobEventDetails::NEW_PAGE, document_, | 320 JobEventDetails::NEW_PAGE, document_, |
321 make_scoped_refptr(page))); | 321 make_scoped_refptr(page))); |
322 | 322 |
323 // Preprocess. | 323 // Preprocess. |
324 if (printing_context_->NewPage() != PrintingContext::OK) { | 324 if (printing_context_->NewPage() != PrintingContext::OK) { |
(...skipping 28 matching lines...) Expand all Loading... |
353 | 353 |
354 // Signal everyone that the page is printed. | 354 // Signal everyone that the page is printed. |
355 owner_->message_loop()->PostTask( | 355 owner_->message_loop()->PostTask( |
356 FROM_HERE, | 356 FROM_HERE, |
357 base::Bind(NotificationCallback, make_scoped_refptr(owner_), | 357 base::Bind(NotificationCallback, make_scoped_refptr(owner_), |
358 JobEventDetails::PAGE_DONE, document_, | 358 JobEventDetails::PAGE_DONE, document_, |
359 make_scoped_refptr(page))); | 359 make_scoped_refptr(page))); |
360 } | 360 } |
361 | 361 |
362 void PrintJobWorker::OnFailure() { | 362 void PrintJobWorker::OnFailure() { |
363 DCHECK_EQ(message_loop(), MessageLoop::current()); | 363 DCHECK_EQ(message_loop(), base::MessageLoop::current()); |
364 | 364 |
365 // We may loose our last reference by broadcasting the FAILED event. | 365 // We may loose our last reference by broadcasting the FAILED event. |
366 scoped_refptr<PrintJobWorkerOwner> handle(owner_); | 366 scoped_refptr<PrintJobWorkerOwner> handle(owner_); |
367 | 367 |
368 owner_->message_loop()->PostTask( | 368 owner_->message_loop()->PostTask( |
369 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), | 369 FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_), |
370 JobEventDetails::FAILED, document_, | 370 JobEventDetails::FAILED, document_, |
371 scoped_refptr<PrintedPage>())); | 371 scoped_refptr<PrintedPage>())); |
372 Cancel(); | 372 Cancel(); |
373 | 373 |
374 // Makes sure the variables are reinitialized. | 374 // Makes sure the variables are reinitialized. |
375 document_ = NULL; | 375 document_ = NULL; |
376 page_number_ = PageNumber::npos(); | 376 page_number_ = PageNumber::npos(); |
377 } | 377 } |
378 | 378 |
379 } // namespace printing | 379 } // namespace printing |
OLD | NEW |