Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / chrome / renderer / plugins / chrome_plugin_placeholder.cc
blob862627c67455f30bdaf1d69e16d838c14edac3f6
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_uma.h"
17 #include "content/app/strings/grit/content_strings.h"
18 #include "content/public/common/context_menu_params.h"
19 #include "content/public/renderer/render_frame.h"
20 #include "content/public/renderer/render_thread.h"
21 #include "gin/handle.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/WebKit.h"
26 #include "third_party/WebKit/public/web/WebLocalFrame.h"
27 #include "third_party/WebKit/public/web/WebScriptSource.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 blink::WebDocument;
36 using blink::WebElement;
37 using blink::WebFrame;
38 using blink::WebLocalFrame;
39 using blink::WebMouseEvent;
40 using blink::WebNode;
41 using blink::WebPlugin;
42 using blink::WebPluginContainer;
43 using blink::WebPluginParams;
44 using content::RenderThread;
45 using content::RenderView;
47 namespace {
48 const plugins::PluginPlaceholder* g_last_active_menu = NULL;
49 } // namespace
51 // The placeholder is loaded in normal web renderer processes, so it should not
52 // have a chrome:// scheme that might let it be confused with a WebUI page.
53 const char ChromePluginPlaceholder::kPluginPlaceholderDataURL[] =
54 "data:text/html,pluginplaceholderdata";
56 ChromePluginPlaceholder::ChromePluginPlaceholder(
57 content::RenderFrame* render_frame,
58 blink::WebLocalFrame* frame,
59 const blink::WebPluginParams& params,
60 const std::string& html_data,
61 const base::string16& title)
62 : plugins::LoadablePluginPlaceholder(render_frame,
63 frame,
64 params,
65 html_data,
66 GURL(kPluginPlaceholderDataURL)),
67 status_(new ChromeViewHostMsg_GetPluginInfo_Status),
68 title_(title),
69 #if defined(ENABLE_PLUGIN_INSTALLATION)
70 placeholder_routing_id_(MSG_ROUTING_NONE),
71 #endif
72 has_host_(false),
73 context_menu_request_id_(0) {
74 RenderThread::Get()->AddObserver(this);
77 ChromePluginPlaceholder::~ChromePluginPlaceholder() {
78 RenderThread::Get()->RemoveObserver(this);
79 if (context_menu_request_id_ && render_frame())
80 render_frame()->CancelContextMenu(context_menu_request_id_);
82 #if defined(ENABLE_PLUGIN_INSTALLATION)
83 if (placeholder_routing_id_ == MSG_ROUTING_NONE)
84 return;
85 RenderThread::Get()->RemoveRoute(placeholder_routing_id_);
86 if (has_host_) {
87 RenderThread::Get()->Send(new ChromeViewHostMsg_RemovePluginPlaceholderHost(
88 routing_id(), placeholder_routing_id_));
90 #endif
93 // static
94 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateMissingPlugin(
95 content::RenderFrame* render_frame,
96 WebLocalFrame* frame,
97 const WebPluginParams& params) {
98 const base::StringPiece template_html(
99 ResourceBundle::GetSharedInstance().GetRawDataResource(
100 IDR_BLOCKED_PLUGIN_HTML));
102 base::DictionaryValue values;
103 values.SetString("message",
104 l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
106 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
108 // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
109 ChromePluginPlaceholder* missing_plugin = new ChromePluginPlaceholder(
110 render_frame, frame, params, html_data, params.mimeType);
111 missing_plugin->set_allow_loading(true);
112 return missing_plugin;
115 // static
116 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateErrorPlugin(
117 content::RenderFrame* render_frame,
118 const base::FilePath& file_path) {
119 base::DictionaryValue values;
120 values.SetString("message",
121 l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR));
123 const base::StringPiece template_html(
124 ResourceBundle::GetSharedInstance().GetRawDataResource(
125 IDR_BLOCKED_PLUGIN_HTML));
126 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
128 WebPluginParams params;
129 // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
130 ChromePluginPlaceholder* plugin = new ChromePluginPlaceholder(
131 render_frame, NULL, params, html_data, params.mimeType);
133 RenderThread::Get()->Send(new ChromeViewHostMsg_CouldNotLoadPlugin(
134 plugin->routing_id(), file_path));
135 return plugin;
138 // static
139 ChromePluginPlaceholder* ChromePluginPlaceholder::CreateBlockedPlugin(
140 content::RenderFrame* render_frame,
141 WebLocalFrame* frame,
142 const WebPluginParams& params,
143 const content::WebPluginInfo& info,
144 const std::string& identifier,
145 const base::string16& name,
146 int template_id,
147 const base::string16& message,
148 const PlaceholderPosterInfo& poster_info) {
149 base::DictionaryValue values;
150 values.SetString("message", message);
151 values.SetString("name", name);
152 values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE));
154 if (!poster_info.poster_attribute.empty()) {
155 values.SetString("poster", poster_info.poster_attribute);
156 values.SetString("baseurl", poster_info.base_url.spec());
158 if (!poster_info.custom_poster_size.IsEmpty()) {
159 values.SetString(
160 "visibleWidth",
161 base::IntToString(poster_info.custom_poster_size.width()) + "px");
162 values.SetString(
163 "visibleHeight",
164 base::IntToString(poster_info.custom_poster_size.height()) + "px");
168 const base::StringPiece template_html(
169 ResourceBundle::GetSharedInstance().GetRawDataResource(template_id));
171 DCHECK(!template_html.empty()) << "unable to load template. ID: "
172 << template_id;
173 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
175 // |blocked_plugin| will destroy itself when its WebViewPlugin is going away.
176 ChromePluginPlaceholder* blocked_plugin = new ChromePluginPlaceholder(
177 render_frame, frame, params, html_data, name);
179 #if defined(ENABLE_PLUGINS)
180 if (!poster_info.poster_attribute.empty())
181 blocked_plugin->BlockForPowerSaverPoster();
182 #endif
183 blocked_plugin->SetPluginInfo(info);
184 blocked_plugin->SetIdentifier(identifier);
185 return blocked_plugin;
188 void ChromePluginPlaceholder::SetStatus(
189 const ChromeViewHostMsg_GetPluginInfo_Status& status) {
190 status_->value = status.value;
193 #if defined(ENABLE_PLUGIN_INSTALLATION)
194 int32 ChromePluginPlaceholder::CreateRoutingId() {
195 placeholder_routing_id_ = RenderThread::Get()->GenerateRoutingID();
196 RenderThread::Get()->AddRoute(placeholder_routing_id_, this);
197 return placeholder_routing_id_;
199 #endif
201 bool ChromePluginPlaceholder::OnMessageReceived(const IPC::Message& message) {
202 #if defined(ENABLE_PLUGIN_INSTALLATION)
203 bool handled = true;
204 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
205 IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin, OnFoundMissingPlugin)
206 IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin,
207 OnDidNotFindMissingPlugin)
208 IPC_MESSAGE_HANDLER(ChromeViewMsg_StartedDownloadingPlugin,
209 OnStartedDownloadingPlugin)
210 IPC_MESSAGE_HANDLER(ChromeViewMsg_FinishedDownloadingPlugin,
211 OnFinishedDownloadingPlugin)
212 IPC_MESSAGE_HANDLER(ChromeViewMsg_ErrorDownloadingPlugin,
213 OnErrorDownloadingPlugin)
214 IPC_MESSAGE_HANDLER(ChromeViewMsg_CancelledDownloadingPlugin,
215 OnCancelledDownloadingPlugin)
216 IPC_MESSAGE_UNHANDLED(handled = false)
217 IPC_END_MESSAGE_MAP()
219 if (handled)
220 return true;
221 #endif
223 // We don't swallow these messages because multiple blocked plugins and other
224 // objects have an interest in them.
225 IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message)
226 IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
227 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
228 IPC_END_MESSAGE_MAP()
230 return false;
233 void ChromePluginPlaceholder::OpenAboutPluginsCallback() {
234 RenderThread::Get()->Send(
235 new ChromeViewHostMsg_OpenAboutPlugins(routing_id()));
238 #if defined(ENABLE_PLUGIN_INSTALLATION)
239 void ChromePluginPlaceholder::OnDidNotFindMissingPlugin() {
240 SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND));
243 void ChromePluginPlaceholder::OnFoundMissingPlugin(
244 const base::string16& plugin_name) {
245 if (status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound)
246 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name));
247 has_host_ = true;
248 plugin_name_ = plugin_name;
251 void ChromePluginPlaceholder::OnStartedDownloadingPlugin() {
252 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_));
255 void ChromePluginPlaceholder::OnFinishedDownloadingPlugin() {
256 bool is_installing =
257 status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
258 SetMessage(l10n_util::GetStringFUTF16(
259 is_installing ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
260 plugin_name_));
263 void ChromePluginPlaceholder::OnErrorDownloadingPlugin(
264 const std::string& error) {
265 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR,
266 base::UTF8ToUTF16(error)));
269 void ChromePluginPlaceholder::OnCancelledDownloadingPlugin() {
270 SetMessage(
271 l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, plugin_name_));
273 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
275 void ChromePluginPlaceholder::PluginListChanged() {
276 if (!GetFrame() || !plugin())
277 return;
278 WebDocument document = GetFrame()->top()->document();
279 if (document.isNull())
280 return;
282 ChromeViewHostMsg_GetPluginInfo_Output output;
283 std::string mime_type(GetPluginParams().mimeType.utf8());
284 render_frame()->Send(
285 new ChromeViewHostMsg_GetPluginInfo(routing_id(),
286 GURL(GetPluginParams().url),
287 document.url(),
288 mime_type,
289 &output));
290 if (output.status.value == status_->value)
291 return;
292 WebPlugin* new_plugin = ChromeContentRendererClient::CreatePlugin(
293 render_frame(), GetFrame(), GetPluginParams(), output);
294 ReplacePlugin(new_plugin);
295 if (!new_plugin) {
296 PluginUMAReporter::GetInstance()->ReportPluginMissing(
297 GetPluginParams().mimeType.utf8(), GURL(GetPluginParams().url));
301 void ChromePluginPlaceholder::OnMenuAction(int request_id, unsigned action) {
302 DCHECK_EQ(context_menu_request_id_, request_id);
303 if (g_last_active_menu != this)
304 return;
305 switch (action) {
306 case chrome::MENU_COMMAND_PLUGIN_RUN: {
307 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu"));
308 #if defined(ENABLE_PLUGINS)
309 MarkPluginEssential(
310 content::PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
311 #endif
312 LoadPlugin();
313 break;
315 case chrome::MENU_COMMAND_PLUGIN_HIDE: {
316 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Menu"));
317 HidePlugin();
318 break;
320 default:
321 NOTREACHED();
325 void ChromePluginPlaceholder::OnMenuClosed(int request_id) {
326 DCHECK_EQ(context_menu_request_id_, request_id);
327 context_menu_request_id_ = 0;
330 void ChromePluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) {
331 #if !defined(OS_ANDROID) // The context menu is not applicable on Android.
332 if (context_menu_request_id_)
333 return; // Don't allow nested context menu requests.
335 content::ContextMenuParams params;
337 if (!title_.empty()) {
338 content::MenuItem name_item;
339 name_item.label = title_;
340 params.custom_items.push_back(name_item);
342 content::MenuItem separator_item;
343 separator_item.type = content::MenuItem::SEPARATOR;
344 params.custom_items.push_back(separator_item);
347 if (!GetPluginInfo().path.value().empty()) {
348 content::MenuItem run_item;
349 run_item.action = chrome::MENU_COMMAND_PLUGIN_RUN;
350 // Disable this menu item if the plugin is blocked by policy.
351 run_item.enabled = LoadingAllowed();
352 run_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_RUN);
353 params.custom_items.push_back(run_item);
356 content::MenuItem hide_item;
357 hide_item.action = chrome::MENU_COMMAND_PLUGIN_HIDE;
358 hide_item.enabled = true;
359 hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE);
360 params.custom_items.push_back(hide_item);
362 params.x = event.windowX;
363 params.y = event.windowY;
365 context_menu_request_id_ = render_frame()->ShowContextMenu(this, params);
366 g_last_active_menu = this;
367 #endif // OS_ANDROID
370 void ChromePluginPlaceholder::BindWebFrame(blink::WebFrame* frame) {
371 v8::Isolate* isolate = blink::mainThreadIsolate();
372 v8::HandleScope handle_scope(isolate);
373 v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
374 DCHECK(!context.IsEmpty());
376 v8::Context::Scope context_scope(context);
377 v8::Handle<v8::Object> global = context->Global();
378 global->Set(gin::StringToV8(isolate, "plugin"),
379 gin::CreateHandle(isolate, this).ToV8());
382 gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder(
383 v8::Isolate* isolate) {
384 return LoadablePluginPlaceholder::GetObjectTemplateBuilder(isolate).SetMethod(
385 "openAboutPlugins", &ChromePluginPlaceholder::OpenAboutPluginsCallback);