Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / renderer / plugins / chrome_plugin_placeholder.cc
blobc1fe2b4ef04a8fbdaceb151b947097bfab91283d
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.
5 #include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/values.h"
10 #include "chrome/common/prerender_messages.h"
11 #include "chrome/common/render_messages.h"
12 #include "chrome/grit/generated_resources.h"
13 #include "chrome/grit/renderer_resources.h"
14 #include "chrome/renderer/chrome_content_renderer_client.h"
15 #include "chrome/renderer/custom_menu_commands.h"
16 #include "chrome/renderer/plugins/plugin_preroller.h"
17 #include "chrome/renderer/plugins/plugin_uma.h"
18 #include "components/content_settings/content/common/content_settings_messages.h"
19 #include "content/public/common/context_menu_params.h"
20 #include "content/public/renderer/render_frame.h"
21 #include "content/public/renderer/render_thread.h"
22 #include "gin/object_template_builder.h"
23 #include "third_party/WebKit/public/web/WebDocument.h"
24 #include "third_party/WebKit/public/web/WebInputEvent.h"
25 #include "third_party/WebKit/public/web/WebLocalFrame.h"
26 #include "third_party/WebKit/public/web/WebScriptSource.h"
27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/base/webui/jstemplate_builder.h"
31 #include "ui/gfx/geometry/size.h"
32 #include "url/url_util.h"
34 using base::UserMetricsAction;
35 using content::RenderThread;
36 using content::RenderView;
38 namespace {
39 const ChromePluginPlaceholder* g_last_active_menu = NULL;
40 } // namespace
42 gin::WrapperInfo ChromePluginPlaceholder::kWrapperInfo = {
43 gin::kEmbedderNativeGin};
45 ChromePluginPlaceholder::ChromePluginPlaceholder(
46 content::RenderFrame* render_frame,
47 blink::WebLocalFrame* frame,
48 const blink::WebPluginParams& params,
49 const std::string& html_data,
50 const base::string16& title)
51 : plugins::LoadablePluginPlaceholder(render_frame,
52 frame,
53 params,
54 html_data),
55 status_(ChromeViewHostMsg_GetPluginInfo_Status::kAllowed),
56 title_(title),
57 #if defined(ENABLE_PLUGIN_INSTALLATION)
58 placeholder_routing_id_(MSG_ROUTING_NONE),
59 #endif
60 has_host_(false),
61 context_menu_request_id_(0) {
62 RenderThread::Get()->AddObserver(this);
65 ChromePluginPlaceholder::~ChromePluginPlaceholder() {
66 RenderThread::Get()->RemoveObserver(this);
67 if (context_menu_request_id_ && render_frame())
68 render_frame()->CancelContextMenu(context_menu_request_id_);
70 #if defined(ENABLE_PLUGIN_INSTALLATION)
71 if (placeholder_routing_id_ == MSG_ROUTING_NONE)
72 return;
73 RenderThread::Get()->RemoveRoute(placeholder_routing_id_);
74 if (has_host_) {
75 RenderThread::Get()->Send(new ChromeViewHostMsg_RemovePluginPlaceholderHost(
76 routing_id(), placeholder_routing_id_));
78 #endif
81 // static
82 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateLoadableMissingPlugin(
83 content::RenderFrame* render_frame,
84 blink::WebLocalFrame* frame,
85 const blink::WebPluginParams& params) {
86 const base::StringPiece template_html(
87 ResourceBundle::GetSharedInstance().GetRawDataResource(
88 IDR_BLOCKED_PLUGIN_HTML));
90 base::DictionaryValue values;
91 values.SetString("message",
92 l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
94 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
96 // Will destroy itself when its WebViewPlugin is going away.
97 return new ChromePluginPlaceholder(render_frame, frame, params, html_data,
98 params.mimeType);
101 // static
102 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateBlockedPlugin(
103 content::RenderFrame* render_frame,
104 blink::WebLocalFrame* frame,
105 const blink::WebPluginParams& params,
106 const content::WebPluginInfo& info,
107 const std::string& identifier,
108 const base::string16& name,
109 int template_id,
110 const base::string16& message,
111 const PlaceholderPosterInfo& poster_info) {
112 base::DictionaryValue values;
113 values.SetString("message", message);
114 values.SetString("name", name);
115 values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE));
116 values.SetString("pluginType",
117 frame->view()->mainFrame()->isWebLocalFrame() &&
118 frame->view()->mainFrame()->document().isPluginDocument()
119 ? "document"
120 : "embedded");
122 if (!poster_info.poster_attribute.empty()) {
123 values.SetString("poster", poster_info.poster_attribute);
124 values.SetString("baseurl", poster_info.base_url.spec());
126 if (!poster_info.custom_poster_size.IsEmpty()) {
127 float zoom_factor =
128 blink::WebView::zoomLevelToZoomFactor(frame->view()->zoomLevel());
129 int width = roundf(poster_info.custom_poster_size.width() / zoom_factor);
130 int height =
131 roundf(poster_info.custom_poster_size.height() / zoom_factor);
132 values.SetString("visibleWidth", base::IntToString(width) + "px");
133 values.SetString("visibleHeight", base::IntToString(height) + "px");
137 const base::StringPiece template_html(
138 ResourceBundle::GetSharedInstance().GetRawDataResource(template_id));
140 DCHECK(!template_html.empty()) << "unable to load template. ID: "
141 << template_id;
142 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
144 // |blocked_plugin| will destroy itself when its WebViewPlugin is going away.
145 ChromePluginPlaceholder* blocked_plugin = new ChromePluginPlaceholder(
146 render_frame, frame, params, html_data, name);
148 if (!poster_info.poster_attribute.empty())
149 blocked_plugin->BlockForPowerSaverPoster();
150 blocked_plugin->SetPluginInfo(info);
151 blocked_plugin->SetIdentifier(identifier);
152 return blocked_plugin;
155 void ChromePluginPlaceholder::SetStatus(
156 ChromeViewHostMsg_GetPluginInfo_Status status) {
157 status_ = status;
160 #if defined(ENABLE_PLUGIN_INSTALLATION)
161 int32 ChromePluginPlaceholder::CreateRoutingId() {
162 placeholder_routing_id_ = RenderThread::Get()->GenerateRoutingID();
163 RenderThread::Get()->AddRoute(placeholder_routing_id_, this);
164 return placeholder_routing_id_;
166 #endif
168 bool ChromePluginPlaceholder::OnMessageReceived(const IPC::Message& message) {
169 #if defined(ENABLE_PLUGIN_INSTALLATION)
170 bool handled = true;
171 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
172 IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin, OnFoundMissingPlugin)
173 IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin,
174 OnDidNotFindMissingPlugin)
175 IPC_MESSAGE_HANDLER(ChromeViewMsg_StartedDownloadingPlugin,
176 OnStartedDownloadingPlugin)
177 IPC_MESSAGE_HANDLER(ChromeViewMsg_FinishedDownloadingPlugin,
178 OnFinishedDownloadingPlugin)
179 IPC_MESSAGE_HANDLER(ChromeViewMsg_ErrorDownloadingPlugin,
180 OnErrorDownloadingPlugin)
181 IPC_MESSAGE_HANDLER(ChromeViewMsg_CancelledDownloadingPlugin,
182 OnCancelledDownloadingPlugin)
183 IPC_MESSAGE_UNHANDLED(handled = false)
184 IPC_END_MESSAGE_MAP()
186 if (handled)
187 return true;
188 #endif
190 // We don't swallow these messages because multiple blocked plugins and other
191 // objects have an interest in them.
192 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
193 IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
194 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
195 IPC_END_MESSAGE_MAP()
197 return false;
200 void ChromePluginPlaceholder::OpenAboutPluginsCallback() {
201 RenderThread::Get()->Send(
202 new ChromeViewHostMsg_OpenAboutPlugins(routing_id()));
205 #if defined(ENABLE_PLUGIN_INSTALLATION)
206 void ChromePluginPlaceholder::OnDidNotFindMissingPlugin() {
207 SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND));
210 void ChromePluginPlaceholder::OnFoundMissingPlugin(
211 const base::string16& plugin_name) {
212 if (status_ == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound)
213 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name));
214 has_host_ = true;
215 plugin_name_ = plugin_name;
218 void ChromePluginPlaceholder::OnStartedDownloadingPlugin() {
219 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_));
222 void ChromePluginPlaceholder::OnFinishedDownloadingPlugin() {
223 bool is_installing =
224 status_ == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
225 SetMessage(l10n_util::GetStringFUTF16(
226 is_installing ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
227 plugin_name_));
230 void ChromePluginPlaceholder::OnErrorDownloadingPlugin(
231 const std::string& error) {
232 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR,
233 base::UTF8ToUTF16(error)));
236 void ChromePluginPlaceholder::OnCancelledDownloadingPlugin() {
237 SetMessage(
238 l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, plugin_name_));
240 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
242 void ChromePluginPlaceholder::PluginListChanged() {
243 if (!GetFrame() || !plugin())
244 return;
245 blink::WebDocument document = GetFrame()->top()->document();
246 if (document.isNull())
247 return;
249 ChromeViewHostMsg_GetPluginInfo_Output output;
250 std::string mime_type(GetPluginParams().mimeType.utf8());
251 blink::WebString top_origin = GetFrame()->top()->securityOrigin().toString();
252 render_frame()->Send(
253 new ChromeViewHostMsg_GetPluginInfo(routing_id(),
254 GURL(GetPluginParams().url),
255 GURL(top_origin),
256 mime_type,
257 &output));
258 if (output.status == status_)
259 return;
260 blink::WebPlugin* new_plugin = ChromeContentRendererClient::CreatePlugin(
261 render_frame(), GetFrame(), GetPluginParams(), output);
262 ReplacePlugin(new_plugin);
263 if (!new_plugin) {
264 PluginUMAReporter::GetInstance()->ReportPluginMissing(
265 GetPluginParams().mimeType.utf8(), GURL(GetPluginParams().url));
269 void ChromePluginPlaceholder::OnMenuAction(int request_id, unsigned action) {
270 DCHECK_EQ(context_menu_request_id_, request_id);
271 if (g_last_active_menu != this)
272 return;
273 switch (action) {
274 case chrome::MENU_COMMAND_PLUGIN_RUN: {
275 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu"));
276 MarkPluginEssential(
277 content::PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
278 LoadPlugin();
279 break;
281 case chrome::MENU_COMMAND_PLUGIN_HIDE: {
282 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Menu"));
283 HidePlugin();
284 break;
286 default:
287 NOTREACHED();
291 void ChromePluginPlaceholder::OnMenuClosed(int request_id) {
292 DCHECK_EQ(context_menu_request_id_, request_id);
293 context_menu_request_id_ = 0;
296 v8::Local<v8::Value> ChromePluginPlaceholder::GetV8Handle(
297 v8::Isolate* isolate) {
298 return gin::CreateHandle(isolate, this).ToV8();
301 void ChromePluginPlaceholder::ShowContextMenu(
302 const blink::WebMouseEvent& event) {
303 if (context_menu_request_id_)
304 return; // Don't allow nested context menu requests.
306 content::ContextMenuParams params;
308 if (!title_.empty()) {
309 content::MenuItem name_item;
310 name_item.label = title_;
311 params.custom_items.push_back(name_item);
313 content::MenuItem separator_item;
314 separator_item.type = content::MenuItem::SEPARATOR;
315 params.custom_items.push_back(separator_item);
318 if (!GetPluginInfo().path.value().empty()) {
319 content::MenuItem run_item;
320 run_item.action = chrome::MENU_COMMAND_PLUGIN_RUN;
321 // Disable this menu item if the plugin is blocked by policy.
322 run_item.enabled = LoadingAllowed();
323 run_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_RUN);
324 params.custom_items.push_back(run_item);
327 content::MenuItem hide_item;
328 hide_item.action = chrome::MENU_COMMAND_PLUGIN_HIDE;
329 bool is_main_frame_plugin_document =
330 GetFrame()->view()->mainFrame()->isWebLocalFrame() &&
331 GetFrame()->view()->mainFrame()->document().isPluginDocument();
332 hide_item.enabled = !is_main_frame_plugin_document;
333 hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE);
334 params.custom_items.push_back(hide_item);
336 params.x = event.windowX;
337 params.y = event.windowY;
339 context_menu_request_id_ = render_frame()->ShowContextMenu(this, params);
340 g_last_active_menu = this;
343 blink::WebPlugin* ChromePluginPlaceholder::CreatePlugin() {
344 scoped_ptr<content::PluginInstanceThrottler> throttler;
345 // If the plugin has already been marked essential in its placeholder form,
346 // we shouldn't create a new throttler and start the process all over again.
347 if (power_saver_enabled()) {
348 throttler = content::PluginInstanceThrottler::Create();
349 // PluginPreroller manages its own lifetime.
350 new PluginPreroller(render_frame(), GetFrame(), GetPluginParams(),
351 GetPluginInfo(), GetIdentifier(), title_,
352 l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, title_),
353 throttler.get());
355 return render_frame()->CreatePlugin(GetFrame(), GetPluginInfo(),
356 GetPluginParams(), throttler.Pass());
359 gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder(
360 v8::Isolate* isolate) {
361 return gin::Wrappable<ChromePluginPlaceholder>::GetObjectTemplateBuilder(
362 isolate)
363 .SetMethod<void (ChromePluginPlaceholder::*)()>(
364 "hide", &ChromePluginPlaceholder::HideCallback)
365 .SetMethod<void (ChromePluginPlaceholder::*)()>(
366 "load", &ChromePluginPlaceholder::LoadCallback)
367 .SetMethod<void (ChromePluginPlaceholder::*)()>(
368 "didFinishLoading",
369 &ChromePluginPlaceholder::DidFinishLoadingCallback)
370 .SetMethod("openAboutPlugins",
371 &ChromePluginPlaceholder::OpenAboutPluginsCallback);