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

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

Issue 23606022: Move renderer plugin code into a new component. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move renderer plugin code into a new component - put back wrongly deleted DEPS file Created 7 years, 3 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
Jói 2013/09/09 17:46:17 Likewise for this file, let's see if --similarity=
aberent 2013/09/10 13:24:01 I will experiment
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 "components/plugins/renderer/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 "components/plugins/renderer/plugin_uma.h"
15 #include "content/public/common/content_constants.h"
16 #include "content/public/common/context_menu_params.h"
17 #include "content/public/renderer/render_thread.h"
18 #include "content/public/renderer/render_view.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebElement.h"
21 #include "third_party/WebKit/public/web/WebFrame.h"
22 #include "third_party/WebKit/public/web/WebInputEvent.h"
23 #include "third_party/WebKit/public/web/WebPluginContainer.h"
24 #include "third_party/WebKit/public/web/WebScriptSource.h"
25 #include "third_party/WebKit/public/web/WebView.h"
26 #include "third_party/re2/re2/re2.h"
27
28 using content::RenderThread;
29 using WebKit::WebElement;
30 using WebKit::WebFrame;
31 using WebKit::WebMouseEvent;
32 using WebKit::WebNode;
33 using WebKit::WebPlugin;
34 using WebKit::WebPluginContainer;
35 using WebKit::WebPluginParams;
36 using WebKit::WebScriptSource;
37 using WebKit::WebURLRequest;
38 using webkit_glue::CppArgumentList;
39 using webkit_glue::CppVariant;
40
41 const char* const kPluginPlaceholderDataURL = "chrome://pluginplaceholderdata/";
42
43 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
44 // Strings we used to parse the youtube plugin url.
45 const char* const kSlashVSlash = "/v/";
46 const char* const kSlashESlash = "/e/";
47 #endif
48
49 PluginPlaceholder::PluginPlaceholder(content::RenderView* render_view,
50 WebFrame* frame,
51 const WebPluginParams& params,
52 const std::string& html_data)
53 : content::RenderViewObserver(render_view),
54 frame_(frame),
55 plugin_params_(params),
56 plugin_(WebViewPlugin::Create(this,
57 render_view->GetWebkitPreferences(),
58 html_data,
59 GURL(kPluginPlaceholderDataURL))),
60 is_blocked_for_prerendering_(false),
61 allow_loading_(false),
62 hidden_(false),
63 finished_loading_(false) {}
64
65 PluginPlaceholder::~PluginPlaceholder() {}
66
67 void PluginPlaceholder::BindWebFrame(WebFrame* frame) {
68 BindToJavascript(frame, "plugin");
69 BindCallback(
70 "load",
71 base::Bind(&PluginPlaceholder::LoadCallback, base::Unretained(this)));
72 BindCallback(
73 "hide",
74 base::Bind(&PluginPlaceholder::HideCallback, base::Unretained(this)));
75 BindCallback("openAboutPlugins",
76 base::Bind(&PluginPlaceholder::OpenAboutPluginsCallback,
77 base::Unretained(this)));
78 BindCallback("didFinishLoading",
79 base::Bind(&PluginPlaceholder::DidFinishLoadingCallback,
80 base::Unretained(this)));
81 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
82 BindCallback("openYoutubeURL",
83 base::Bind(&PluginPlaceholder::OpenYoutubeUrlCallback,
84 base::Unretained(this)));
85 #endif
86 }
87
88 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
89 // Helper function to get the youtube id from plugin params for old style
90 // embedded youtube video.
91 std::string PluginPlaceholder::GetYoutubeVideoId(
92 const WebPluginParams& params) {
93 GURL url(params.url);
94 std::string video_id = url.path().substr(strlen(kSlashVSlash));
95
96 // Extract just the video id
97 size_t video_id_end = video_id.find('&');
98 if (video_id_end != std::string::npos)
99 video_id = video_id.substr(0, video_id_end);
100 return video_id;
101 }
102 #endif
103
104 void PluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) {
105 CHECK(plugin_);
106 if (!new_plugin) {
107 PluginUMAReporter::GetInstance()->ReportPluginMissing(
108 plugin_params_.mimeType.utf8(), plugin_params_.url);
109 return;
110 }
111
112 WebPluginContainer* container = plugin_->container();
113 // Set the new plug-in on the container before initializing it.
114 container->setPlugin(new_plugin);
115 // Save the element in case the plug-in is removed from the page during
116 // initialization.
117 WebElement element = container->element();
118 if (!new_plugin->initialize(container)) {
119 // We couldn't initialize the new plug-in. Restore the old one and abort.
120 container->setPlugin(plugin_);
121 return;
122 }
123
124 // The plug-in has been removed from the page. Destroy the old plug-in
125 // (which will destroy us).
126 if (!element.pluginContainer()) {
127 plugin_->destroy();
128 return;
129 }
130
131 // During initialization, the new plug-in might have replaced itself in turn
132 // with another plug-in. Make sure not to use the passed in |new_plugin| after
133 // this point.
134 new_plugin = container->plugin();
135
136 plugin_->RestoreTitleText();
137 container->invalidate();
138 container->reportGeometry();
139 plugin_->ReplayReceivedData(new_plugin);
140 plugin_->destroy();
141 }
142
143 void PluginPlaceholder::HidePlugin() {
144 hidden_ = true;
145 WebPluginContainer* container = plugin_->container();
146 WebElement element = container->element();
147 element.setAttribute("style", "display: none;");
148 // If we have a width and height, search for a parent (often <div>) with the
149 // same dimensions. If we find such a parent, hide that as well.
150 // This makes much more uncovered page content usable (including clickable)
151 // as opposed to merely visible.
152 // TODO(cevans) -- it's a foul heurisitc but we're going to tolerate it for
153 // now for these reasons:
154 // 1) Makes the user experience better.
155 // 2) Foulness is encapsulated within this single function.
156 // 3) Confidence in no fasle positives.
157 // 4) Seems to have a good / low false negative rate at this time.
158 if (element.hasAttribute("width") && element.hasAttribute("height")) {
159 std::string width_str("width:[\\s]*");
160 width_str += element.getAttribute("width").utf8().data();
161 if (EndsWith(width_str, "px", false)) {
162 width_str = width_str.substr(0, width_str.length() - 2);
163 }
164 TrimWhitespace(width_str, TRIM_TRAILING, &width_str);
165 width_str += "[\\s]*px";
166 std::string height_str("height:[\\s]*");
167 height_str += element.getAttribute("height").utf8().data();
168 if (EndsWith(height_str, "px", false)) {
169 height_str = height_str.substr(0, height_str.length() - 2);
170 }
171 TrimWhitespace(height_str, TRIM_TRAILING, &height_str);
172 height_str += "[\\s]*px";
173 WebNode parent = element;
174 while (!parent.parentNode().isNull()) {
175 parent = parent.parentNode();
176 if (!parent.isElementNode())
177 continue;
178 element = parent.toConst<WebElement>();
179 if (element.hasAttribute("style")) {
180 std::string style_str = element.getAttribute("style").utf8();
181 if (RE2::PartialMatch(style_str, width_str) &&
182 RE2::PartialMatch(style_str, height_str))
183 element.setAttribute("style", "display: none;");
184 }
185 }
186 }
187 }
188
189 void PluginPlaceholder::WillDestroyPlugin() { delete this; }
190
191 void PluginPlaceholder::SetMessage(const string16& message) {
192 message_ = message;
193 if (finished_loading_)
194 UpdateMessage();
195 }
196
197 void PluginPlaceholder::UpdateMessage() {
198 std::string script =
199 "window.setMessage(" + base::GetDoubleQuotedJson(message_) + ")";
200 plugin_->web_view()->mainFrame()->executeScript(
201 WebScriptSource(ASCIIToUTF16(script)));
202 }
203
204 void PluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) {
205 // Does nothing by default. Will be overridden if a specific browser wants
206 // a context menu.
207 return;
208 }
209
210 void PluginPlaceholder::OnLoadBlockedPlugins(const std::string& identifier) {
211 if (!identifier.empty() && identifier != identifier_)
212 return;
213
214 RenderThread::Get()->RecordUserMetrics("Plugin_Load_UI");
215 LoadPlugin();
216 }
217
218 void PluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) {
219 // Prerendering can only be enabled prior to a RenderView's first navigation,
220 // so no BlockedPlugin should see the notification that enables prerendering.
221 DCHECK(!is_prerendering);
222 if (is_blocked_for_prerendering_ && !is_prerendering)
223 LoadPlugin();
224 }
225
226 void PluginPlaceholder::LoadPlugin() {
227 // This is not strictly necessary but is an important defense in case the
228 // event propagation changes between "close" vs. "click-to-play".
229 if (hidden_)
230 return;
231 if (!allow_loading_) {
232 NOTREACHED();
233 return;
234 }
235
236 // TODO(mmenke): In the case of prerendering, feed into
237 // ChromeContentRendererClient::CreatePlugin instead, to
238 // reduce the chance of future regressions.
239 WebPlugin* plugin =
240 render_view()->CreatePlugin(frame_, plugin_info_, plugin_params_);
241 ReplacePlugin(plugin);
242 }
243
244 void PluginPlaceholder::LoadCallback(const CppArgumentList& args,
245 CppVariant* result) {
246 RenderThread::Get()->RecordUserMetrics("Plugin_Load_Click");
247 LoadPlugin();
248 }
249
250 void PluginPlaceholder::HideCallback(const CppArgumentList& args,
251 CppVariant* result) {
252 RenderThread::Get()->RecordUserMetrics("Plugin_Hide_Click");
253 HidePlugin();
254 }
255
256 void PluginPlaceholder::OpenAboutPluginsCallback(const CppArgumentList& args,
257 CppVariant* result) {
258 OpenAboutPlugins();
259 }
260
261 void PluginPlaceholder::OpenAboutPlugins() {
262 // Default version does nothing.
263 }
264
265 void PluginPlaceholder::DidFinishLoadingCallback(const CppArgumentList& args,
266 CppVariant* result) {
267 finished_loading_ = true;
268 if (message_.length() > 0)
269 UpdateMessage();
270 }
271
272 #if defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
273 void PluginPlaceholder::OpenYoutubeUrlCallback(const CppArgumentList& args,
274 CppVariant* result) {
275 std::string youtube("vnd.youtube:");
276 GURL url(youtube.append(GetYoutubeVideoId(plugin_params_)));
277 WebURLRequest request;
278 request.initialize();
279 request.setURL(url);
280 render_view()->LoadURLExternally(
281 frame_, request, WebKit::WebNavigationPolicyNewForegroundTab);
282 }
283
284 bool PluginPlaceholder::IsValidYouTubeVideo(const std::string& path) {
285 unsigned len = strlen(kSlashVSlash);
286
287 // check for more than just /v/ or /e/.
288 if (path.length() <= len)
289 return false;
290
291 std::string str = StringToLowerASCII(path);
292 // Youtube flash url can start with /v/ or /e/.
293 if (strncmp(str.data(), kSlashVSlash, len) != 0 &&
294 strncmp(str.data(), kSlashESlash, len) != 0)
295 return false;
296
297 // Start after /v/
298 for (unsigned i = len; i < path.length(); i++) {
299 char c = str[i];
300 if (isalpha(c) || isdigit(c) || c == '_' || c == '-')
301 continue;
302 // The url can have more parameters such as &hl=en after the video id.
303 // Once we start seeing extra parameters we can return true.
304 return c == '&' && i > len;
305 }
306 return true;
307 }
308
309 bool PluginPlaceholder::IsYouTubeURL(const GURL& url,
310 const std::string& mime_type) {
311 std::string host = url.host();
312 bool is_youtube = EndsWith(host, "youtube.com", true) ||
313 EndsWith(host, "youtube-nocookie.com", true);
314
315 return is_youtube && IsValidYouTubeVideo(url.path()) &&
316 LowerCaseEqualsASCII(mime_type, content::kFlashPluginSwfMimeType);
317 }
318 #endif // defined(ENABLE_MOBILE_YOUTUBE_PLUGIN)
319
320 void PluginPlaceholder::SetPluginInfo(
321 const content::WebPluginInfo& plugin_info) {
322 plugin_info_ = plugin_info;
323 }
324
325 const content::WebPluginInfo& PluginPlaceholder::GetPluginInfo() const {
326 return plugin_info_;
327 }
328
329 void PluginPlaceholder::SetIdentifier(const std::string& identifier) {
330 identifier_ = identifier;
331 }
332
333 WebKit::WebFrame* PluginPlaceholder::GetFrame() { return frame_; }
334
335 const WebKit::WebPluginParams& PluginPlaceholder::GetPluginParams() const {
336 return plugin_params_;
337 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698