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
PrintViewManager(content::WebContents * web_contents)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
~PrintViewManager()45 PrintViewManager::~PrintViewManager() {
46 DCHECK_EQ(NOT_PREVIEWING, print_preview_state_);
47 }
48
49 #if !defined(DISABLE_BASIC_PRINTING)
PrintForSystemDialogNow()50 bool PrintViewManager::PrintForSystemDialogNow() {
51 return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id()));
52 }
53
BasicPrint()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
PrintPreviewNow(bool selection_only)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
PrintPreviewForWebNode()89 void PrintViewManager::PrintPreviewForWebNode() {
90 if (print_preview_state_ != NOT_PREVIEWING)
91 return;
92 print_preview_state_ = USER_INITIATED_PREVIEW;
93 }
94
PrintPreviewDone()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
set_observer(PrintViewManagerObserver * observer)112 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) {
113 DCHECK(!observer || !observer_);
114 observer_ = observer;
115 }
116
RenderProcessGone(base::TerminationStatus status)117 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) {
118 print_preview_state_ = NOT_PREVIEWING;
119 PrintViewManagerBase::RenderProcessGone(status);
120 }
121
OnDidShowPrintDialog()122 void PrintViewManager::OnDidShowPrintDialog() {
123 if (observer_)
124 observer_->OnPrintDialogShown();
125 }
126
OnSetupScriptedPrintPreview(IPC::Message * reply_msg)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
OnShowScriptedPrintPreview(bool source_is_modifiable)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
OnScriptedPrintPreviewReply(IPC::Message * reply_msg)177 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) {
178 DCHECK_CURRENTLY_ON(BrowserThread::UI);
179 Send(reply_msg);
180 }
181
OnMessageReceived(const IPC::Message & message)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