blob: 4fcb837f1c4dcb36cd0bda9c12a47a5b2d02e657 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/plugins/renderer/loadable_plugin_placeholder.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/json/string_escape.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_view.h"
#include "url/gurl.h"
#include "url/origin.h"
using base::UserMetricsAction;
using content::RenderFrame;
using content::RenderThread;
namespace plugins {
void LoadablePluginPlaceholder::MaybeLoadBlockedPlugin(
const std::string& identifier) {
if (!identifier.empty() && identifier != identifier_)
return;
RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI"));
LoadPlugin();
}
LoadablePluginPlaceholder::LoadablePluginPlaceholder(
RenderFrame* render_frame,
const blink::WebPluginParams& params)
: PluginPlaceholderBase(render_frame, params) {}
LoadablePluginPlaceholder::~LoadablePluginPlaceholder() {
}
void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
CHECK(plugin());
if (!new_plugin)
return;
blink::WebPluginContainer* container = plugin()->Container();
// This can occur if the container has been destroyed.
if (!container) {
new_plugin->Destroy();
return;
}
container->SetPlugin(new_plugin);
if (!new_plugin->Initialize(container)) {
if (new_plugin->Container()) {
// Since the we couldn't initialize the new plugin, but the container
// still exists, restore the placeholder and destroy the new plugin.
container->SetPlugin(plugin());
new_plugin->Destroy();
} else {
// The container has been destroyed, along with the new plugin. Destroy
// our placeholder plugin also.
plugin()->Destroy();
}
return;
}
// During initialization, the new plugin might have replaced itself in turn
// with another plugin. Make sure not to use the passed in |new_plugin| after
// this point.
new_plugin = container->Plugin();
container->Invalidate();
container->ReportGeometry();
container->GetElement().SetAttribute("title", plugin()->old_title());
plugin()->ReplayReceivedData(new_plugin);
plugin()->Destroy();
}
void LoadablePluginPlaceholder::UpdateMessage() {
if (!plugin())
return;
std::string script =
"window.setMessage(" + base::GetQuotedJSONString(message_) + ")";
plugin()->main_frame()->ExecuteScript(
blink::WebScriptSource(blink::WebString::FromUTF8(script)));
}
bool LoadablePluginPlaceholder::IsErrorPlaceholder() {
return !allow_loading_;
}
void LoadablePluginPlaceholder::OnSetIsNoStatePrefetching(
bool is_no_state_prefetching) {
// NoStatePrefetching can only be enabled prior to a RenderView's first
// navigation, so no BlockedPlugin should see the notification that enables
// NoStatePrefetching.
DCHECK(!is_no_state_prefetching);
if (is_blocked_for_no_state_prefetching_) {
is_blocked_for_no_state_prefetching_ = false;
if (!LoadingBlocked())
LoadPlugin();
}
}
void LoadablePluginPlaceholder::LoadPlugin() {
// This is not strictly necessary but is an important defense in case the
// event propagation changes between "close" vs. "click-to-play".
if (hidden())
return;
if (!plugin())
return;
if (!allow_loading_) {
NOTREACHED();
}
ReplacePlugin(CreatePlugin());
}
void LoadablePluginPlaceholder::LoadCallback() {
RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click"));
// If the user specifically clicks on the plugin content's placeholder,
// disable power saver throttling for this instance.
LoadPlugin();
}
void LoadablePluginPlaceholder::DidFinishLoadingCallback() {
finished_loading_ = true;
if (message_.length() > 0)
UpdateMessage();
// In case our initial geometry was reported before the placeholder finished
// loading, request another one. Needed for correct large poster unthrottling.
if (plugin()) {
CHECK(plugin()->Container());
plugin()->Container()->ReportGeometry();
}
}
void LoadablePluginPlaceholder::SetPluginInfo(
const content::WebPluginInfo& plugin_info) {
plugin_info_ = plugin_info;
}
const content::WebPluginInfo& LoadablePluginPlaceholder::GetPluginInfo() const {
return plugin_info_;
}
void LoadablePluginPlaceholder::SetIdentifier(const std::string& identifier) {
identifier_ = identifier;
}
bool LoadablePluginPlaceholder::LoadingBlocked() const {
DCHECK(allow_loading_);
return is_blocked_for_no_state_prefetching_;
}
} // namespace plugins