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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/printing/print_view_manager.h" 6 7 #include <map> 8 9 #include "base/bind.h" 10 #include "base/lazy_instance.h" 11 #include "base/metrics/histogram.h" 12 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/printing/print_job_manager.h" 14 #include "chrome/browser/printing/print_preview_dialog_controller.h" 15 #include "chrome/browser/printing/print_view_manager_observer.h" 16 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" 17 #include "chrome/common/print_messages.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/web_contents.h" 20 21 using content::BrowserThread; 22 23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager); 24 25 namespace { 26 27 // Keeps track of pending scripted print preview closures. 28 // No locking, only access on the UI thread. 29 typedef std::map<content::RenderProcessHost*, base::Closure> 30 ScriptedPrintPreviewClosureMap; 31 static base::LazyInstance<ScriptedPrintPreviewClosureMap> 32 g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER; 33 34 } // namespace 35 36 namespace printing { 37 38 PrintViewManager::PrintViewManager(content::WebContents* web_contents) 39 : PrintViewManagerBase(web_contents), 40 observer_(NULL), 41 print_preview_state_(NOT_PREVIEWING), 42 scripted_print_preview_rph_(NULL) { 43 } 44 45 PrintViewManager::~PrintViewManager() { 46 DCHECK_EQ(NOT_PREVIEWING, print_preview_state_); 47 } 48 49 #if !defined(DISABLE_BASIC_PRINTING) 50 bool PrintViewManager::PrintForSystemDialogNow() { 51 return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id())); 52 } 53 54 bool PrintViewManager::BasicPrint() { 55 PrintPreviewDialogController* dialog_controller = 56 PrintPreviewDialogController::GetInstance(); 57 if (!dialog_controller) 58 return false; 59 content::WebContents* print_preview_dialog = 60 dialog_controller->GetPrintPreviewForContents(web_contents()); 61 if (print_preview_dialog) { 62 if (!print_preview_dialog->GetWebUI()) 63 return false; 64 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>( 65 print_preview_dialog->GetWebUI()->GetController()); 66 print_preview_ui->OnShowSystemDialog(); 67 return true; 68 } else { 69 return PrintNow(); 70 } 71 } 72 #endif // !DISABLE_BASIC_PRINTING 73 bool PrintViewManager::PrintPreviewNow(bool selection_only) { 74 // Users can send print commands all they want and it is beyond 75 // PrintViewManager's control. Just ignore the extra commands. 76 // See http://crbug.com/136842 for example. 77 if (print_preview_state_ != NOT_PREVIEWING) 78 return false; 79 80 if (!PrintNowInternal(new PrintMsg_InitiatePrintPreview(routing_id(), 81 selection_only))) { 82 return false; 83 } 84 85 print_preview_state_ = USER_INITIATED_PREVIEW; 86 return true; 87 } 88 89 void PrintViewManager::PrintPreviewForWebNode() { 90 if (print_preview_state_ != NOT_PREVIEWING) 91 return; 92 print_preview_state_ = USER_INITIATED_PREVIEW; 93 } 94 95 void PrintViewManager::PrintPreviewDone() { 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); 97 DCHECK_NE(NOT_PREVIEWING, print_preview_state_); 98 99 if (print_preview_state_ == SCRIPTED_PREVIEW) { 100 ScriptedPrintPreviewClosureMap& map = 101 g_scripted_print_preview_closure_map.Get(); 102 ScriptedPrintPreviewClosureMap::iterator it = 103 map.find(scripted_print_preview_rph_); 104 CHECK(it != map.end()); 105 it->second.Run(); 106 map.erase(scripted_print_preview_rph_); 107 scripted_print_preview_rph_ = NULL; 108 } 109 print_preview_state_ = NOT_PREVIEWING; 110 } 111 112 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) { 113 DCHECK(!observer || !observer_); 114 observer_ = observer; 115 } 116 117 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { 118 print_preview_state_ = NOT_PREVIEWING; 119 PrintViewManagerBase::RenderProcessGone(status); 120 } 121 122 void PrintViewManager::OnDidShowPrintDialog() { 123 if (observer_) 124 observer_->OnPrintDialogShown(); 125 } 126 127 void PrintViewManager::OnSetupScriptedPrintPreview(IPC::Message* reply_msg) { 128 DCHECK_CURRENTLY_ON(BrowserThread::UI); 129 ScriptedPrintPreviewClosureMap& map = 130 g_scripted_print_preview_closure_map.Get(); 131 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost(); 132 133 // This should always be 0 once we get modal window.print(). 134 if (map.count(rph) != 0) { 135 // Renderer already handling window.print() in another View. 136 Send(reply_msg); 137 return; 138 } 139 if (print_preview_state_ != NOT_PREVIEWING) { 140 // If a user initiated print dialog is already open, ignore the scripted 141 // print message. 142 DCHECK_EQ(USER_INITIATED_PREVIEW, print_preview_state_); 143 Send(reply_msg); 144 return; 145 } 146 147 PrintPreviewDialogController* dialog_controller = 148 PrintPreviewDialogController::GetInstance(); 149 if (!dialog_controller) { 150 Send(reply_msg); 151 return; 152 } 153 154 print_preview_state_ = SCRIPTED_PREVIEW; 155 base::Closure callback = 156 base::Bind(&PrintViewManager::OnScriptedPrintPreviewReply, 157 base::Unretained(this), 158 reply_msg); 159 map[rph] = callback; 160 scripted_print_preview_rph_ = rph; 161 } 162 163 void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) { 164 PrintPreviewDialogController* dialog_controller = 165 PrintPreviewDialogController::GetInstance(); 166 if (!dialog_controller) { 167 PrintPreviewDone(); 168 return; 169 } 170 dialog_controller->PrintPreview(web_contents()); 171 PrintHostMsg_RequestPrintPreview_Params params; 172 params.is_modifiable = source_is_modifiable; 173 PrintPreviewUI::SetInitialParams( 174 dialog_controller->GetPrintPreviewForContents(web_contents()), params); 175 } 176 177 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) { 178 DCHECK_CURRENTLY_ON(BrowserThread::UI); 179 Send(reply_msg); 180 } 181 182 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) { 183 bool handled = true; 184 IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message) 185 IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) 186 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_SetupScriptedPrintPreview, 187 OnSetupScriptedPrintPreview) 188 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowScriptedPrintPreview, 189 OnShowScriptedPrintPreview) 190 IPC_MESSAGE_UNHANDLED(handled = false) 191 IPC_END_MESSAGE_MAP() 192 193 return handled ? true : PrintViewManagerBase::OnMessageReceived(message); 194 } 195 196 } // namespace printing 197