Update comments of TabObserver#onLoadStarted and rename onContentChanged
[chromium-blink-merge.git] / components / plugins / renderer / loadable_plugin_placeholder.cc
blob54a1e06b0b69b470e12b3139c7d3ec1bb813b8a0
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
3 // found in the LICENSE file.
5 #include "components/plugins/renderer/loadable_plugin_placeholder.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/json/string_escape.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "content/public/child/v8_value_converter.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/renderer/render_frame.h"
17 #include "content/public/renderer/render_thread.h"
18 #include "gin/handle.h"
19 #include "gin/object_template_builder.h"
20 #include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebElement.h"
23 #include "third_party/WebKit/public/web/WebInputEvent.h"
24 #include "third_party/WebKit/public/web/WebKit.h"
25 #include "third_party/WebKit/public/web/WebLocalFrame.h"
26 #include "third_party/WebKit/public/web/WebPluginContainer.h"
27 #include "third_party/WebKit/public/web/WebScriptSource.h"
28 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
29 #include "third_party/WebKit/public/web/WebView.h"
31 using base::UserMetricsAction;
32 using content::PluginInstanceThrottler;
33 using content::RenderThread;
35 namespace plugins {
37 void LoadablePluginPlaceholder::BlockForPowerSaverPoster() {
38 DCHECK(!is_blocked_for_power_saver_poster_);
39 is_blocked_for_power_saver_poster_ = true;
41 render_frame()->RegisterPeripheralPlugin(
42 GURL(GetPluginParams().url).GetOrigin(),
43 base::Bind(&LoadablePluginPlaceholder::MarkPluginEssential,
44 weak_factory_.GetWeakPtr(),
45 PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_WHITELIST));
48 void LoadablePluginPlaceholder::SetPremadePlugin(
49 content::PluginInstanceThrottler* throttler) {
50 DCHECK(throttler);
51 DCHECK(!premade_throttler_);
52 premade_throttler_ = throttler;
55 LoadablePluginPlaceholder::LoadablePluginPlaceholder(
56 content::RenderFrame* render_frame,
57 blink::WebLocalFrame* frame,
58 const blink::WebPluginParams& params,
59 const std::string& html_data)
60 : PluginPlaceholder(render_frame, frame, params, html_data),
61 is_blocked_for_background_tab_(false),
62 is_blocked_for_prerendering_(false),
63 is_blocked_for_power_saver_poster_(false),
64 power_saver_enabled_(false),
65 premade_throttler_(nullptr),
66 allow_loading_(true),
67 finished_loading_(false),
68 weak_factory_(this) {
71 LoadablePluginPlaceholder::~LoadablePluginPlaceholder() {
74 void LoadablePluginPlaceholder::MarkPluginEssential(
75 PluginInstanceThrottler::PowerSaverUnthrottleMethod method) {
76 if (!power_saver_enabled_)
77 return;
79 power_saver_enabled_ = false;
81 if (premade_throttler_)
82 premade_throttler_->MarkPluginEssential(method);
83 else
84 PluginInstanceThrottler::RecordUnthrottleMethodMetric(method);
86 if (is_blocked_for_power_saver_poster_) {
87 is_blocked_for_power_saver_poster_ = false;
88 if (!LoadingBlocked())
89 LoadPlugin();
93 gin::ObjectTemplateBuilder LoadablePluginPlaceholder::GetObjectTemplateBuilder(
94 v8::Isolate* isolate) {
95 return PluginPlaceholder::GetObjectTemplateBuilder(isolate)
96 .SetMethod("load", &LoadablePluginPlaceholder::LoadCallback)
97 .SetMethod("didFinishLoading",
98 &LoadablePluginPlaceholder::DidFinishLoadingCallback);
101 void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
102 CHECK(plugin());
103 if (!new_plugin)
104 return;
105 blink::WebPluginContainer* container = plugin()->container();
106 // Set the new plugin on the container before initializing it.
107 container->setPlugin(new_plugin);
108 // Save the element in case the plugin is removed from the page during
109 // initialization.
110 blink::WebElement element = container->element();
111 bool plugin_needs_initialization =
112 !premade_throttler_ || new_plugin != premade_throttler_->GetWebPlugin();
113 if (plugin_needs_initialization && !new_plugin->initialize(container)) {
114 // We couldn't initialize the new plugin. Restore the old one and abort.
115 container->setPlugin(plugin());
116 return;
119 // The plugin has been removed from the page. Destroy the old plugin. We
120 // will be destroyed as soon as V8 garbage collects us.
121 if (!element.pluginContainer()) {
122 plugin()->destroy();
123 return;
126 // During initialization, the new plugin might have replaced itself in turn
127 // with another plugin. Make sure not to use the passed in |new_plugin| after
128 // this point.
129 new_plugin = container->plugin();
131 plugin()->RestoreTitleText();
132 container->invalidate();
133 container->reportGeometry();
134 plugin()->ReplayReceivedData(new_plugin);
135 plugin()->destroy();
138 void LoadablePluginPlaceholder::SetMessage(const base::string16& message) {
139 message_ = message;
140 if (finished_loading_)
141 UpdateMessage();
144 void LoadablePluginPlaceholder::UpdateMessage() {
145 if (!plugin())
146 return;
147 std::string script =
148 "window.setMessage(" + base::GetQuotedJSONString(message_) + ")";
149 plugin()->web_view()->mainFrame()->executeScript(
150 blink::WebScriptSource(base::UTF8ToUTF16(script)));
153 void LoadablePluginPlaceholder::PluginDestroyed() {
154 if (power_saver_enabled_) {
155 if (premade_throttler_) {
156 // Since the premade plugin has been detached from the container, it will
157 // not be automatically destroyed along with the page.
158 premade_throttler_->GetWebPlugin()->destroy();
159 premade_throttler_ = nullptr;
160 } else if (is_blocked_for_power_saver_poster_) {
161 // Record the NEVER unthrottle count only if there is no throttler.
162 PluginInstanceThrottler::RecordUnthrottleMethodMetric(
163 PluginInstanceThrottler::UNTHROTTLE_METHOD_NEVER);
166 // Prevent processing subsequent calls to MarkPluginEssential.
167 power_saver_enabled_ = false;
170 PluginPlaceholder::PluginDestroyed();
173 v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject(
174 v8::Isolate* isolate) const {
175 // Pass through JavaScript access to the underlying throttled plugin.
176 if (premade_throttler_ && premade_throttler_->GetWebPlugin()) {
177 return premade_throttler_->GetWebPlugin()->v8ScriptableObject(isolate);
179 return v8::Local<v8::Object>();
182 void LoadablePluginPlaceholder::WasShown() {
183 if (is_blocked_for_background_tab_) {
184 is_blocked_for_background_tab_ = false;
185 if (!LoadingBlocked())
186 LoadPlugin();
190 void LoadablePluginPlaceholder::OnLoadBlockedPlugins(
191 const std::string& identifier) {
192 if (!identifier.empty() && identifier != identifier_)
193 return;
195 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI"));
196 LoadPlugin();
199 void LoadablePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) {
200 // Prerendering can only be enabled prior to a RenderView's first navigation,
201 // so no BlockedPlugin should see the notification that enables prerendering.
202 DCHECK(!is_prerendering);
203 if (is_blocked_for_prerendering_) {
204 is_blocked_for_prerendering_ = false;
205 if (!LoadingBlocked())
206 LoadPlugin();
210 void LoadablePluginPlaceholder::LoadPlugin() {
211 // This is not strictly necessary but is an important defense in case the
212 // event propagation changes between "close" vs. "click-to-play".
213 if (hidden())
214 return;
215 if (!plugin())
216 return;
217 if (!allow_loading_) {
218 NOTREACHED();
219 return;
222 if (premade_throttler_) {
223 premade_throttler_->SetHiddenForPlaceholder(false /* hidden */);
224 ReplacePlugin(premade_throttler_->GetWebPlugin());
225 premade_throttler_ = nullptr;
226 } else {
227 ReplacePlugin(CreatePlugin());
231 void LoadablePluginPlaceholder::LoadCallback() {
232 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click"));
233 // If the user specifically clicks on the plugin content's placeholder,
234 // disable power saver throttling for this instance.
235 MarkPluginEssential(PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
236 LoadPlugin();
239 void LoadablePluginPlaceholder::DidFinishLoadingCallback() {
240 finished_loading_ = true;
241 if (message_.length() > 0)
242 UpdateMessage();
244 // Wait for the placeholder to finish loading to hide the premade plugin.
245 // This is necessary to prevent a flicker.
246 if (premade_throttler_ && power_saver_enabled_)
247 premade_throttler_->SetHiddenForPlaceholder(true /* hidden */);
249 // Set an attribute and post an event, so browser tests can wait for the
250 // placeholder to be ready to receive simulated user input.
251 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
252 switches::kEnablePluginPlaceholderTesting)) {
253 blink::WebElement element = plugin()->container()->element();
254 element.setAttribute("placeholderLoaded", "true");
256 scoped_ptr<content::V8ValueConverter> converter(
257 content::V8ValueConverter::create());
258 base::StringValue value("placeholderLoaded");
259 blink::WebSerializedScriptValue message_data =
260 blink::WebSerializedScriptValue::serialize(converter->ToV8Value(
261 &value, element.document().frame()->mainWorldScriptContext()));
263 blink::WebDOMEvent event = element.document().createEvent("MessageEvent");
264 blink::WebDOMMessageEvent msg_event = event.to<blink::WebDOMMessageEvent>();
265 msg_event.initMessageEvent("message", // type
266 false, // canBubble
267 false, // cancelable
268 message_data, // data
269 "", // origin [*]
270 NULL, // source [*]
271 ""); // lastEventId
272 element.dispatchEvent(msg_event);
276 void LoadablePluginPlaceholder::SetPluginInfo(
277 const content::WebPluginInfo& plugin_info) {
278 plugin_info_ = plugin_info;
281 const content::WebPluginInfo& LoadablePluginPlaceholder::GetPluginInfo() const {
282 return plugin_info_;
285 void LoadablePluginPlaceholder::SetIdentifier(const std::string& identifier) {
286 identifier_ = identifier;
289 const std::string& LoadablePluginPlaceholder::GetIdentifier() const {
290 return identifier_;
293 bool LoadablePluginPlaceholder::LoadingBlocked() const {
294 DCHECK(allow_loading_);
295 return is_blocked_for_background_tab_ || is_blocked_for_power_saver_poster_ ||
296 is_blocked_for_prerendering_;
299 } // namespace plugins