| 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 |