Reland "Non-SFI mode: Switch to newlib. (patchset #4 id:60001 of https://codereview...
[chromium-blink-merge.git] / chrome / renderer / plugins / chrome_plugin_placeholder.cc
blob165eebb9501b080d14134c464f5d9443f0ecee56
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 "ui/base/l10n/l10n_util.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/base/webui/jstemplate_builder.h"
30 #include "ui/gfx/geometry/size.h"
31 #include "url/url_util.h"
33 using base::UserMetricsAction;
34 using blink::WebDocument;
35 using blink::WebElement;
36 using blink::WebFrame;
37 using blink::WebLocalFrame;
38 using blink::WebMouseEvent;
39 using blink::WebNode;
40 using blink::WebPlugin;
41 using blink::WebPluginContainer;
42 using blink::WebPluginParams;
43 using content::RenderThread;
44 using content::RenderView;
46 namespace {
47 const ChromePluginPlaceholder* g_last_active_menu = NULL;
48 } // namespace
50 gin::WrapperInfo ChromePluginPlaceholder::kWrapperInfo = {
51 gin::kEmbedderNativeGin};
53 ChromePluginPlaceholder::ChromePluginPlaceholder(
54 content::RenderFrame* render_frame,
55 blink::WebLocalFrame* frame,
56 const blink::WebPluginParams& params,
57 const std::string& html_data,
58 const base::string16& title)
59 : plugins::LoadablePluginPlaceholder(render_frame,
60 frame,
61 params,
62 html_data),
63 status_(ChromeViewHostMsg_GetPluginInfo_Status::kAllowed),
64 title_(title),
65 #if defined(ENABLE_PLUGIN_INSTALLATION)
66 placeholder_routing_id_(MSG_ROUTING_NONE),
67 #endif
68 has_host_(false),
69 context_menu_request_id_(0) {
70 RenderThread::Get()->AddObserver(this);
73 ChromePluginPlaceholder::~ChromePluginPlaceholder() {
74 RenderThread::Get()->RemoveObserver(this);
75 if (context_menu_request_id_ && render_frame())
76 render_frame()->CancelContextMenu(context_menu_request_id_);
78 #if defined(ENABLE_PLUGIN_INSTALLATION)
79 if (placeholder_routing_id_ == MSG_ROUTING_NONE)
80 return;
81 RenderThread::Get()->RemoveRoute(placeholder_routing_id_);
82 if (has_host_) {
83 RenderThread::Get()->Send(new ChromeViewHostMsg_RemovePluginPlaceholderHost(
84 routing_id(), placeholder_routing_id_));
86 #endif
89 // static
90 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateLoadableMissingPlugin(
91 content::RenderFrame* render_frame,
92 WebLocalFrame* frame,
93 const WebPluginParams& params) {
94 const base::StringPiece template_html(
95 ResourceBundle::GetSharedInstance().GetRawDataResource(
96 IDR_BLOCKED_PLUGIN_HTML));
98 base::DictionaryValue values;
99 values.SetString("message",
100 l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
102 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
104 // Will destroy itself when its WebViewPlugin is going away.
105 return new ChromePluginPlaceholder(render_frame, frame, params, html_data,
106 params.mimeType);
109 // static
110 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateBlockedPlugin(
111 content::RenderFrame* render_frame,
112 WebLocalFrame* frame,
113 const WebPluginParams& params,
114 const content::WebPluginInfo& info,
115 const std::string& identifier,
116 const base::string16& name,
117 int template_id,
118 const base::string16& message,
119 const PlaceholderPosterInfo& poster_info) {
120 base::DictionaryValue values;
121 values.SetString("message", message);
122 values.SetString("name", name);
123 values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE));
125 if (!poster_info.poster_attribute.empty()) {
126 values.SetString("poster", poster_info.poster_attribute);
127 values.SetString("baseurl", poster_info.base_url.spec());
129 if (!poster_info.custom_poster_size.IsEmpty()) {
130 values.SetString(
131 "visibleWidth",
132 base::IntToString(poster_info.custom_poster_size.width()) + "px");
133 values.SetString(
134 "visibleHeight",
135 base::IntToString(poster_info.custom_poster_size.height()) + "px");
139 const base::StringPiece template_html(
140 ResourceBundle::GetSharedInstance().GetRawDataResource(template_id));
142 DCHECK(!template_html.empty()) << "unable to load template. ID: "
143 << template_id;
144 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
146 // |blocked_plugin| will destroy itself when its WebViewPlugin is going away.
147 ChromePluginPlaceholder* blocked_plugin = new ChromePluginPlaceholder(
148 render_frame, frame, params, html_data, name);
150 if (!poster_info.poster_attribute.empty())
151 blocked_plugin->BlockForPowerSaverPoster();
152 blocked_plugin->SetPluginInfo(info);
153 blocked_plugin->SetIdentifier(identifier);
154 return blocked_plugin;
157 void ChromePluginPlaceholder::SetStatus(
158 ChromeViewHostMsg_GetPluginInfo_Status status) {
159 status_ = status;
162 #if defined(ENABLE_PLUGIN_INSTALLATION)
163 int32 ChromePluginPlaceholder::CreateRoutingId() {
164 placeholder_routing_id_ = RenderThread::Get()->GenerateRoutingID();
165 RenderThread::Get()->AddRoute(placeholder_routing_id_, this);
166 return placeholder_routing_id_;
168 #endif
170 bool ChromePluginPlaceholder::OnMessageReceived(const IPC::Message& message) {
171 #if defined(ENABLE_PLUGIN_INSTALLATION)
172 bool handled = true;
173 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
174 IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin, OnFoundMissingPlugin)
175 IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin,
176 OnDidNotFindMissingPlugin)
177 IPC_MESSAGE_HANDLER(ChromeViewMsg_StartedDownloadingPlugin,
178 OnStartedDownloadingPlugin)
179 IPC_MESSAGE_HANDLER(ChromeViewMsg_FinishedDownloadingPlugin,
180 OnFinishedDownloadingPlugin)
181 IPC_MESSAGE_HANDLER(ChromeViewMsg_ErrorDownloadingPlugin,
182 OnErrorDownloadingPlugin)
183 IPC_MESSAGE_HANDLER(ChromeViewMsg_CancelledDownloadingPlugin,
184 OnCancelledDownloadingPlugin)
185 IPC_MESSAGE_UNHANDLED(handled = false)
186 IPC_END_MESSAGE_MAP()
188 if (handled)
189 return true;
190 #endif
192 // We don't swallow these messages because multiple blocked plugins and other
193 // objects have an interest in them.
194 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
195 IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
196 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
197 IPC_END_MESSAGE_MAP()
199 return false;
202 void ChromePluginPlaceholder::OpenAboutPluginsCallback() {
203 RenderThread::Get()->Send(
204 new ChromeViewHostMsg_OpenAboutPlugins(routing_id()));
207 #if defined(ENABLE_PLUGIN_INSTALLATION)
208 void ChromePluginPlaceholder::OnDidNotFindMissingPlugin() {
209 SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND));
212 void ChromePluginPlaceholder::OnFoundMissingPlugin(
213 const base::string16& plugin_name) {
214 if (status_ == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound)
215 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name));
216 has_host_ = true;
217 plugin_name_ = plugin_name;
220 void ChromePluginPlaceholder::OnStartedDownloadingPlugin() {
221 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_));
224 void ChromePluginPlaceholder::OnFinishedDownloadingPlugin() {
225 bool is_installing =
226 status_ == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
227 SetMessage(l10n_util::GetStringFUTF16(
228 is_installing ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
229 plugin_name_));
232 void ChromePluginPlaceholder::OnErrorDownloadingPlugin(
233 const std::string& error) {
234 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR,
235 base::UTF8ToUTF16(error)));
238 void ChromePluginPlaceholder::OnCancelledDownloadingPlugin() {
239 SetMessage(
240 l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, plugin_name_));
242 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
244 void ChromePluginPlaceholder::PluginListChanged() {
245 if (!GetFrame() || !plugin())
246 return;
247 WebDocument document = GetFrame()->top()->document();
248 if (document.isNull())
249 return;
251 ChromeViewHostMsg_GetPluginInfo_Output output;
252 std::string mime_type(GetPluginParams().mimeType.utf8());
253 render_frame()->Send(
254 new ChromeViewHostMsg_GetPluginInfo(routing_id(),
255 GURL(GetPluginParams().url),
256 document.url(),
257 mime_type,
258 &output));
259 if (output.status == status_)
260 return;
261 WebPlugin* new_plugin = ChromeContentRendererClient::CreatePlugin(
262 render_frame(), GetFrame(), GetPluginParams(), output);
263 ReplacePlugin(new_plugin);
264 if (!new_plugin) {
265 PluginUMAReporter::GetInstance()->ReportPluginMissing(
266 GetPluginParams().mimeType.utf8(), GURL(GetPluginParams().url));
270 void ChromePluginPlaceholder::OnMenuAction(int request_id, unsigned action) {
271 DCHECK_EQ(context_menu_request_id_, request_id);
272 if (g_last_active_menu != this)
273 return;
274 switch (action) {
275 case chrome::MENU_COMMAND_PLUGIN_RUN: {
276 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu"));
277 MarkPluginEssential(
278 content::PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
279 LoadPlugin();
280 break;
282 case chrome::MENU_COMMAND_PLUGIN_HIDE: {
283 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Menu"));
284 HidePlugin();
285 break;
287 default:
288 NOTREACHED();
292 void ChromePluginPlaceholder::OnMenuClosed(int request_id) {
293 DCHECK_EQ(context_menu_request_id_, request_id);
294 context_menu_request_id_ = 0;
297 v8::Local<v8::Value> ChromePluginPlaceholder::GetV8Handle(
298 v8::Isolate* isolate) {
299 return gin::CreateHandle(isolate, this).ToV8();
302 void ChromePluginPlaceholder::ShowContextMenu(const 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 hide_item.enabled = true;
330 hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE);
331 params.custom_items.push_back(hide_item);
333 params.x = event.windowX;
334 params.y = event.windowY;
336 context_menu_request_id_ = render_frame()->ShowContextMenu(this, params);
337 g_last_active_menu = this;
340 blink::WebPlugin* ChromePluginPlaceholder::CreatePlugin() {
341 scoped_ptr<content::PluginInstanceThrottler> throttler;
342 // If the plugin has already been marked essential in its placeholder form,
343 // we shouldn't create a new throttler and start the process all over again.
344 if (power_saver_enabled()) {
345 throttler = content::PluginInstanceThrottler::Create();
346 // PluginPreroller manages its own lifetime.
347 new PluginPreroller(render_frame(), GetFrame(), GetPluginParams(),
348 GetPluginInfo(), GetIdentifier(), title_,
349 l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, title_),
350 throttler.get());
352 return render_frame()->CreatePlugin(GetFrame(), GetPluginInfo(),
353 GetPluginParams(), throttler.Pass());
356 gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder(
357 v8::Isolate* isolate) {
358 return gin::Wrappable<ChromePluginPlaceholder>::GetObjectTemplateBuilder(
359 isolate)
360 .SetMethod<void (ChromePluginPlaceholder::*)()>(
361 "hide", &ChromePluginPlaceholder::HideCallback)
362 .SetMethod<void (ChromePluginPlaceholder::*)()>(
363 "load", &ChromePluginPlaceholder::LoadCallback)
364 .SetMethod<void (ChromePluginPlaceholder::*)()>(
365 "didFinishLoading",
366 &ChromePluginPlaceholder::DidFinishLoadingCallback)
367 .SetMethod("openAboutPlugins",
368 &ChromePluginPlaceholder::OpenAboutPluginsCallback);