OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/plugins/renderer/loadable_plugin_placeholder.h" | 5 #include "components/plugins/renderer/loadable_plugin_placeholder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/json/string_escape.h" | 9 #include "base/json/string_escape.h" |
10 #include "base/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 is_blocked_for_power_saver_poster_ = true; | 43 is_blocked_for_power_saver_poster_ = true; |
44 | 44 |
45 render_frame()->RegisterPeripheralPlugin( | 45 render_frame()->RegisterPeripheralPlugin( |
46 GURL(GetPluginParams().url).GetOrigin(), | 46 GURL(GetPluginParams().url).GetOrigin(), |
47 base::Bind(&LoadablePluginPlaceholder::DisablePowerSaverForInstance, | 47 base::Bind(&LoadablePluginPlaceholder::DisablePowerSaverForInstance, |
48 weak_factory_.GetWeakPtr(), | 48 weak_factory_.GetWeakPtr(), |
49 PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_WHITELIST)); | 49 PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_WHITELIST)); |
50 } | 50 } |
51 #endif | 51 #endif |
52 | 52 |
| 53 void LoadablePluginPlaceholder::SetPremadePlugin( |
| 54 blink::WebPlugin* plugin, |
| 55 content::PluginInstanceThrottler* throttler) { |
| 56 DCHECK(!premade_plugin_); |
| 57 DCHECK(!premade_throttler_); |
| 58 premade_plugin_ = plugin; |
| 59 premade_throttler_ = throttler; |
| 60 |
| 61 premade_throttler_->AddObserver(this); |
| 62 } |
| 63 |
53 LoadablePluginPlaceholder::LoadablePluginPlaceholder( | 64 LoadablePluginPlaceholder::LoadablePluginPlaceholder( |
54 content::RenderFrame* render_frame, | 65 content::RenderFrame* render_frame, |
55 WebLocalFrame* frame, | 66 WebLocalFrame* frame, |
56 const WebPluginParams& params, | 67 const WebPluginParams& params, |
57 const std::string& html_data, | 68 const std::string& html_data, |
58 GURL placeholderDataUrl) | 69 GURL placeholderDataUrl) |
59 : PluginPlaceholder(render_frame, | 70 : PluginPlaceholder(render_frame, |
60 frame, | 71 frame, |
61 params, | 72 params, |
62 html_data, | 73 html_data, |
63 placeholderDataUrl), | 74 placeholderDataUrl), |
64 is_blocked_for_background_tab_(false), | 75 is_blocked_for_background_tab_(false), |
65 is_blocked_for_prerendering_(false), | 76 is_blocked_for_prerendering_(false), |
66 is_blocked_for_power_saver_poster_(false), | 77 is_blocked_for_power_saver_poster_(false), |
67 power_saver_mode_(PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL), | 78 power_saver_mode_(PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL), |
| 79 premade_plugin_(nullptr), |
| 80 premade_throttler_(nullptr), |
68 allow_loading_(false), | 81 allow_loading_(false), |
69 placeholder_was_replaced_(false), | 82 placeholder_was_replaced_(false), |
70 hidden_(false), | 83 hidden_(false), |
71 finished_loading_(false), | 84 finished_loading_(false), |
72 weak_factory_(this) { | 85 weak_factory_(this) { |
73 } | 86 } |
74 | 87 |
75 LoadablePluginPlaceholder::~LoadablePluginPlaceholder() { | 88 LoadablePluginPlaceholder::~LoadablePluginPlaceholder() { |
76 #if defined(ENABLE_PLUGINS) | 89 #if defined(ENABLE_PLUGINS) |
| 90 if (premade_throttler_) |
| 91 premade_throttler_->RemoveObserver(this); |
| 92 |
77 if (!placeholder_was_replaced_ && !is_blocked_for_prerendering_ && | 93 if (!placeholder_was_replaced_ && !is_blocked_for_prerendering_ && |
78 power_saver_mode_ != PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL) { | 94 power_saver_mode_ != PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL) { |
79 PluginInstanceThrottler::RecordUnthrottleMethodMetric( | 95 PluginInstanceThrottler::RecordUnthrottleMethodMetric( |
80 PluginInstanceThrottler::UNTHROTTLE_METHOD_NEVER); | 96 PluginInstanceThrottler::UNTHROTTLE_METHOD_NEVER); |
81 } | 97 } |
82 #endif | 98 #endif |
83 } | 99 } |
84 | 100 |
85 #if defined(ENABLE_PLUGINS) | 101 #if defined(ENABLE_PLUGINS) |
86 void LoadablePluginPlaceholder::DisablePowerSaverForInstance( | 102 void LoadablePluginPlaceholder::DisablePowerSaverForInstance( |
87 PluginInstanceThrottler::PowerSaverUnthrottleMethod method) { | 103 PluginInstanceThrottler::PowerSaverUnthrottleMethod method) { |
88 if (power_saver_mode_ == PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL) | 104 if (power_saver_mode_ == PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL) |
89 return; | 105 return; |
90 | 106 |
91 power_saver_mode_ = PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL; | 107 power_saver_mode_ = PluginPowerSaverMode::POWER_SAVER_MODE_ESSENTIAL; |
92 PluginInstanceThrottler::RecordUnthrottleMethodMetric(method); | 108 if (premade_throttler_) { |
| 109 premade_throttler_->MarkPluginEssential(method); |
| 110 } else { |
| 111 PluginInstanceThrottler::RecordUnthrottleMethodMetric(method); |
| 112 } |
| 113 |
93 if (is_blocked_for_power_saver_poster_) { | 114 if (is_blocked_for_power_saver_poster_) { |
94 is_blocked_for_power_saver_poster_ = false; | 115 is_blocked_for_power_saver_poster_ = false; |
95 if (!LoadingBlocked()) | 116 if (!LoadingBlocked()) |
96 LoadPlugin(); | 117 LoadPlugin(); |
97 } | 118 } |
98 } | 119 } |
99 #endif | 120 #endif |
100 | 121 |
101 gin::ObjectTemplateBuilder LoadablePluginPlaceholder::GetObjectTemplateBuilder( | 122 gin::ObjectTemplateBuilder LoadablePluginPlaceholder::GetObjectTemplateBuilder( |
102 v8::Isolate* isolate) { | 123 v8::Isolate* isolate) { |
103 return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) | 124 return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) |
104 .SetMethod("load", &LoadablePluginPlaceholder::LoadCallback) | 125 .SetMethod("load", &LoadablePluginPlaceholder::LoadCallback) |
105 .SetMethod("hide", &LoadablePluginPlaceholder::HideCallback) | 126 .SetMethod("hide", &LoadablePluginPlaceholder::HideCallback) |
106 .SetMethod("didFinishLoading", | 127 .SetMethod("didFinishLoading", |
107 &LoadablePluginPlaceholder::DidFinishLoadingCallback); | 128 &LoadablePluginPlaceholder::DidFinishLoadingCallback); |
108 } | 129 } |
109 | 130 |
110 void LoadablePluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) { | 131 void LoadablePluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) { |
111 CHECK(plugin()); | 132 CHECK(plugin()); |
112 if (!new_plugin) | 133 if (!new_plugin) |
113 return; | 134 return; |
114 WebPluginContainer* container = plugin()->container(); | 135 WebPluginContainer* container = plugin()->container(); |
115 // Set the new plug-in on the container before initializing it. | 136 // Set the new plug-in on the container before initializing it. |
116 container->setPlugin(new_plugin); | 137 container->setPlugin(new_plugin); |
117 // Save the element in case the plug-in is removed from the page during | 138 // Save the element in case the plug-in is removed from the page during |
118 // initialization. | 139 // initialization. |
119 WebElement element = container->element(); | 140 WebElement element = container->element(); |
120 if (!new_plugin->initialize(container)) { | 141 if (new_plugin != premade_plugin_ && !new_plugin->initialize(container)) { |
121 // We couldn't initialize the new plug-in. Restore the old one and abort. | 142 // We couldn't initialize the new plug-in. Restore the old one and abort. |
122 container->setPlugin(plugin()); | 143 container->setPlugin(plugin()); |
123 return; | 144 return; |
124 } | 145 } |
125 | 146 |
126 // The plug-in has been removed from the page. Destroy the old plug-in. We | 147 // The plug-in has been removed from the page. Destroy the old plug-in. We |
127 // will be destroyed as soon as V8 garbage collects us. | 148 // will be destroyed as soon as V8 garbage collects us. |
128 if (!element.pluginContainer()) { | 149 if (!element.pluginContainer()) { |
129 plugin()->destroy(); | 150 plugin()->destroy(); |
130 return; | 151 return; |
131 } | 152 } |
132 | 153 |
| 154 placeholder_was_replaced_ = true; |
| 155 |
133 // During initialization, the new plug-in might have replaced itself in turn | 156 // During initialization, the new plug-in might have replaced itself in turn |
134 // with another plug-in. Make sure not to use the passed in |new_plugin| after | 157 // with another plug-in. Make sure not to use the passed in |new_plugin| after |
135 // this point. | 158 // this point. |
136 new_plugin = container->plugin(); | 159 new_plugin = container->plugin(); |
137 | 160 |
138 plugin()->RestoreTitleText(); | 161 plugin()->RestoreTitleText(); |
139 container->invalidate(); | 162 container->invalidate(); |
140 container->reportGeometry(); | 163 container->reportGeometry(); |
141 plugin()->ReplayReceivedData(new_plugin); | 164 plugin()->ReplayReceivedData(new_plugin); |
142 plugin()->destroy(); | 165 plugin()->destroy(); |
143 | |
144 placeholder_was_replaced_ = true; | |
145 } | 166 } |
146 | 167 |
147 void LoadablePluginPlaceholder::HidePlugin() { | 168 void LoadablePluginPlaceholder::HidePlugin() { |
148 hidden_ = true; | 169 hidden_ = true; |
149 if (!plugin()) | 170 if (!plugin()) |
150 return; | 171 return; |
151 WebPluginContainer* container = plugin()->container(); | 172 WebPluginContainer* container = plugin()->container(); |
152 WebElement element = container->element(); | 173 WebElement element = container->element(); |
153 element.setAttribute("style", "display: none;"); | 174 element.setAttribute("style", "display: none;"); |
154 // If we have a width and height, search for a parent (often <div>) with the | 175 // If we have a width and height, search for a parent (often <div>) with the |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 | 221 |
201 void LoadablePluginPlaceholder::UpdateMessage() { | 222 void LoadablePluginPlaceholder::UpdateMessage() { |
202 if (!plugin()) | 223 if (!plugin()) |
203 return; | 224 return; |
204 std::string script = | 225 std::string script = |
205 "window.setMessage(" + base::GetQuotedJSONString(message_) + ")"; | 226 "window.setMessage(" + base::GetQuotedJSONString(message_) + ")"; |
206 plugin()->web_view()->mainFrame()->executeScript( | 227 plugin()->web_view()->mainFrame()->executeScript( |
207 WebScriptSource(base::UTF8ToUTF16(script))); | 228 WebScriptSource(base::UTF8ToUTF16(script))); |
208 } | 229 } |
209 | 230 |
210 void LoadablePluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) { | 231 void LoadablePluginPlaceholder::PluginDestroyed() { |
211 // Does nothing by default. Will be overridden if a specific browser wants | 232 // Since the premade plugin has been detached from the container, it will not |
212 // a context menu. | 233 // be automatically destroyed along with the page. |
213 return; | 234 if (!placeholder_was_replaced_ && premade_plugin_) { |
| 235 premade_plugin_->destroy(); |
| 236 premade_plugin_ = nullptr; |
| 237 premade_throttler_ = nullptr; |
| 238 } |
| 239 |
| 240 PluginPlaceholder::PluginDestroyed(); |
214 } | 241 } |
215 | 242 |
216 void LoadablePluginPlaceholder::WasShown() { | 243 void LoadablePluginPlaceholder::WasShown() { |
217 if (is_blocked_for_background_tab_) { | 244 if (is_blocked_for_background_tab_) { |
218 is_blocked_for_background_tab_ = false; | 245 is_blocked_for_background_tab_ = false; |
219 if (!LoadingBlocked()) | 246 if (!LoadingBlocked()) |
220 LoadPlugin(); | 247 LoadPlugin(); |
221 } | 248 } |
222 } | 249 } |
223 | 250 |
| 251 void LoadablePluginPlaceholder::OnThrottleStateChange() { |
| 252 DCHECK(premade_plugin_); |
| 253 DCHECK(premade_throttler_); |
| 254 if (!premade_throttler_->IsThrottled()) { |
| 255 // Premade plugin has been unthrottled externally (by audio playback, etc.). |
| 256 LoadPlugin(); |
| 257 } |
| 258 } |
| 259 |
224 void LoadablePluginPlaceholder::OnLoadBlockedPlugins( | 260 void LoadablePluginPlaceholder::OnLoadBlockedPlugins( |
225 const std::string& identifier) { | 261 const std::string& identifier) { |
226 if (!identifier.empty() && identifier != identifier_) | 262 if (!identifier.empty() && identifier != identifier_) |
227 return; | 263 return; |
228 | 264 |
229 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI")); | 265 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI")); |
230 LoadPlugin(); | 266 LoadPlugin(); |
231 } | 267 } |
232 | 268 |
233 void LoadablePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) { | 269 void LoadablePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) { |
(...skipping 12 matching lines...) Expand all Loading... |
246 // event propagation changes between "close" vs. "click-to-play". | 282 // event propagation changes between "close" vs. "click-to-play". |
247 if (hidden_) | 283 if (hidden_) |
248 return; | 284 return; |
249 if (!plugin()) | 285 if (!plugin()) |
250 return; | 286 return; |
251 if (!allow_loading_) { | 287 if (!allow_loading_) { |
252 NOTREACHED(); | 288 NOTREACHED(); |
253 return; | 289 return; |
254 } | 290 } |
255 | 291 |
256 // TODO(mmenke): In the case of prerendering, feed into | 292 if (premade_plugin_) { |
257 // ChromeContentRendererClient::CreatePlugin instead, to | 293 // Show the (presumably hidden) premade plugin again. |
258 // reduce the chance of future regressions. | 294 premade_plugin_->updateVisibility(true); |
259 scoped_ptr<PluginInstanceThrottler> throttler; | 295 |
| 296 ReplacePlugin(premade_plugin_); |
| 297 |
| 298 premade_throttler_->RemoveObserver(this); |
| 299 premade_plugin_ = nullptr; |
| 300 premade_throttler_ = nullptr; |
| 301 } else { |
| 302 // TODO(mmenke): In the case of prerendering, feed into |
| 303 // ChromeContentRendererClient::CreatePlugin instead, to |
| 304 // reduce the chance of future regressions. |
| 305 scoped_ptr<PluginInstanceThrottler> throttler; |
260 #if defined(ENABLE_PLUGINS) | 306 #if defined(ENABLE_PLUGINS) |
261 throttler = PluginInstanceThrottler::Get( | 307 throttler = PluginInstanceThrottler::Get( |
262 render_frame(), GetPluginParams().url, power_saver_mode_); | 308 render_frame(), GetPluginParams().url, power_saver_mode_); |
263 #endif | 309 #endif |
264 WebPlugin* plugin = render_frame()->CreatePlugin( | 310 WebPlugin* plugin = render_frame()->CreatePlugin( |
265 GetFrame(), plugin_info_, GetPluginParams(), throttler.Pass()); | 311 GetFrame(), plugin_info_, GetPluginParams(), throttler.Pass()); |
266 ReplacePlugin(plugin); | 312 |
| 313 ReplacePlugin(plugin); |
| 314 } |
267 } | 315 } |
268 | 316 |
269 void LoadablePluginPlaceholder::LoadCallback() { | 317 void LoadablePluginPlaceholder::LoadCallback() { |
270 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click")); | 318 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click")); |
271 #if defined(ENABLE_PLUGINS) | 319 #if defined(ENABLE_PLUGINS) |
272 // If the user specifically clicks on the plug-in content's placeholder, | 320 // If the user specifically clicks on the plug-in content's placeholder, |
273 // disable power saver throttling for this instance. | 321 // disable power saver throttling for this instance. |
274 DisablePowerSaverForInstance( | 322 DisablePowerSaverForInstance( |
275 PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK); | 323 PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK); |
276 #endif | 324 #endif |
277 LoadPlugin(); | 325 LoadPlugin(); |
278 } | 326 } |
279 | 327 |
280 void LoadablePluginPlaceholder::HideCallback() { | 328 void LoadablePluginPlaceholder::HideCallback() { |
281 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Click")); | 329 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Click")); |
282 HidePlugin(); | 330 HidePlugin(); |
283 } | 331 } |
284 | 332 |
285 void LoadablePluginPlaceholder::DidFinishLoadingCallback() { | 333 void LoadablePluginPlaceholder::DidFinishLoadingCallback() { |
286 finished_loading_ = true; | 334 finished_loading_ = true; |
287 if (message_.length() > 0) | 335 if (message_.length() > 0) |
288 UpdateMessage(); | 336 UpdateMessage(); |
| 337 |
| 338 // Wait for the placeholder to finish loading to hide the premade plugin. |
| 339 // This is necessary to prevent a flicker. |
| 340 if (premade_plugin_ && !placeholder_was_replaced_) { |
| 341 premade_plugin_->updateVisibility(false); |
| 342 } |
289 } | 343 } |
290 | 344 |
291 void LoadablePluginPlaceholder::SetPluginInfo( | 345 void LoadablePluginPlaceholder::SetPluginInfo( |
292 const content::WebPluginInfo& plugin_info) { | 346 const content::WebPluginInfo& plugin_info) { |
293 plugin_info_ = plugin_info; | 347 plugin_info_ = plugin_info; |
294 } | 348 } |
295 | 349 |
296 const content::WebPluginInfo& LoadablePluginPlaceholder::GetPluginInfo() const { | 350 const content::WebPluginInfo& LoadablePluginPlaceholder::GetPluginInfo() const { |
297 return plugin_info_; | 351 return plugin_info_; |
298 } | 352 } |
299 | 353 |
300 void LoadablePluginPlaceholder::SetIdentifier(const std::string& identifier) { | 354 void LoadablePluginPlaceholder::SetIdentifier(const std::string& identifier) { |
301 identifier_ = identifier; | 355 identifier_ = identifier; |
302 } | 356 } |
303 | 357 |
304 bool LoadablePluginPlaceholder::LoadingBlocked() const { | 358 bool LoadablePluginPlaceholder::LoadingBlocked() const { |
305 DCHECK(allow_loading_); | 359 DCHECK(allow_loading_); |
306 return is_blocked_for_background_tab_ || is_blocked_for_power_saver_poster_ || | 360 return is_blocked_for_background_tab_ || is_blocked_for_power_saver_poster_ || |
307 is_blocked_for_prerendering_; | 361 is_blocked_for_prerendering_; |
308 } | 362 } |
309 | 363 |
310 } // namespace plugins | 364 } // namespace plugins |
OLD | NEW |