Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1094)

Side by Side Diff: chrome/browser/printing/print_view_manager.cc

Issue 22577010: Printing: Add a basic printing mode without print preview and cloud print. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_view_manager.h" 5 #include "chrome/browser/printing/print_view_manager.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/timer/timer.h"
17 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/printing/print_error_dialog.h"
20 #include "chrome/browser/printing/print_job.h"
21 #include "chrome/browser/printing/print_job_manager.h" 13 #include "chrome/browser/printing/print_job_manager.h"
22 #include "chrome/browser/printing/print_preview_dialog_controller.h" 14 #include "chrome/browser/printing/print_preview_dialog_controller.h"
23 #include "chrome/browser/printing/print_view_manager_observer.h" 15 #include "chrome/browser/printing/print_view_manager_observer.h"
24 #include "chrome/browser/printing/printer_query.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" 16 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/print_messages.h" 17 #include "chrome/common/print_messages.h"
30 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_details.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/notification_source.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/web_contents.h" 19 #include "content/public/browser/web_contents.h"
36 #include "content/public/browser/web_contents_view.h"
37 #include "grit/generated_resources.h"
38 #include "printing/metafile.h"
39 #include "printing/metafile_impl.h"
40 #include "printing/print_destination_interface.h" 20 #include "printing/print_destination_interface.h"
41 #include "printing/printed_document.h"
42 #include "ui/base/l10n/l10n_util.h"
43 21
44 using base::TimeDelta;
45 using content::BrowserThread; 22 using content::BrowserThread;
46 using content::WebContents;
47 23
48 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager); 24 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager);
49 25
50 namespace { 26 namespace {
51 27
52 // Keeps track of pending scripted print preview closures. 28 // Keeps track of pending scripted print preview closures.
53 // No locking, only access on the UI thread. 29 // No locking, only access on the UI thread.
54 typedef std::map<content::RenderProcessHost*, base::Closure> 30 typedef std::map<content::RenderProcessHost*, base::Closure>
55 ScriptedPrintPreviewClosureMap; 31 ScriptedPrintPreviewClosureMap;
56 static base::LazyInstance<ScriptedPrintPreviewClosureMap> 32 static base::LazyInstance<ScriptedPrintPreviewClosureMap>
57 g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER; 33 g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER;
58 34
59 // Limits memory usage by raster to 64 MiB.
60 const int kMaxRasterSizeInPixels = 16*1024*1024;
61
62 } // namespace 35 } // namespace
63 36
64 namespace printing { 37 namespace printing {
65 38
66 PrintViewManager::PrintViewManager(content::WebContents* web_contents) 39 PrintViewManager::PrintViewManager(content::WebContents* web_contents)
67 : content::WebContentsObserver(web_contents), 40 : PrintViewManagerBase(web_contents),
68 number_pages_(0),
69 printing_succeeded_(false),
70 inside_inner_message_loop_(false),
71 observer_(NULL), 41 observer_(NULL),
72 cookie_(0),
73 print_preview_state_(NOT_PREVIEWING), 42 print_preview_state_(NOT_PREVIEWING),
74 scripted_print_preview_rph_(NULL), 43 scripted_print_preview_rph_(NULL) {
75 tab_content_blocked_(false) {
76 #if defined(OS_POSIX) && !defined(OS_MACOSX)
77 expecting_first_page_ = true;
78 #endif
79 registrar_.Add(this, chrome::NOTIFICATION_CONTENT_BLOCKED_STATE_CHANGED,
80 content::Source<content::WebContents>(web_contents));
81 Profile* profile =
82 Profile::FromBrowserContext(web_contents->GetBrowserContext());
83 printing_enabled_.Init(
84 prefs::kPrintingEnabled,
85 profile->GetPrefs(),
86 base::Bind(&PrintViewManager::UpdateScriptedPrintingBlocked,
87 base::Unretained(this)));
88 } 44 }
89 45
90 PrintViewManager::~PrintViewManager() { 46 PrintViewManager::~PrintViewManager() {
91 DCHECK_EQ(NOT_PREVIEWING, print_preview_state_); 47 DCHECK_EQ(NOT_PREVIEWING, print_preview_state_);
92 ReleasePrinterQuery();
93 DisconnectFromCurrentPrintJob();
94 }
95
96 bool PrintViewManager::PrintNow() {
97 return PrintNowInternal(new PrintMsg_PrintPages(routing_id()));
98 } 48 }
99 49
100 bool PrintViewManager::PrintForSystemDialogNow() { 50 bool PrintViewManager::PrintForSystemDialogNow() {
101 return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id())); 51 return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id()));
102 } 52 }
103 53
104 bool PrintViewManager::AdvancedPrintNow() { 54 bool PrintViewManager::AdvancedPrintNow() {
105 PrintPreviewDialogController* dialog_controller = 55 PrintPreviewDialogController* dialog_controller =
106 PrintPreviewDialogController::GetInstance(); 56 PrintPreviewDialogController::GetInstance();
107 if (!dialog_controller) 57 if (!dialog_controller)
108 return false; 58 return false;
109 WebContents* print_preview_dialog = 59 content::WebContents* print_preview_dialog =
110 dialog_controller->GetPrintPreviewForContents(web_contents()); 60 dialog_controller->GetPrintPreviewForContents(web_contents());
111 if (print_preview_dialog) { 61 if (print_preview_dialog) {
112 if (!print_preview_dialog->GetWebUI()) 62 if (!print_preview_dialog->GetWebUI())
113 return false; 63 return false;
114 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>( 64 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
115 print_preview_dialog->GetWebUI()->GetController()); 65 print_preview_dialog->GetWebUI()->GetController());
116 print_preview_ui->OnShowSystemDialog(); 66 print_preview_ui->OnShowSystemDialog();
117 return true; 67 return true;
118 } else { 68 } else {
119 return PrintNow(); 69 return PrintNow();
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 ScriptedPrintPreviewClosureMap::iterator it = 111 ScriptedPrintPreviewClosureMap::iterator it =
162 map.find(scripted_print_preview_rph_); 112 map.find(scripted_print_preview_rph_);
163 CHECK(it != map.end()); 113 CHECK(it != map.end());
164 it->second.Run(); 114 it->second.Run();
165 map.erase(scripted_print_preview_rph_); 115 map.erase(scripted_print_preview_rph_);
166 scripted_print_preview_rph_ = NULL; 116 scripted_print_preview_rph_ = NULL;
167 } 117 }
168 print_preview_state_ = NOT_PREVIEWING; 118 print_preview_state_ = NOT_PREVIEWING;
169 } 119 }
170 120
171 void PrintViewManager::UpdateScriptedPrintingBlocked() {
172 Send(new PrintMsg_SetScriptedPrintingBlocked(
173 routing_id(),
174 !printing_enabled_.GetValue() || tab_content_blocked_));
175 }
176
177 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) { 121 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) {
178 DCHECK(!observer || !observer_); 122 DCHECK(!observer || !observer_);
179 observer_ = observer; 123 observer_ = observer;
180 } 124 }
181 125
182 void PrintViewManager::StopNavigation() {
183 // Cancel the current job, wait for the worker to finish.
184 TerminatePrintJob(true);
185 }
186
187 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { 126 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) {
188 print_preview_state_ = NOT_PREVIEWING; 127 print_preview_state_ = NOT_PREVIEWING;
189 ReleasePrinterQuery(); 128 PrintViewManagerBase::RenderProcessGone(status);
190
191 if (!print_job_.get())
192 return;
193
194 scoped_refptr<PrintedDocument> document(print_job_->document());
195 if (document.get()) {
196 // If IsComplete() returns false, the document isn't completely rendered.
197 // Since our renderer is gone, there's nothing to do, cancel it. Otherwise,
198 // the print job may finish without problem.
199 TerminatePrintJob(!document->IsComplete());
200 }
201 }
202
203 string16 PrintViewManager::RenderSourceName() {
204 string16 name(web_contents()->GetTitle());
205 if (name.empty())
206 name = l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE);
207 return name;
208 }
209
210 void PrintViewManager::OnDidGetPrintedPagesCount(int cookie, int number_pages) {
211 DCHECK_GT(cookie, 0);
212 DCHECK_GT(number_pages, 0);
213 number_pages_ = number_pages;
214 OpportunisticallyCreatePrintJob(cookie);
215 }
216
217 void PrintViewManager::OnDidGetDocumentCookie(int cookie) {
218 cookie_ = cookie;
219 } 129 }
220 130
221 void PrintViewManager::OnDidShowPrintDialog() { 131 void PrintViewManager::OnDidShowPrintDialog() {
222 if (observer_) 132 if (observer_)
223 observer_->OnPrintDialogShown(); 133 observer_->OnPrintDialogShown();
224 } 134 }
225 135
226 void PrintViewManager::OnDidPrintPage(
227 const PrintHostMsg_DidPrintPage_Params& params) {
228 if (!OpportunisticallyCreatePrintJob(params.document_cookie))
229 return;
230
231 PrintedDocument* document = print_job_->document();
232 if (!document || params.document_cookie != document->cookie()) {
233 // Out of sync. It may happen since we are completely asynchronous. Old
234 // spurious messages can be received if one of the processes is overloaded.
235 return;
236 }
237
238 #if defined(OS_WIN) || defined(OS_MACOSX)
239 const bool metafile_must_be_valid = true;
240 #elif defined(OS_POSIX)
241 const bool metafile_must_be_valid = expecting_first_page_;
242 expecting_first_page_ = false;
243 #endif
244
245 base::SharedMemory shared_buf(params.metafile_data_handle, true);
246 if (metafile_must_be_valid) {
247 if (!shared_buf.Map(params.data_size)) {
248 NOTREACHED() << "couldn't map";
249 web_contents()->Stop();
250 return;
251 }
252 }
253
254 scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
255 if (metafile_must_be_valid) {
256 if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) {
257 NOTREACHED() << "Invalid metafile header";
258 web_contents()->Stop();
259 return;
260 }
261 }
262
263 #if defined(OS_WIN)
264 bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize);
265 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
266 int raster_size = std::min(params.page_size.GetArea(),
267 kMaxRasterSizeInPixels);
268 if (big_emf || (cmdline && cmdline->HasSwitch(switches::kPrintRaster))) {
269 scoped_ptr<NativeMetafile> raster_metafile(
270 metafile->RasterizeMetafile(raster_size));
271 if (raster_metafile.get()) {
272 metafile.swap(raster_metafile);
273 } else if (big_emf) {
274 // Don't fall back to emf here.
275 NOTREACHED() << "size:" << params.data_size;
276 TerminatePrintJob(true);
277 web_contents()->Stop();
278 return;
279 }
280 }
281 #endif
282
283 // Update the rendered document. It will send notifications to the listener.
284 document->SetPage(params.page_number,
285 metafile.release(),
286 params.actual_shrink,
287 params.page_size,
288 params.content_area);
289
290 ShouldQuitFromInnerMessageLoop();
291 }
292
293 void PrintViewManager::OnPrintingFailed(int cookie) {
294 if (cookie != cookie_) {
295 NOTREACHED();
296 return;
297 }
298
299 chrome::ShowPrintErrorDialog(
300 web_contents()->GetView()->GetTopLevelNativeWindow());
301
302 ReleasePrinterQuery();
303
304 content::NotificationService::current()->Notify(
305 chrome::NOTIFICATION_PRINT_JOB_RELEASED,
306 content::Source<content::WebContents>(web_contents()),
307 content::NotificationService::NoDetails());
308 }
309
310 void PrintViewManager::OnScriptedPrintPreview(bool source_is_modifiable, 136 void PrintViewManager::OnScriptedPrintPreview(bool source_is_modifiable,
311 IPC::Message* reply_msg) { 137 IPC::Message* reply_msg) {
312 BrowserThread::CurrentlyOn(BrowserThread::UI); 138 BrowserThread::CurrentlyOn(BrowserThread::UI);
313 ScriptedPrintPreviewClosureMap& map = 139 ScriptedPrintPreviewClosureMap& map =
314 g_scripted_print_preview_closure_map.Get(); 140 g_scripted_print_preview_closure_map.Get();
315 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost(); 141 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
316 142
317 // This should always be 0 once we get modal window.print(). 143 // This should always be 0 once we get modal window.print().
318 if (map.count(rph) != 0) { 144 if (map.count(rph) != 0) {
319 // Renderer already handling window.print() in another View. 145 // Renderer already handling window.print() in another View.
(...skipping 28 matching lines...) Expand all
348 params.is_modifiable = source_is_modifiable; 174 params.is_modifiable = source_is_modifiable;
349 PrintPreviewUI::SetInitialParams( 175 PrintPreviewUI::SetInitialParams(
350 dialog_controller->GetPrintPreviewForContents(web_contents()), params); 176 dialog_controller->GetPrintPreviewForContents(web_contents()), params);
351 } 177 }
352 178
353 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) { 179 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) {
354 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355 Send(reply_msg); 181 Send(reply_msg);
356 } 182 }
357 183
358 void PrintViewManager::DidStartLoading(
359 content::RenderViewHost* render_view_host) {
360 UpdateScriptedPrintingBlocked();
361 }
362
363 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) { 184 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) {
364 bool handled = true; 185 bool handled = true;
365 IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message) 186 IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message)
366 IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPrintedPagesCount,
367 OnDidGetPrintedPagesCount)
368 IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDocumentCookie,
369 OnDidGetDocumentCookie)
370 IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) 187 IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog)
371 IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage)
372 IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
373 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrintPreview, 188 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrintPreview,
374 OnScriptedPrintPreview) 189 OnScriptedPrintPreview)
375 IPC_MESSAGE_UNHANDLED(handled = false) 190 IPC_MESSAGE_UNHANDLED(handled = false)
376 IPC_END_MESSAGE_MAP() 191 IPC_END_MESSAGE_MAP()
377 return handled;
378 }
379 192
380 void PrintViewManager::Observe(int type, 193 return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
381 const content::NotificationSource& source,
382 const content::NotificationDetails& details) {
383 switch (type) {
384 case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
385 OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
386 break;
387 }
388 case chrome::NOTIFICATION_CONTENT_BLOCKED_STATE_CHANGED: {
389 tab_content_blocked_ = *content::Details<const bool>(details).ptr();
390 UpdateScriptedPrintingBlocked();
391 break;
392 }
393 default: {
394 NOTREACHED();
395 break;
396 }
397 }
398 }
399
400 void PrintViewManager::OnNotifyPrintJobEvent(
401 const JobEventDetails& event_details) {
402 switch (event_details.type()) {
403 case JobEventDetails::FAILED: {
404 TerminatePrintJob(true);
405
406 content::NotificationService::current()->Notify(
407 chrome::NOTIFICATION_PRINT_JOB_RELEASED,
408 content::Source<content::WebContents>(web_contents()),
409 content::NotificationService::NoDetails());
410 break;
411 }
412 case JobEventDetails::USER_INIT_DONE:
413 case JobEventDetails::DEFAULT_INIT_DONE:
414 case JobEventDetails::USER_INIT_CANCELED: {
415 NOTREACHED();
416 break;
417 }
418 case JobEventDetails::ALL_PAGES_REQUESTED: {
419 ShouldQuitFromInnerMessageLoop();
420 break;
421 }
422 case JobEventDetails::NEW_DOC:
423 case JobEventDetails::NEW_PAGE:
424 case JobEventDetails::PAGE_DONE:
425 case JobEventDetails::DOC_DONE: {
426 // Don't care about the actual printing process.
427 break;
428 }
429 case JobEventDetails::JOB_DONE: {
430 // Printing is done, we don't need it anymore.
431 // print_job_->is_job_pending() may still be true, depending on the order
432 // of object registration.
433 printing_succeeded_ = true;
434 ReleasePrintJob();
435
436 content::NotificationService::current()->Notify(
437 chrome::NOTIFICATION_PRINT_JOB_RELEASED,
438 content::Source<content::WebContents>(web_contents()),
439 content::NotificationService::NoDetails());
440 break;
441 }
442 default: {
443 NOTREACHED();
444 break;
445 }
446 }
447 }
448
449 bool PrintViewManager::RenderAllMissingPagesNow() {
450 if (!print_job_.get() || !print_job_->is_job_pending())
451 return false;
452
453 // We can't print if there is no renderer.
454 if (!web_contents() ||
455 !web_contents()->GetRenderViewHost() ||
456 !web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
457 return false;
458 }
459
460 // Is the document already complete?
461 if (print_job_->document() && print_job_->document()->IsComplete()) {
462 printing_succeeded_ = true;
463 return true;
464 }
465
466 // WebContents is either dying or a second consecutive request to print
467 // happened before the first had time to finish. We need to render all the
468 // pages in an hurry if a print_job_ is still pending. No need to wait for it
469 // to actually spool the pages, only to have the renderer generate them. Run
470 // a message loop until we get our signal that the print job is satisfied.
471 // PrintJob will send a ALL_PAGES_REQUESTED after having received all the
472 // pages it needs. MessageLoop::current()->Quit() will be called as soon as
473 // print_job_->document()->IsComplete() is true on either ALL_PAGES_REQUESTED
474 // or in DidPrintPage(). The check is done in
475 // ShouldQuitFromInnerMessageLoop().
476 // BLOCKS until all the pages are received. (Need to enable recursive task)
477 if (!RunInnerMessageLoop()) {
478 // This function is always called from DisconnectFromCurrentPrintJob() so we
479 // know that the job will be stopped/canceled in any case.
480 return false;
481 }
482 return true;
483 }
484
485 void PrintViewManager::ShouldQuitFromInnerMessageLoop() {
486 // Look at the reason.
487 DCHECK(print_job_->document());
488 if (print_job_->document() &&
489 print_job_->document()->IsComplete() &&
490 inside_inner_message_loop_) {
491 // We are in a message loop created by RenderAllMissingPagesNow. Quit from
492 // it.
493 base::MessageLoop::current()->Quit();
494 inside_inner_message_loop_ = false;
495 }
496 }
497
498 bool PrintViewManager::CreateNewPrintJob(PrintJobWorkerOwner* job) {
499 DCHECK(!inside_inner_message_loop_);
500
501 // Disconnect the current print_job_.
502 DisconnectFromCurrentPrintJob();
503
504 // We can't print if there is no renderer.
505 if (!web_contents()->GetRenderViewHost() ||
506 !web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
507 return false;
508 }
509
510 // Ask the renderer to generate the print preview, create the print preview
511 // view and switch to it, initialize the printer and show the print dialog.
512 DCHECK(!print_job_.get());
513 DCHECK(job);
514 if (!job)
515 return false;
516
517 print_job_ = new PrintJob();
518 print_job_->Initialize(job, this, number_pages_);
519 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
520 content::Source<PrintJob>(print_job_.get()));
521 printing_succeeded_ = false;
522 return true;
523 }
524
525 void PrintViewManager::DisconnectFromCurrentPrintJob() {
526 // Make sure all the necessary rendered page are done. Don't bother with the
527 // return value.
528 bool result = RenderAllMissingPagesNow();
529
530 // Verify that assertion.
531 if (print_job_.get() &&
532 print_job_->document() &&
533 !print_job_->document()->IsComplete()) {
534 DCHECK(!result);
535 // That failed.
536 TerminatePrintJob(true);
537 } else {
538 // DO NOT wait for the job to finish.
539 ReleasePrintJob();
540 }
541 #if defined(OS_POSIX) && !defined(OS_MACOSX)
542 expecting_first_page_ = true;
543 #endif
544 }
545
546 void PrintViewManager::PrintingDone(bool success) {
547 if (!print_job_.get())
548 return;
549 Send(new PrintMsg_PrintingDone(routing_id(), success));
550 }
551
552 void PrintViewManager::TerminatePrintJob(bool cancel) {
553 if (!print_job_.get())
554 return;
555
556 if (cancel) {
557 // We don't need the metafile data anymore because the printing is canceled.
558 print_job_->Cancel();
559 inside_inner_message_loop_ = false;
560 } else {
561 DCHECK(!inside_inner_message_loop_);
562 DCHECK(!print_job_->document() || print_job_->document()->IsComplete());
563
564 // WebContents is either dying or navigating elsewhere. We need to render
565 // all the pages in an hurry if a print job is still pending. This does the
566 // trick since it runs a blocking message loop:
567 print_job_->Stop();
568 }
569 ReleasePrintJob();
570 }
571
572 void PrintViewManager::ReleasePrintJob() {
573 if (!print_job_.get())
574 return;
575
576 PrintingDone(printing_succeeded_);
577
578 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
579 content::Source<PrintJob>(print_job_.get()));
580 print_job_->DisconnectSource();
581 // Don't close the worker thread.
582 print_job_ = NULL;
583 }
584
585 bool PrintViewManager::RunInnerMessageLoop() {
586 // This value may actually be too low:
587 //
588 // - If we're looping because of printer settings initialization, the premise
589 // here is that some poor users have their print server away on a VPN over a
590 // slow connection. In this situation, the simple fact of opening the printer
591 // can be dead slow. On the other side, we don't want to die infinitely for a
592 // real network error. Give the printer 60 seconds to comply.
593 //
594 // - If we're looping because of renderer page generation, the renderer could
595 // be CPU bound, the page overly complex/large or the system just
596 // memory-bound.
597 static const int kPrinterSettingsTimeout = 60000;
598 base::OneShotTimer<base::MessageLoop> quit_timer;
599 quit_timer.Start(FROM_HERE,
600 TimeDelta::FromMilliseconds(kPrinterSettingsTimeout),
601 base::MessageLoop::current(), &base::MessageLoop::Quit);
602
603 inside_inner_message_loop_ = true;
604
605 // Need to enable recursive task.
606 {
607 base::MessageLoop::ScopedNestableTaskAllower allow(
608 base::MessageLoop::current());
609 base::MessageLoop::current()->Run();
610 }
611
612 bool success = true;
613 if (inside_inner_message_loop_) {
614 // Ok we timed out. That's sad.
615 inside_inner_message_loop_ = false;
616 success = false;
617 }
618
619 return success;
620 }
621
622 bool PrintViewManager::OpportunisticallyCreatePrintJob(int cookie) {
623 if (print_job_.get())
624 return true;
625
626 if (!cookie) {
627 // Out of sync. It may happens since we are completely asynchronous. Old
628 // spurious message can happen if one of the processes is overloaded.
629 return false;
630 }
631
632 // The job was initiated by a script. Time to get the corresponding worker
633 // thread.
634 scoped_refptr<PrinterQuery> queued_query;
635 g_browser_process->print_job_manager()->PopPrinterQuery(cookie,
636 &queued_query);
637 DCHECK(queued_query.get());
638 if (!queued_query.get())
639 return false;
640
641 if (!CreateNewPrintJob(queued_query.get())) {
642 // Don't kill anything.
643 return false;
644 }
645
646 // Settings are already loaded. Go ahead. This will set
647 // print_job_->is_job_pending() to true.
648 print_job_->StartPrinting();
649 return true;
650 }
651
652 bool PrintViewManager::PrintNowInternal(IPC::Message* message) {
653 // Don't print / print preview interstitials.
654 if (web_contents()->ShowingInterstitialPage()) {
655 delete message;
656 return false;
657 }
658 return Send(message);
659 }
660
661 void PrintViewManager::ReleasePrinterQuery() {
662 if (!cookie_)
663 return;
664
665 int cookie = cookie_;
666 cookie_ = 0;
667 g_browser_process->print_job_manager()->SetPrintDestination(NULL);
668
669
670 printing::PrintJobManager* print_job_manager =
671 g_browser_process->print_job_manager();
672 // May be NULL in tests.
673 if (!print_job_manager)
674 return;
675
676 scoped_refptr<printing::PrinterQuery> printer_query;
677 print_job_manager->PopPrinterQuery(cookie, &printer_query);
678 if (!printer_query.get())
679 return;
680 BrowserThread::PostTask(
681 BrowserThread::IO, FROM_HERE,
682 base::Bind(&PrinterQuery::StopWorker, printer_query.get()));
683 } 194 }
684 195
685 } // namespace printing 196 } // namespace printing
OLDNEW
« no previous file with comments | « chrome/browser/printing/print_view_manager.h ('k') | chrome/browser/printing/print_view_manager_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698