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