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 #include "printing/print_destination_interface.h" 21 22 using content::BrowserThread; 23 24 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager); 25 26 namespace { 27 28 // Keeps track of pending scripted print preview closures. 29 // No locking, only access on the UI thread. 30 typedef std::map<content::RenderProcessHost*, base::Closure> 31 ScriptedPrintPreviewClosureMap; 32 static base::LazyInstance<ScriptedPrintPreviewClosureMap> 33 g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER; 34 35 } // namespace 36 37 namespace printing { 38 39 PrintViewManager::PrintViewManager(content::WebContents* web_contents) 40 : PrintViewManagerBase(web_contents), 41 observer_(NULL), 42 print_preview_state_(NOT_PREVIEWING), 43 scripted_print_preview_rph_(NULL) { 44 } 45 46 PrintViewManager::~PrintViewManager() { 47 DCHECK_EQ(NOT_PREVIEWING, print_preview_state_); 48 } 49 50 bool PrintViewManager::PrintForSystemDialogNow() { 51 return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id())); 52 } 53 54 bool PrintViewManager::AdvancedPrintNow() { 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 73 bool PrintViewManager::PrintToDestination() { 74 // TODO(mad): Remove this once we can send user metrics from the metro driver. 75 // crbug.com/142330 76 UMA_HISTOGRAM_ENUMERATION("Metro.Print", 0, 2); 77 // TODO(mad): Use a passed in destination interface instead. 78 g_browser_process->print_job_manager()->queue()->SetDestination( 79 printing::CreatePrintDestination()); 80 return PrintNowInternal(new PrintMsg_PrintPages(routing_id())); 81 } 82 83 bool PrintViewManager::PrintPreviewNow(bool selection_only) { 84 // Users can send print commands all they want and it is beyond 85 // PrintViewManager's control. Just ignore the extra commands. 86 // See http://crbug.com/136842 for example. 87 if (print_preview_state_ != NOT_PREVIEWING) 88 return false; 89 90 if (!PrintNowInternal(new PrintMsg_InitiatePrintPreview(routing_id(), 91 selection_only))) { 92 return false; 93 } 94 95 print_preview_state_ = USER_INITIATED_PREVIEW; 96 return true; 97 } 98 99 void PrintViewManager::PrintPreviewForWebNode() { 100 if (print_preview_state_ != NOT_PREVIEWING) 101 return; 102 print_preview_state_ = USER_INITIATED_PREVIEW; 103 } 104 105 void PrintViewManager::PrintPreviewDone() { 106 DCHECK_CURRENTLY_ON(BrowserThread::UI); 107 DCHECK_NE(NOT_PREVIEWING, print_preview_state_); 108 109 if (print_preview_state_ == SCRIPTED_PREVIEW) { 110 ScriptedPrintPreviewClosureMap& map = 111 g_scripted_print_preview_closure_map.Get(); 112 ScriptedPrintPreviewClosureMap::iterator it = 113 map.find(scripted_print_preview_rph_); 114 CHECK(it != map.end()); 115 it->second.Run(); 116 map.erase(scripted_print_preview_rph_); 117 scripted_print_preview_rph_ = NULL; 118 } 119 print_preview_state_ = NOT_PREVIEWING; 120 } 121 122 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) { 123 DCHECK(!observer || !observer_); 124 observer_ = observer; 125 } 126 127 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { 128 print_preview_state_ = NOT_PREVIEWING; 129 PrintViewManagerBase::RenderProcessGone(status); 130 } 131 132 void PrintViewManager::OnDidShowPrintDialog() { 133 if (observer_) 134 observer_->OnPrintDialogShown(); 135 } 136 137 void PrintViewManager::OnSetupScriptedPrintPreview(IPC::Message* reply_msg) { 138 DCHECK_CURRENTLY_ON(BrowserThread::UI); 139 ScriptedPrintPreviewClosureMap& map = 140 g_scripted_print_preview_closure_map.Get(); 141 content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost(); 142 143 // This should always be 0 once we get modal window.print(). 144 if (map.count(rph) != 0) { 145 // Renderer already handling window.print() in another View. 146 Send(reply_msg); 147 return; 148 } 149 if (print_preview_state_ != NOT_PREVIEWING) { 150 // If a user initiated print dialog is already open, ignore the scripted 151 // print message. 152 DCHECK_EQ(USER_INITIATED_PREVIEW, print_preview_state_); 153 Send(reply_msg); 154 return; 155 } 156 157 PrintPreviewDialogController* dialog_controller = 158 PrintPreviewDialogController::GetInstance(); 159 if (!dialog_controller) { 160 Send(reply_msg); 161 return; 162 } 163 164 print_preview_state_ = SCRIPTED_PREVIEW; 165 base::Closure callback = 166 base::Bind(&PrintViewManager::OnScriptedPrintPreviewReply, 167 base::Unretained(this), 168 reply_msg); 169 map[rph] = callback; 170 scripted_print_preview_rph_ = rph; 171 } 172 173 void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) { 174 PrintPreviewDialogController* dialog_controller = 175 PrintPreviewDialogController::GetInstance(); 176 if (!dialog_controller) { 177 PrintPreviewDone(); 178 return; 179 } 180 dialog_controller->PrintPreview(web_contents()); 181 PrintHostMsg_RequestPrintPreview_Params params; 182 params.is_modifiable = source_is_modifiable; 183 PrintPreviewUI::SetInitialParams( 184 dialog_controller->GetPrintPreviewForContents(web_contents()), params); 185 } 186 187 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) { 188 DCHECK_CURRENTLY_ON(BrowserThread::UI); 189 Send(reply_msg); 190 } 191 192 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) { 193 bool handled = true; 194 IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message) 195 IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) 196 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_SetupScriptedPrintPreview, 197 OnSetupScriptedPrintPreview) 198 IPC_MESSAGE_HANDLER(PrintHostMsg_ShowScriptedPrintPreview, 199 OnShowScriptedPrintPreview) 200 IPC_MESSAGE_UNHANDLED(handled = false) 201 IPC_END_MESSAGE_MAP() 202 203 return handled ? true : PrintViewManagerBase::OnMessageReceived(message); 204 } 205 206 } // namespace printing 207