OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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/renderer/plugins/chrome_plugin_placeholder.h" | |
6 | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "base/values.h" | |
9 #include "chrome/common/prerender_messages.h" | |
10 #include "chrome/common/render_messages.h" | |
11 #include "chrome/renderer/chrome_content_renderer_client.h" | |
12 #include "chrome/renderer/custom_menu_commands.h" | |
13 #include "content/public/common/context_menu_params.h" | |
14 #include "content/public/renderer/render_thread.h" | |
15 #include "content/public/renderer/render_view.h" | |
16 #include "grit/generated_resources.h" | |
17 #include "grit/renderer_resources.h" | |
18 #include "grit/webkit_strings.h" | |
19 #include "third_party/WebKit/public/web/WebDocument.h" | |
20 #include "third_party/WebKit/public/web/WebFrame.h" | |
21 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
22 #include "third_party/WebKit/public/web/WebScriptSource.h" | |
23 #include "ui/base/l10n/l10n_util.h" | |
24 #include "ui/base/resource/resource_bundle.h" | |
25 #include "ui/webui/jstemplate_builder.h" | |
26 | |
27 using content::RenderThread; | |
28 using content::RenderView; | |
29 using WebKit::WebDocument; | |
30 using WebKit::WebElement; | |
31 using WebKit::WebFrame; | |
32 using WebKit::WebMouseEvent; | |
33 using WebKit::WebNode; | |
34 using WebKit::WebPlugin; | |
35 using WebKit::WebPluginContainer; | |
36 using WebKit::WebPluginParams; | |
37 | |
38 namespace { | |
39 const PluginPlaceholder* g_last_active_menu = NULL; | |
40 } // namespace | |
41 | |
42 ChromePluginPlaceholder::ChromePluginPlaceholder( | |
43 content::RenderView* render_view, | |
44 WebKit::WebFrame* frame, | |
45 const WebKit::WebPluginParams& params, | |
46 const std::string& html_data, | |
47 const string16& title) | |
48 : PluginPlaceholder(render_view, frame, params, html_data), | |
49 status_(new ChromeViewHostMsg_GetPluginInfo_Status), | |
50 title_(title), | |
51 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
52 placeholder_routing_id_(MSG_ROUTING_NONE), | |
53 #endif | |
54 has_host_(false), | |
55 context_menu_request_id_(0) { | |
56 RenderThread::Get()->AddObserver(this); | |
57 } | |
58 | |
59 ChromePluginPlaceholder::~ChromePluginPlaceholder() { | |
60 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
61 if (placeholder_routing_id_ == MSG_ROUTING_NONE) | |
62 return; | |
63 RenderThread::Get()->RemoveRoute(placeholder_routing_id_); | |
64 if (has_host_) { | |
65 RenderThread::Get()->Send(new ChromeViewHostMsg_RemovePluginPlaceholderHost( | |
66 routing_id(), placeholder_routing_id_)); | |
67 } | |
68 #endif | |
69 RenderThread::Get()->RemoveObserver(this); | |
70 if (context_menu_request_id_) | |
71 render_view()->CancelContextMenu(context_menu_request_id_); | |
72 } | |
73 | |
74 // static | |
75 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateMissingPlugin( | |
76 RenderView* render_view, | |
77 WebFrame* frame, | |
78 const WebPluginParams& params) { | |
79 const base::StringPiece template_html( | |
80 ResourceBundle::GetSharedInstance() | |
81 .GetRawDataResource(IDR_BLOCKED_PLUGIN_HTML)); | |
82 | |
83 base::DictionaryValue values; | |
84 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
85 values.SetString("message", l10n_util::GetStringUTF8(IDS_PLUGIN_SEARCHING)); | |
86 #else | |
87 values.SetString("message", | |
88 l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED)); | |
89 #endif | |
90 | |
91 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); | |
92 | |
93 // |missing_plugin| will destroy itself when its WebViewPlugin is going away. | |
94 ChromePluginPlaceholder* missing_plugin = new ChromePluginPlaceholder( | |
95 render_view, frame, params, html_data, params.mimeType); | |
96 missing_plugin->set_allow_loading(true); | |
97 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
98 RenderThread::Get()->Send( | |
99 new ChromeViewHostMsg_FindMissingPlugin(missing_plugin->routing_id(), | |
100 missing_plugin->CreateRoutingId(), | |
101 params.mimeType.utf8())); | |
102 #endif | |
103 return missing_plugin; | |
104 } | |
105 | |
106 // static | |
107 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateErrorPlugin( | |
108 RenderView* render_view, | |
109 const base::FilePath& file_path) { | |
110 base::DictionaryValue values; | |
111 values.SetString("message", | |
112 l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR)); | |
113 | |
114 const base::StringPiece template_html( | |
115 ResourceBundle::GetSharedInstance() | |
116 .GetRawDataResource(IDR_BLOCKED_PLUGIN_HTML)); | |
117 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); | |
118 | |
119 WebPluginParams params; | |
120 // |missing_plugin| will destroy itself when its WebViewPlugin is going away. | |
121 ChromePluginPlaceholder* plugin = new ChromePluginPlaceholder( | |
122 render_view, NULL, params, html_data, params.mimeType); | |
123 | |
124 RenderThread::Get()->Send(new ChromeViewHostMsg_CouldNotLoadPlugin( | |
125 plugin->routing_id(), file_path)); | |
126 return plugin; | |
127 } | |
128 | |
129 // static | |
130 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateBlockedPlugin( | |
131 RenderView* render_view, | |
132 WebFrame* frame, | |
133 const WebPluginParams& params, | |
134 const content::WebPluginInfo& plugin, | |
135 const std::string& identifier, | |
136 const string16& name, | |
137 int template_id, | |
138 const string16& message) { | |
139 base::DictionaryValue values; | |
140 values.SetString("message", message); | |
141 values.SetString("name", name); | |
142 values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE)); | |
143 | |
144 const base::StringPiece template_html( | |
145 ResourceBundle::GetSharedInstance().GetRawDataResource(template_id)); | |
146 | |
147 DCHECK(!template_html.empty()) << "unable to load template. ID: " | |
148 << template_id; | |
149 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); | |
150 | |
151 // |blocked_plugin| will destroy itself when its WebViewPlugin is going away. | |
152 ChromePluginPlaceholder* blocked_plugin = | |
153 new ChromePluginPlaceholder(render_view, frame, params, html_data, name); | |
154 blocked_plugin->SetPluginInfo(plugin); | |
155 blocked_plugin->SetIdentifier(identifier); | |
156 return blocked_plugin; | |
157 } | |
158 | |
159 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN) | |
160 // static | |
161 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateMobileYoutubePlugin( | |
162 content::RenderView* render_view, | |
163 WebFrame* frame, | |
164 const WebPluginParams& params) { | |
165 const base::StringPiece template_html( | |
166 ResourceBundle::GetSharedInstance() | |
167 .GetRawDataResource(IDR_MOBILE_YOUTUBE_PLUGIN_HTML)); | |
168 | |
169 base::DictionaryValue values; | |
170 values.SetString("video_id", PluginPlaceholder::GetYoutubeVideoId(params)); | |
171 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); | |
172 | |
173 // |youtube_plugin| will destroy itself when its WebViewPlugin is going away. | |
174 ChromePluginPlaceholder* youtube_plugin = new ChromePluginPlaceholder( | |
175 render_view, frame, params, html_data, params.mimeType); | |
176 return youtube_plugin; | |
177 } | |
178 #endif | |
179 | |
180 void ChromePluginPlaceholder::SetStatus( | |
181 const ChromeViewHostMsg_GetPluginInfo_Status& status) { | |
182 status_->value = status.value; | |
183 } | |
184 | |
185 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
186 int32 ChromePluginPlaceholder::CreateRoutingId() { | |
187 placeholder_routing_id_ = RenderThread::Get()->GenerateRoutingID(); | |
188 RenderThread::Get()->AddRoute(placeholder_routing_id_, this); | |
189 return placeholder_routing_id_; | |
190 } | |
191 #endif | |
192 | |
193 bool ChromePluginPlaceholder::OnMessageReceived(const IPC::Message& message) { | |
194 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
195 bool handled = true; | |
196 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message) | |
197 IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin, OnFoundMissingPlugin) | |
198 IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin, | |
199 OnDidNotFindMissingPlugin) | |
200 IPC_MESSAGE_HANDLER(ChromeViewMsg_StartedDownloadingPlugin, | |
201 OnStartedDownloadingPlugin) | |
202 IPC_MESSAGE_HANDLER(ChromeViewMsg_FinishedDownloadingPlugin, | |
203 OnFinishedDownloadingPlugin) | |
204 IPC_MESSAGE_HANDLER(ChromeViewMsg_ErrorDownloadingPlugin, | |
205 OnErrorDownloadingPlugin) | |
206 IPC_MESSAGE_HANDLER(ChromeViewMsg_CancelledDownloadingPlugin, | |
207 OnCancelledDownloadingPlugin) | |
208 IPC_MESSAGE_UNHANDLED(handled = false) | |
209 IPC_END_MESSAGE_MAP() | |
210 | |
211 if (handled) | |
212 return true; | |
213 #endif | |
214 | |
215 // We don't swallow these messages because multiple blocked plugins have an | |
216 // interest in them. | |
217 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message) | |
218 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins) | |
219 IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering) | |
220 IPC_END_MESSAGE_MAP() | |
221 | |
222 return false; | |
223 } | |
224 | |
225 void ChromePluginPlaceholder::OnLoadBlockedPlugins( | |
226 const std::string& identifier) { | |
227 PluginPlaceholder::OnLoadBlockedPlugins(identifier); | |
228 } | |
229 | |
230 void ChromePluginPlaceholder::OpenAboutPlugins() { | |
231 RenderThread::Get() | |
232 ->Send(new ChromeViewHostMsg_OpenAboutPlugins(routing_id())); | |
233 } | |
234 | |
235 void ChromePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) { | |
236 PluginPlaceholder::OnSetIsPrerendering(is_prerendering); | |
237 } | |
238 | |
239 #if defined(ENABLE_PLUGIN_INSTALLATION) | |
240 void ChromePluginPlaceholder::OnDidNotFindMissingPlugin() { | |
241 SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND)); | |
242 } | |
243 | |
244 void ChromePluginPlaceholder::OnFoundMissingPlugin( | |
245 const string16& plugin_name) { | |
246 if (status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound) | |
247 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name)); | |
248 has_host_ = true; | |
249 plugin_name_ = plugin_name; | |
250 } | |
251 | |
252 void ChromePluginPlaceholder::OnStartedDownloadingPlugin() { | |
253 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_)); | |
254 } | |
255 | |
256 void ChromePluginPlaceholder::OnFinishedDownloadingPlugin() { | |
257 bool is_installing = | |
258 status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound; | |
259 SetMessage(l10n_util::GetStringFUTF16( | |
260 is_installing ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING, | |
261 plugin_name_)); | |
262 } | |
263 | |
264 void ChromePluginPlaceholder::OnErrorDownloadingPlugin( | |
265 const std::string& error) { | |
266 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR, | |
267 UTF8ToUTF16(error))); | |
268 } | |
269 | |
270 void ChromePluginPlaceholder::OnCancelledDownloadingPlugin() { | |
271 SetMessage( | |
272 l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, plugin_name_)); | |
273 } | |
274 #endif // defined(ENABLE_PLUGIN_INSTALLATION) | |
275 | |
276 void ChromePluginPlaceholder::PluginListChanged() { | |
277 if (!GetFrame()) | |
278 return; | |
279 WebDocument document = GetFrame()->top()->document(); | |
280 if (document.isNull()) | |
281 return; | |
282 | |
283 ChromeViewHostMsg_GetPluginInfo_Output output; | |
284 std::string mime_type(GetPluginParams().mimeType.utf8()); | |
285 render_view() | |
286 ->Send(new ChromeViewHostMsg_GetPluginInfo(routing_id(), | |
Bernhard Bauer
2013/09/09 17:28:07
Can you format this differently, so you don't have
aberent
2013/09/10 13:24:01
I don't particularly like it either, but this is a
| |
287 GURL(GetPluginParams().url), | |
288 document.url(), | |
289 mime_type, | |
290 &output)); | |
291 if (output.status.value == status_->value) | |
292 return; | |
293 WebPlugin* new_plugin = chrome::ChromeContentRendererClient::CreatePlugin( | |
294 render_view(), GetFrame(), GetPluginParams(), output); | |
295 ReplacePlugin(new_plugin); | |
296 } | |
297 | |
298 void ChromePluginPlaceholder::OnMenuAction(int request_id, unsigned action) { | |
299 DCHECK_EQ(context_menu_request_id_, request_id); | |
300 if (g_last_active_menu != this) | |
301 return; | |
302 switch (action) { | |
303 case chrome::MENU_COMMAND_PLUGIN_RUN: { | |
304 RenderThread::Get()->RecordUserMetrics("Plugin_Load_Menu"); | |
305 LoadPlugin(); | |
306 break; | |
307 } | |
308 case chrome::MENU_COMMAND_PLUGIN_HIDE: { | |
309 RenderThread::Get()->RecordUserMetrics("Plugin_Hide_Menu"); | |
310 HidePlugin(); | |
311 break; | |
312 } | |
313 default: | |
314 NOTREACHED(); | |
315 } | |
316 } | |
317 | |
318 void ChromePluginPlaceholder::OnMenuClosed(int request_id) { | |
319 DCHECK_EQ(context_menu_request_id_, request_id); | |
320 context_menu_request_id_ = 0; | |
321 } | |
322 | |
323 void ChromePluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) { | |
324 if (context_menu_request_id_) | |
325 return; // Don't allow nested context menu requests. | |
326 | |
327 content::ContextMenuParams params; | |
328 | |
329 content::MenuItem name_item; | |
330 name_item.label = title_; | |
331 params.custom_items.push_back(name_item); | |
332 | |
333 content::MenuItem separator_item; | |
334 separator_item.type = content::MenuItem::SEPARATOR; | |
335 params.custom_items.push_back(separator_item); | |
336 | |
337 if (!GetPluginInfo().path.value().empty()) { | |
338 content::MenuItem run_item; | |
339 run_item.action = chrome::MENU_COMMAND_PLUGIN_RUN; | |
340 // Disable this menu item if the plugin is blocked by policy. | |
341 run_item.enabled = LoadingAllowed(); | |
342 run_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_RUN); | |
343 params.custom_items.push_back(run_item); | |
344 } | |
345 | |
346 content::MenuItem hide_item; | |
347 hide_item.action = chrome::MENU_COMMAND_PLUGIN_HIDE; | |
348 hide_item.enabled = true; | |
349 hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE); | |
350 params.custom_items.push_back(hide_item); | |
351 | |
352 params.x = event.windowX; | |
353 params.y = event.windowY; | |
354 | |
355 context_menu_request_id_ = render_view()->ShowContextMenu(this, params); | |
356 g_last_active_menu = this; | |
357 } | |
OLD | NEW |