Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: chrome/renderer/plugins/plugin_placeholder.cc

Issue 27197004: Move renderer plugin code into a new component (re-land) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move renderer plugin code into a new component (re-land) - fix nit and rebase Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/renderer/plugins/plugin_placeholder.h ('k') | chrome/renderer/plugins/plugin_uma.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/renderer/plugins/plugin_placeholder.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/json/string_escape.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/common/prerender_messages.h"
15 #include "chrome/common/render_messages.h"
16 #include "chrome/renderer/chrome_content_renderer_client.h"
17 #include "chrome/renderer/custom_menu_commands.h"
18 #include "chrome/renderer/plugins/plugin_uma.h"
19 #include "content/public/common/content_constants.h"
20 #include "content/public/common/context_menu_params.h"
21 #include "content/public/renderer/render_thread.h"
22 #include "content/public/renderer/render_view.h"
23 #include "grit/generated_resources.h"
24 #include "grit/renderer_resources.h"
25 #include "grit/webkit_strings.h"
26 #include "third_party/WebKit/public/platform/WebData.h"
27 #include "third_party/WebKit/public/platform/WebPoint.h"
28 #include "third_party/WebKit/public/platform/WebURLRequest.h"
29 #include "third_party/WebKit/public/platform/WebVector.h"
30 #include "third_party/WebKit/public/web/WebContextMenuData.h"
31 #include "third_party/WebKit/public/web/WebDocument.h"
32 #include "third_party/WebKit/public/web/WebElement.h"
33 #include "third_party/WebKit/public/web/WebFrame.h"
34 #include "third_party/WebKit/public/web/WebInputEvent.h"
35 #include "third_party/WebKit/public/web/WebPluginContainer.h"
36 #include "third_party/WebKit/public/web/WebScriptSource.h"
37 #include "third_party/WebKit/public/web/WebView.h"
38 #include "third_party/re2/re2/re2.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/base/webui/jstemplate_builder.h"
42
43 using content::RenderThread;
44 using content::RenderView;
45 using WebKit::WebContextMenuData;
46 using WebKit::WebDocument;
47 using WebKit::WebElement;
48 using WebKit::WebFrame;
49 using WebKit::WebMouseEvent;
50 using WebKit::WebNode;
51 using WebKit::WebPlugin;
52 using WebKit::WebPluginContainer;
53 using WebKit::WebPluginParams;
54 using WebKit::WebPoint;
55 using WebKit::WebScriptSource;
56 using WebKit::WebString;
57 using WebKit::WebURLRequest;
58 using WebKit::WebVector;
59 using webkit_glue::CppArgumentList;
60 using webkit_glue::CppVariant;
61
62 const char* const kPluginPlaceholderDataURL =
63 "chrome://pluginplaceholderdata/";
64
65 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
66 // Strings we used to parse the youtube plugin url.
67 const char* const kSlashVSlash = "/v/";
68 const char* const kSlashESlash = "/e/";
69 #endif
70
71 namespace {
72 const PluginPlaceholder* g_last_active_menu = NULL;
73
74 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
75 // Helper function to get the youtube id from plugin params for old style
76 // embedded youtube video.
77 std::string GetYoutubeVideoId(const WebPluginParams& params) {
78 GURL url(params.url);
79 std::string video_id = url.path().substr(strlen(kSlashVSlash));
80
81 // Extract just the video id
82 size_t video_id_end = video_id.find('&');
83 if (video_id_end != std::string::npos)
84 video_id = video_id.substr(0, video_id_end);
85 return video_id;
86 }
87 #endif
88 } // namespace
89
90 // static
91 PluginPlaceholder* PluginPlaceholder::CreateMissingPlugin(
92 RenderView* render_view,
93 WebFrame* frame,
94 const WebPluginParams& params) {
95 const base::StringPiece template_html(
96 ResourceBundle::GetSharedInstance().GetRawDataResource(
97 IDR_BLOCKED_PLUGIN_HTML));
98
99 base::DictionaryValue values;
100 #if defined(ENABLE_PLUGIN_INSTALLATION)
101 values.SetString("message", l10n_util::GetStringUTF8(IDS_PLUGIN_SEARCHING));
102 #else
103 values.SetString("message",
104 l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
105 #endif
106
107 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
108
109 // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
110 PluginPlaceholder* missing_plugin = new PluginPlaceholder(
111 render_view, frame, params, html_data, params.mimeType);
112 missing_plugin->set_allow_loading(true);
113 #if defined(ENABLE_PLUGIN_INSTALLATION)
114 RenderThread::Get()->Send(new ChromeViewHostMsg_FindMissingPlugin(
115 missing_plugin->routing_id(), missing_plugin->CreateRoutingId(),
116 params.mimeType.utf8()));
117 #endif
118 return missing_plugin;
119 }
120
121 PluginPlaceholder* PluginPlaceholder::CreateErrorPlugin(
122 RenderView* render_view,
123 const base::FilePath& file_path) {
124 base::DictionaryValue values;
125 values.SetString("message",
126 l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR));
127
128 const base::StringPiece template_html(
129 ResourceBundle::GetSharedInstance().GetRawDataResource(
130 IDR_BLOCKED_PLUGIN_HTML));
131 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
132
133 WebPluginParams params;
134 // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
135 PluginPlaceholder* plugin = new PluginPlaceholder(
136 render_view, NULL, params, html_data, params.mimeType);
137
138 RenderThread::Get()->Send(
139 new ChromeViewHostMsg_CouldNotLoadPlugin(plugin->routing_id(),
140 file_path));
141 return plugin;
142 }
143
144 // static
145 PluginPlaceholder* PluginPlaceholder::CreateBlockedPlugin(
146 RenderView* render_view,
147 WebFrame* frame,
148 const WebPluginParams& params,
149 const content::WebPluginInfo& plugin,
150 const std::string& identifier,
151 const string16& name,
152 int template_id,
153 const string16& message) {
154 base::DictionaryValue values;
155 values.SetString("message", message);
156 values.SetString("name", name);
157 values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE));
158
159 const base::StringPiece template_html(
160 ResourceBundle::GetSharedInstance().GetRawDataResource(
161 template_id));
162
163 DCHECK(!template_html.empty()) << "unable to load template. ID: "
164 << template_id;
165 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
166
167 // |blocked_plugin| will destroy itself when its WebViewPlugin is going away.
168 PluginPlaceholder* blocked_plugin = new PluginPlaceholder(
169 render_view, frame, params, html_data, name);
170 blocked_plugin->plugin_info_ = plugin;
171 blocked_plugin->identifier_ = identifier;
172 return blocked_plugin;
173 }
174
175 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
176 // static
177 PluginPlaceholder* PluginPlaceholder::CreateMobileYoutubePlugin(
178 content::RenderView* render_view,
179 WebFrame* frame,
180 const WebPluginParams& params) {
181 const base::StringPiece template_html(
182 ResourceBundle::GetSharedInstance().GetRawDataResource(
183 IDR_MOBILE_YOUTUBE_PLUGIN_HTML));
184
185 base::DictionaryValue values;
186 values.SetString("video_id", GetYoutubeVideoId(params));
187 std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
188
189 // |youtube_plugin| will destroy itself when its WebViewPlugin is going away.
190 PluginPlaceholder* youtube_plugin = new PluginPlaceholder(
191 render_view, frame, params, html_data, params.mimeType);
192 return youtube_plugin;
193 }
194 #endif
195
196 PluginPlaceholder::PluginPlaceholder(content::RenderView* render_view,
197 WebFrame* frame,
198 const WebPluginParams& params,
199 const std::string& html_data,
200 const string16& title)
201 : content::RenderViewObserver(render_view),
202 frame_(frame),
203 plugin_params_(params),
204 plugin_(WebViewPlugin::Create(
205 this, render_view->GetWebkitPreferences(), html_data,
206 GURL(kPluginPlaceholderDataURL))),
207 title_(title),
208 status_(new ChromeViewHostMsg_GetPluginInfo_Status),
209 is_blocked_for_prerendering_(false),
210 allow_loading_(false),
211 #if defined(ENABLE_PLUGIN_INSTALLATION)
212 placeholder_routing_id_(MSG_ROUTING_NONE),
213 #endif
214 hidden_(false),
215 has_host_(false),
216 finished_loading_(false),
217 context_menu_request_id_(0) {
218 RenderThread::Get()->AddObserver(this);
219 }
220
221 PluginPlaceholder::~PluginPlaceholder() {
222 RenderThread::Get()->RemoveObserver(this);
223 if (context_menu_request_id_)
224 render_view()->CancelContextMenu(context_menu_request_id_);
225
226 #if defined(ENABLE_PLUGIN_INSTALLATION)
227 if (placeholder_routing_id_ == MSG_ROUTING_NONE)
228 return;
229 RenderThread::Get()->RemoveRoute(placeholder_routing_id_);
230 if (has_host_) {
231 RenderThread::Get()->Send(
232 new ChromeViewHostMsg_RemovePluginPlaceholderHost(
233 routing_id(), placeholder_routing_id_));
234 }
235 #endif
236 }
237
238 #if defined(ENABLE_PLUGIN_INSTALLATION)
239 int32 PluginPlaceholder::CreateRoutingId() {
240 placeholder_routing_id_ = RenderThread::Get()->GenerateRoutingID();
241 RenderThread::Get()->AddRoute(placeholder_routing_id_, this);
242 return placeholder_routing_id_;
243 }
244 #endif
245
246 void PluginPlaceholder::SetStatus(
247 const ChromeViewHostMsg_GetPluginInfo_Status& status) {
248 status_->value = status.value;
249 }
250
251 void PluginPlaceholder::BindWebFrame(WebFrame* frame) {
252 BindToJavascript(frame, "plugin");
253 BindCallback("load", base::Bind(&PluginPlaceholder::LoadCallback,
254 base::Unretained(this)));
255 BindCallback("hide", base::Bind(&PluginPlaceholder::HideCallback,
256 base::Unretained(this)));
257 BindCallback("openAboutPlugins",
258 base::Bind(&PluginPlaceholder::OpenAboutPluginsCallback,
259 base::Unretained(this)));
260 BindCallback("didFinishLoading",
261 base::Bind(&PluginPlaceholder::DidFinishLoadingCallback,
262 base::Unretained(this)));
263 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
264 BindCallback("openYoutubeURL",
265 base::Bind(&PluginPlaceholder::OpenYoutubeUrlCallback,
266 base::Unretained(this)));
267 #endif
268 }
269
270 bool PluginPlaceholder::OnMessageReceived(const IPC::Message& message) {
271 #if defined(ENABLE_PLUGIN_INSTALLATION)
272 bool handled = true;
273 IPC_BEGIN_MESSAGE_MAP(PluginPlaceholder, message)
274 IPC_MESSAGE_HANDLER(ChromeViewMsg_FoundMissingPlugin,
275 OnFoundMissingPlugin)
276 IPC_MESSAGE_HANDLER(ChromeViewMsg_DidNotFindMissingPlugin,
277 OnDidNotFindMissingPlugin)
278 IPC_MESSAGE_HANDLER(ChromeViewMsg_StartedDownloadingPlugin,
279 OnStartedDownloadingPlugin)
280 IPC_MESSAGE_HANDLER(ChromeViewMsg_FinishedDownloadingPlugin,
281 OnFinishedDownloadingPlugin)
282 IPC_MESSAGE_HANDLER(ChromeViewMsg_ErrorDownloadingPlugin,
283 OnErrorDownloadingPlugin)
284 IPC_MESSAGE_HANDLER(ChromeViewMsg_CancelledDownloadingPlugin,
285 OnCancelledDownloadingPlugin)
286 IPC_MESSAGE_UNHANDLED(handled = false)
287 IPC_END_MESSAGE_MAP()
288
289 if (handled)
290 return true;
291 #endif
292
293 // We don't swallow these messages because multiple blocked plugins have an
294 // interest in them.
295 IPC_BEGIN_MESSAGE_MAP(PluginPlaceholder, message)
296 IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
297 IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
298 IPC_END_MESSAGE_MAP()
299
300 return false;
301 }
302
303 void PluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) {
304 CHECK(plugin_);
305 if (!new_plugin) {
306 PluginUMAReporter::GetInstance()->ReportPluginMissing(
307 plugin_params_.mimeType.utf8(),
308 plugin_params_.url);
309 return;
310 }
311
312 WebPluginContainer* container = plugin_->container();
313 // Set the new plug-in on the container before initializing it.
314 container->setPlugin(new_plugin);
315 // Save the element in case the plug-in is removed from the page during
316 // initialization.
317 WebElement element = container->element();
318 if (!new_plugin->initialize(container)) {
319 // We couldn't initialize the new plug-in. Restore the old one and abort.
320 container->setPlugin(plugin_);
321 return;
322 }
323
324 // The plug-in has been removed from the page. Destroy the old plug-in
325 // (which will destroy us).
326 if (!element.pluginContainer()) {
327 plugin_->destroy();
328 return;
329 }
330
331 // During initialization, the new plug-in might have replaced itself in turn
332 // with another plug-in. Make sure not to use the passed in |new_plugin| after
333 // this point.
334 new_plugin = container->plugin();
335
336 plugin_->RestoreTitleText();
337 container->invalidate();
338 container->reportGeometry();
339 plugin_->ReplayReceivedData(new_plugin);
340 plugin_->destroy();
341 }
342
343 void PluginPlaceholder::HidePlugin() {
344 hidden_ = true;
345 WebPluginContainer* container = plugin_->container();
346 WebElement element = container->element();
347 element.setAttribute("style", "display: none;");
348 // If we have a width and height, search for a parent (often <div>) with the
349 // same dimensions. If we find such a parent, hide that as well.
350 // This makes much more uncovered page content usable (including clickable)
351 // as opposed to merely visible.
352 // TODO(cevans) -- it's a foul heurisitc but we're going to tolerate it for
353 // now for these reasons:
354 // 1) Makes the user experience better.
355 // 2) Foulness is encapsulated within this single function.
356 // 3) Confidence in no fasle positives.
357 // 4) Seems to have a good / low false negative rate at this time.
358 if (element.hasAttribute("width") && element.hasAttribute("height")) {
359 std::string width_str("width:[\\s]*");
360 width_str += element.getAttribute("width").utf8().data();
361 if (EndsWith(width_str, "px", false)) {
362 width_str = width_str.substr(0, width_str.length() - 2);
363 }
364 TrimWhitespace(width_str, TRIM_TRAILING, &width_str);
365 width_str += "[\\s]*px";
366 std::string height_str("height:[\\s]*");
367 height_str += element.getAttribute("height").utf8().data();
368 if (EndsWith(height_str, "px", false)) {
369 height_str = height_str.substr(0, height_str.length() - 2);
370 }
371 TrimWhitespace(height_str, TRIM_TRAILING, &height_str);
372 height_str += "[\\s]*px";
373 WebNode parent = element;
374 while (!parent.parentNode().isNull()) {
375 parent = parent.parentNode();
376 if (!parent.isElementNode())
377 continue;
378 element = parent.toConst<WebElement>();
379 if (element.hasAttribute("style")) {
380 std::string style_str = element.getAttribute("style").utf8();
381 if (RE2::PartialMatch(style_str, width_str) &&
382 RE2::PartialMatch(style_str, height_str))
383 element.setAttribute("style", "display: none;");
384 }
385 }
386 }
387 }
388
389 void PluginPlaceholder::WillDestroyPlugin() {
390 delete this;
391 }
392
393 #if defined(ENABLE_PLUGIN_INSTALLATION)
394 void PluginPlaceholder::OnDidNotFindMissingPlugin() {
395 SetMessage(l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_FOUND));
396 }
397
398 void PluginPlaceholder::OnFoundMissingPlugin(const string16& plugin_name) {
399 if (status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound)
400 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_FOUND, plugin_name));
401 has_host_ = true;
402 plugin_name_ = plugin_name;
403 }
404
405 void PluginPlaceholder::OnStartedDownloadingPlugin() {
406 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_));
407 }
408
409 void PluginPlaceholder::OnFinishedDownloadingPlugin() {
410 bool is_installing =
411 status_->value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
412 SetMessage(l10n_util::GetStringFUTF16(
413 is_installing ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
414 plugin_name_));
415 }
416
417 void PluginPlaceholder::OnErrorDownloadingPlugin(const std::string& error) {
418 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR,
419 UTF8ToUTF16(error)));
420 }
421
422 void PluginPlaceholder::OnCancelledDownloadingPlugin() {
423 SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED,
424 plugin_name_));
425 }
426 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
427
428 void PluginPlaceholder::PluginListChanged() {
429 if (!frame_)
430 return;
431 WebDocument document = frame_->top()->document();
432 if (document.isNull())
433 return;
434
435 ChromeViewHostMsg_GetPluginInfo_Output output;
436 std::string mime_type(plugin_params_.mimeType.utf8());
437 render_view()->Send(new ChromeViewHostMsg_GetPluginInfo(
438 routing_id(), GURL(plugin_params_.url), document.url(),
439 mime_type, &output));
440 if (output.status.value == status_->value)
441 return;
442 WebPlugin* new_plugin = chrome::ChromeContentRendererClient::CreatePlugin(
443 render_view(), frame_, plugin_params_, output);
444 ReplacePlugin(new_plugin);
445 }
446
447 void PluginPlaceholder::OnMenuAction(int request_id, unsigned action) {
448 DCHECK_EQ(context_menu_request_id_, request_id);
449 if (g_last_active_menu != this)
450 return;
451 switch (action) {
452 case chrome::MENU_COMMAND_PLUGIN_RUN: {
453 RenderThread::Get()->RecordUserMetrics("Plugin_Load_Menu");
454 LoadPlugin();
455 break;
456 }
457 case chrome::MENU_COMMAND_PLUGIN_HIDE: {
458 RenderThread::Get()->RecordUserMetrics("Plugin_Hide_Menu");
459 HidePlugin();
460 break;
461 }
462 default:
463 NOTREACHED();
464 }
465 }
466
467 void PluginPlaceholder::OnMenuClosed(int request_id) {
468 DCHECK_EQ(context_menu_request_id_, request_id);
469 context_menu_request_id_ = 0;
470 }
471
472 void PluginPlaceholder::SetMessage(const string16& message) {
473 message_ = message;
474 if (finished_loading_)
475 UpdateMessage();
476 }
477
478 void PluginPlaceholder::UpdateMessage() {
479 std::string script = "window.setMessage(" +
480 base::GetDoubleQuotedJson(message_) + ")";
481 plugin_->web_view()->mainFrame()->executeScript(
482 WebScriptSource(ASCIIToUTF16(script)));
483 }
484
485 void PluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) {
486 if (context_menu_request_id_)
487 return; // Don't allow nested context menu requests.
488
489 content::ContextMenuParams params;
490
491 content::MenuItem name_item;
492 name_item.label = title_;
493 params.custom_items.push_back(name_item);
494
495 content::MenuItem separator_item;
496 separator_item.type = content::MenuItem::SEPARATOR;
497 params.custom_items.push_back(separator_item);
498
499 if (!plugin_info_.path.value().empty()) {
500 content::MenuItem run_item;
501 run_item.action = chrome::MENU_COMMAND_PLUGIN_RUN;
502 // Disable this menu item if the plugin is blocked by policy.
503 run_item.enabled = allow_loading_;
504 run_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_RUN);
505 params.custom_items.push_back(run_item);
506 }
507
508 content::MenuItem hide_item;
509 hide_item.action = chrome::MENU_COMMAND_PLUGIN_HIDE;
510 hide_item.enabled = true;
511 hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE);
512 params.custom_items.push_back(hide_item);
513
514 params.x = event.windowX;
515 params.y = event.windowY;
516
517 context_menu_request_id_ = render_view()->ShowContextMenu(this, params);
518 g_last_active_menu = this;
519 }
520
521 void PluginPlaceholder::OnLoadBlockedPlugins(const std::string& identifier) {
522 if (!identifier.empty() && identifier != identifier_)
523 return;
524
525 RenderThread::Get()->RecordUserMetrics("Plugin_Load_UI");
526 LoadPlugin();
527 }
528
529 void PluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) {
530 // Prerendering can only be enabled prior to a RenderView's first navigation,
531 // so no BlockedPlugin should see the notification that enables prerendering.
532 DCHECK(!is_prerendering);
533 if (is_blocked_for_prerendering_ && !is_prerendering)
534 LoadPlugin();
535 }
536
537 void PluginPlaceholder::LoadPlugin() {
538 // This is not strictly necessary but is an important defense in case the
539 // event propagation changes between "close" vs. "click-to-play".
540 if (hidden_)
541 return;
542 if (!allow_loading_) {
543 NOTREACHED();
544 return;
545 }
546
547 // TODO(mmenke): In the case of prerendering, feed into
548 // ChromeContentRendererClient::CreatePlugin instead, to
549 // reduce the chance of future regressions.
550 WebPlugin* plugin =
551 render_view()->CreatePlugin(frame_, plugin_info_, plugin_params_);
552 ReplacePlugin(plugin);
553 }
554
555 void PluginPlaceholder::LoadCallback(const CppArgumentList& args,
556 CppVariant* result) {
557 RenderThread::Get()->RecordUserMetrics("Plugin_Load_Click");
558 LoadPlugin();
559 }
560
561 void PluginPlaceholder::HideCallback(const CppArgumentList& args,
562 CppVariant* result) {
563 RenderThread::Get()->RecordUserMetrics("Plugin_Hide_Click");
564 HidePlugin();
565 }
566
567 void PluginPlaceholder::OpenAboutPluginsCallback(const CppArgumentList& args,
568 CppVariant* result) {
569 RenderThread::Get()->Send(
570 new ChromeViewHostMsg_OpenAboutPlugins(routing_id()));
571 }
572
573 void PluginPlaceholder::DidFinishLoadingCallback(const CppArgumentList& args,
574 CppVariant* result) {
575 finished_loading_ = true;
576 if (message_.length() > 0)
577 UpdateMessage();
578 }
579
580 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
581 void PluginPlaceholder::OpenYoutubeUrlCallback(const CppArgumentList& args,
582 CppVariant* result) {
583 std::string youtube("vnd.youtube:");
584 GURL url(youtube.append(GetYoutubeVideoId(plugin_params_)));
585 WebURLRequest request;
586 request.initialize();
587 request.setURL(url);
588 render_view()->LoadURLExternally(
589 frame_, request, WebKit::WebNavigationPolicyNewForegroundTab);
590 }
591
592 bool PluginPlaceholder::IsValidYouTubeVideo(const std::string& path) {
593 unsigned len = strlen(kSlashVSlash);
594
595 // check for more than just /v/ or /e/.
596 if (path.length() <= len)
597 return false;
598
599 std::string str = StringToLowerASCII(path);
600 // Youtube flash url can start with /v/ or /e/.
601 if (strncmp(str.data(), kSlashVSlash, len) != 0 &&
602 strncmp(str.data(), kSlashESlash, len) != 0)
603 return false;
604
605 // Start after /v/
606 for (unsigned i = len; i < path.length(); i++) {
607 char c = str[i];
608 if (isalpha(c) || isdigit(c) || c == '_' || c == '-')
609 continue;
610 // The url can have more parameters such as &hl=en after the video id.
611 // Once we start seeing extra parameters we can return true.
612 return c == '&' && i > len;
613 }
614 return true;
615 }
616
617 bool PluginPlaceholder::IsYouTubeURL(const GURL& url,
618 const std::string& mime_type) {
619 std::string host = url.host();
620 bool is_youtube = EndsWith(host, "youtube.com", true) ||
621 EndsWith(host, "youtube-nocookie.com", true);
622
623 return is_youtube && IsValidYouTubeVideo(url.path()) &&
624 LowerCaseEqualsASCII(mime_type, content::kFlashPluginSwfMimeType);
625 }
626 #endif
OLDNEW
« no previous file with comments | « chrome/renderer/plugins/plugin_placeholder.h ('k') | chrome/renderer/plugins/plugin_uma.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698