diff options
author | tommycli <tommycli@chromium.org> | 2015-06-11 15:20:14 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-11 22:21:17 +0000 |
commit | 425d6965196e7448a2ba9180a3fd2f5b08f5b329 (patch) | |
tree | 0799c08a8aa683b6196ebbf7f3963b29731abbcc /components/plugins | |
parent | 60b17299b23088c43179c092a26977cdb294b0da (diff) | |
download | chromium_src-425d6965196e7448a2ba9180a3fd2f5b08f5b329.zip chromium_src-425d6965196e7448a2ba9180a3fd2f5b08f5b329.tar.gz chromium_src-425d6965196e7448a2ba9180a3fd2f5b08f5b329.tar.bz2 |
Reland: Plugin Placeholders: Refactor for platforms that don't support plugins
This patch removes a lot of plugin placeholder code from builds that don't support plugins (enable_plugins==0).
This is a reland of https://codereview.chromium.org/1126073003/.
See patchsets for fixes of the crashes.
BUG=493889
TBR=
Review URL: https://codereview.chromium.org/1161923004
Cr-Commit-Position: refs/heads/master@{#334054}
Diffstat (limited to 'components/plugins')
-rw-r--r-- | components/plugins/renderer/BUILD.gn | 10 | ||||
-rw-r--r-- | components/plugins/renderer/loadable_plugin_placeholder.cc | 129 | ||||
-rw-r--r-- | components/plugins/renderer/loadable_plugin_placeholder.h | 34 | ||||
-rw-r--r-- | components/plugins/renderer/mobile_youtube_plugin.cc | 34 | ||||
-rw-r--r-- | components/plugins/renderer/mobile_youtube_plugin.h | 14 | ||||
-rw-r--r-- | components/plugins/renderer/plugin_placeholder.cc | 120 | ||||
-rw-r--r-- | components/plugins/renderer/plugin_placeholder.h | 60 | ||||
-rw-r--r-- | components/plugins/renderer/webview_plugin.cc | 17 | ||||
-rw-r--r-- | components/plugins/renderer/webview_plugin.h | 7 |
9 files changed, 215 insertions, 210 deletions
diff --git a/components/plugins/renderer/BUILD.gn b/components/plugins/renderer/BUILD.gn index ef7e8f1..446ad99 100644 --- a/components/plugins/renderer/BUILD.gn +++ b/components/plugins/renderer/BUILD.gn @@ -2,15 +2,21 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/features.gni") + static_library("renderer") { sources = [ - "loadable_plugin_placeholder.cc", - "loadable_plugin_placeholder.h", "plugin_placeholder.cc", "plugin_placeholder.h", "webview_plugin.cc", "webview_plugin.h", ] + if (enable_plugins) { + sources += [ + "loadable_plugin_placeholder.cc", + "loadable_plugin_placeholder.h", + ] + } if (is_android) { sources += [ "mobile_youtube_plugin.cc", diff --git a/components/plugins/renderer/loadable_plugin_placeholder.cc b/components/plugins/renderer/loadable_plugin_placeholder.cc index ea288e2..a41c9ea 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.cc +++ b/components/plugins/renderer/loadable_plugin_placeholder.cc @@ -9,7 +9,6 @@ #include "base/command_line.h" #include "base/json/string_escape.h" #include "base/strings/string_piece.h" -#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "base/values.h" @@ -29,24 +28,13 @@ #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" #include "third_party/WebKit/public/web/WebView.h" -#include "third_party/re2/re2/re2.h" using base::UserMetricsAction; -using blink::WebElement; -using blink::WebLocalFrame; -using blink::WebMouseEvent; -using blink::WebNode; -using blink::WebPlugin; -using blink::WebPluginContainer; -using blink::WebPluginParams; -using blink::WebScriptSource; -using blink::WebURLRequest; using content::PluginInstanceThrottler; using content::RenderThread; namespace plugins { -#if defined(ENABLE_PLUGINS) // TODO(tommycli): After an unthrottling size update, re-check the size after // this delay, as Blink can report incorrect sizes to plugins while the // compositing state is dirty. Chosen because it seems to work. @@ -69,26 +57,19 @@ void LoadablePluginPlaceholder::SetPremadePlugin( DCHECK(!premade_throttler_); premade_throttler_ = throttler; } -#endif LoadablePluginPlaceholder::LoadablePluginPlaceholder( content::RenderFrame* render_frame, - WebLocalFrame* frame, - const WebPluginParams& params, - const std::string& html_data, - GURL placeholderDataUrl) - : PluginPlaceholder(render_frame, - frame, - params, - html_data, - placeholderDataUrl), + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + const std::string& html_data) + : PluginPlaceholderBase(render_frame, frame, params, html_data), is_blocked_for_background_tab_(false), is_blocked_for_prerendering_(false), is_blocked_for_power_saver_poster_(false), power_saver_enabled_(false), premade_throttler_(nullptr), - allow_loading_(false), - hidden_(false), + allow_loading_(true), finished_loading_(false), in_size_recheck_(false), weak_factory_(this) { @@ -97,7 +78,6 @@ LoadablePluginPlaceholder::LoadablePluginPlaceholder( LoadablePluginPlaceholder::~LoadablePluginPlaceholder() { } -#if defined(ENABLE_PLUGINS) void LoadablePluginPlaceholder::MarkPluginEssential( PluginInstanceThrottler::PowerSaverUnthrottleMethod method) { if (!power_saver_enabled_) @@ -116,39 +96,17 @@ void LoadablePluginPlaceholder::MarkPluginEssential( LoadPlugin(); } } -#endif - -void LoadablePluginPlaceholder::BindWebFrame(blink::WebFrame* frame) { - v8::Isolate* isolate = blink::mainThreadIsolate(); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = frame->mainWorldScriptContext(); - DCHECK(!context.IsEmpty()); - - v8::Context::Scope context_scope(context); - v8::Local<v8::Object> global = context->Global(); - global->Set(gin::StringToV8(isolate, "plugin"), - gin::CreateHandle(isolate, this).ToV8()); -} - -gin::ObjectTemplateBuilder LoadablePluginPlaceholder::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) - .SetMethod("load", &LoadablePluginPlaceholder::LoadCallback) - .SetMethod("hide", &LoadablePluginPlaceholder::HideCallback) - .SetMethod("didFinishLoading", - &LoadablePluginPlaceholder::DidFinishLoadingCallback); -} -void LoadablePluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) { +void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) { CHECK(plugin()); if (!new_plugin) return; - WebPluginContainer* container = plugin()->container(); + blink::WebPluginContainer* container = plugin()->container(); // Set the new plugin on the container before initializing it. container->setPlugin(new_plugin); // Save the element in case the plugin is removed from the page during // initialization. - WebElement element = container->element(); + blink::WebElement element = container->element(); bool plugin_needs_initialization = !premade_throttler_ || new_plugin != premade_throttler_->GetWebPlugin(); if (plugin_needs_initialization && !new_plugin->initialize(container)) { @@ -176,54 +134,6 @@ void LoadablePluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) { plugin()->destroy(); } -void LoadablePluginPlaceholder::HidePlugin() { - hidden_ = true; - if (!plugin()) - return; - WebPluginContainer* container = plugin()->container(); - WebElement element = container->element(); - element.setAttribute("style", "display: none;"); - // If we have a width and height, search for a parent (often <div>) with the - // same dimensions. If we find such a parent, hide that as well. - // This makes much more uncovered page content usable (including clickable) - // as opposed to merely visible. - // TODO(cevans) -- it's a foul heuristic but we're going to tolerate it for - // now for these reasons: - // 1) Makes the user experience better. - // 2) Foulness is encapsulated within this single function. - // 3) Confidence in no fasle positives. - // 4) Seems to have a good / low false negative rate at this time. - if (element.hasAttribute("width") && element.hasAttribute("height")) { - std::string width_str("width:[\\s]*"); - width_str += element.getAttribute("width").utf8().data(); - if (EndsWith(width_str, "px", false)) { - width_str = width_str.substr(0, width_str.length() - 2); - } - base::TrimWhitespace(width_str, base::TRIM_TRAILING, &width_str); - width_str += "[\\s]*px"; - std::string height_str("height:[\\s]*"); - height_str += element.getAttribute("height").utf8().data(); - if (EndsWith(height_str, "px", false)) { - height_str = height_str.substr(0, height_str.length() - 2); - } - base::TrimWhitespace(height_str, base::TRIM_TRAILING, &height_str); - height_str += "[\\s]*px"; - WebNode parent = element; - while (!parent.parentNode().isNull()) { - parent = parent.parentNode(); - if (!parent.isElementNode()) - continue; - element = parent.toConst<WebElement>(); - if (element.hasAttribute("style")) { - std::string style_str = element.getAttribute("style").utf8(); - if (RE2::PartialMatch(style_str, width_str) && - RE2::PartialMatch(style_str, height_str)) - element.setAttribute("style", "display: none;"); - } - } - } -} - void LoadablePluginPlaceholder::SetMessage(const base::string16& message) { message_ = message; if (finished_loading_) @@ -236,11 +146,10 @@ void LoadablePluginPlaceholder::UpdateMessage() { std::string script = "window.setMessage(" + base::GetQuotedJSONString(message_) + ")"; plugin()->web_view()->mainFrame()->executeScript( - WebScriptSource(base::UTF8ToUTF16(script))); + blink::WebScriptSource(base::UTF8ToUTF16(script))); } void LoadablePluginPlaceholder::PluginDestroyed() { -#if defined(ENABLE_PLUGINS) if (power_saver_enabled_) { if (premade_throttler_) { // Since the premade plugin has been detached from the container, it will @@ -256,23 +165,19 @@ void LoadablePluginPlaceholder::PluginDestroyed() { // Prevent processing subsequent calls to MarkPluginEssential. power_saver_enabled_ = false; } -#endif - PluginPlaceholder::PluginDestroyed(); + PluginPlaceholderBase::PluginDestroyed(); } v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject( v8::Isolate* isolate) const { -#if defined(ENABLE_PLUGINS) // Pass through JavaScript access to the underlying throttled plugin. if (premade_throttler_ && premade_throttler_->GetWebPlugin()) { return premade_throttler_->GetWebPlugin()->v8ScriptableObject(isolate); } -#endif return v8::Local<v8::Object>(); } -#if defined(ENABLE_PLUGINS) void LoadablePluginPlaceholder::OnUnobscuredSizeUpdate( const gfx::Size& unobscured_size) { DCHECK( @@ -304,7 +209,6 @@ void LoadablePluginPlaceholder::OnUnobscuredSizeUpdate( size_update_timer_.Stop(); } } -#endif // defined(ENABLE_PLUGINS) void LoadablePluginPlaceholder::WasShown() { if (is_blocked_for_background_tab_) { @@ -337,7 +241,7 @@ void LoadablePluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) { 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_) + if (hidden()) return; if (!plugin()) return; @@ -357,19 +261,12 @@ void LoadablePluginPlaceholder::LoadPlugin() { void LoadablePluginPlaceholder::LoadCallback() { RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click")); -#if defined(ENABLE_PLUGINS) // If the user specifically clicks on the plugin content's placeholder, // disable power saver throttling for this instance. MarkPluginEssential(PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK); -#endif LoadPlugin(); } -void LoadablePluginPlaceholder::HideCallback() { - RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Click")); - HidePlugin(); -} - void LoadablePluginPlaceholder::DidFinishLoadingCallback() { finished_loading_ = true; if (message_.length() > 0) @@ -384,7 +281,7 @@ void LoadablePluginPlaceholder::DidFinishLoadingCallback() { // placeholder to be ready to receive simulated user input. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnablePluginPlaceholderTesting)) { - WebElement element = plugin()->container()->element(); + blink::WebElement element = plugin()->container()->element(); element.setAttribute("placeholderLoaded", "true"); scoped_ptr<content::V8ValueConverter> converter( @@ -430,7 +327,6 @@ bool LoadablePluginPlaceholder::LoadingBlocked() const { is_blocked_for_prerendering_; } -#if defined(ENABLE_PLUGINS) void LoadablePluginPlaceholder::RecheckSizeAndMaybeUnthrottle() { DCHECK( content::RenderThread::Get()->GetTaskRunner()->BelongsToCurrentThread()); @@ -448,6 +344,5 @@ void LoadablePluginPlaceholder::RecheckSizeAndMaybeUnthrottle() { in_size_recheck_ = false; } -#endif // defined(ENABLE_PLUGINS) } // namespace plugins diff --git a/components/plugins/renderer/loadable_plugin_placeholder.h b/components/plugins/renderer/loadable_plugin_placeholder.h index 0111dff..13b903d 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.h +++ b/components/plugins/renderer/loadable_plugin_placeholder.h @@ -10,11 +10,12 @@ #include "components/plugins/renderer/plugin_placeholder.h" #include "content/public/common/webplugininfo.h" #include "content/public/renderer/plugin_instance_throttler.h" +#include "content/public/renderer/render_thread.h" namespace plugins { // Placeholders can be used if a plugin is missing or not available // (blocked or disabled). -class LoadablePluginPlaceholder : public PluginPlaceholder { +class LoadablePluginPlaceholder : public PluginPlaceholderBase { public: void set_blocked_for_background_tab(bool blocked_for_background_tab) { is_blocked_for_background_tab_ = blocked_for_background_tab; @@ -24,7 +25,6 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { is_blocked_for_prerendering_ = blocked_for_prerendering; } -#if defined(ENABLE_PLUGINS) bool power_saver_enabled() const { return power_saver_enabled_; } void set_power_saver_enabled(bool power_saver_enabled) { @@ -36,23 +36,19 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { // When we load the plugin, use this already-created plugin, not a new one. void SetPremadePlugin(content::PluginInstanceThrottler* throttler); -#endif - void set_allow_loading(bool allow_loading) { allow_loading_ = allow_loading; } + void DisallowLoading() { allow_loading_ = false; } protected: LoadablePluginPlaceholder(content::RenderFrame* render_frame, blink::WebLocalFrame* frame, const blink::WebPluginParams& params, - const std::string& html_data, - GURL placeholderDataUrl); + const std::string& html_data); ~LoadablePluginPlaceholder() override; -#if defined(ENABLE_PLUGINS) void MarkPluginEssential( content::PluginInstanceThrottler::PowerSaverUnthrottleMethod method); -#endif void OnLoadBlockedPlugins(const std::string& identifier); void OnSetIsPrerendering(bool is_prerendering); @@ -68,42 +64,27 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { // a placeholder again). void ReplacePlugin(blink::WebPlugin* new_plugin); - // Hide this placeholder. - void HidePlugin(); - // Load the blocked plugin. void LoadPlugin(); - // WebViewPlugin::Delegate (via PluginPlaceholder) method - void BindWebFrame(blink::WebFrame* frame) override; - - // gin::Wrappable method: - gin::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; + // Javascript callbacks: + void LoadCallback(); + void DidFinishLoadingCallback(); private: // WebViewPlugin::Delegate methods: void PluginDestroyed() override; v8::Local<v8::Object> GetV8ScriptableObject( v8::Isolate* isolate) const override; -#if defined(ENABLE_PLUGINS) void OnUnobscuredSizeUpdate(const gfx::Size& unobscured_size) override; -#endif // RenderFrameObserver methods: void WasShown() override; - // Javascript callbacks: - void LoadCallback(); - void HideCallback(); - void DidFinishLoadingCallback(); - void UpdateMessage(); bool LoadingBlocked() const; -#if defined(ENABLE_PLUGINS) void RecheckSizeAndMaybeUnthrottle(); -#endif // Plugin creation is embedder-specific. virtual blink::WebPlugin* CreatePlugin() = 0; @@ -132,7 +113,6 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { bool allow_loading_; - bool hidden_; bool finished_loading_; std::string identifier_; diff --git a/components/plugins/renderer/mobile_youtube_plugin.cc b/components/plugins/renderer/mobile_youtube_plugin.cc index 6db102a..9745a0a 100644 --- a/components/plugins/renderer/mobile_youtube_plugin.cc +++ b/components/plugins/renderer/mobile_youtube_plugin.cc @@ -11,10 +11,8 @@ #include "base/values.h" #include "content/public/common/content_constants.h" #include "content/public/renderer/render_frame.h" -#include "gin/handle.h" #include "gin/object_template_builder.h" #include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/WebKit/public/web/WebKit.h" #include "ui/base/webui/jstemplate_builder.h" using blink::WebFrame; @@ -73,16 +71,17 @@ bool IsValidYouTubeVideo(const std::string& path) { namespace plugins { +gin::WrapperInfo MobileYouTubePlugin::kWrapperInfo = {gin::kEmbedderNativeGin}; + MobileYouTubePlugin::MobileYouTubePlugin(content::RenderFrame* render_frame, blink::WebLocalFrame* frame, const blink::WebPluginParams& params, - base::StringPiece& template_html, - GURL placeholderDataUrl) - : PluginPlaceholder(render_frame, - frame, - params, - HtmlData(params, template_html), - placeholderDataUrl) {} + base::StringPiece& template_html) + : PluginPlaceholderBase(render_frame, + frame, + params, + HtmlData(params, template_html)) { +} MobileYouTubePlugin::~MobileYouTubePlugin() {} @@ -108,22 +107,15 @@ void MobileYouTubePlugin::OpenYoutubeUrlCallback() { GetFrame(), request, blink::WebNavigationPolicyNewForegroundTab); } -void MobileYouTubePlugin::BindWebFrame(WebFrame* frame) { - v8::Isolate* isolate = blink::mainThreadIsolate(); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = frame->mainWorldScriptContext(); - DCHECK(!context.IsEmpty()); - - v8::Context::Scope context_scope(context); - v8::Local<v8::Object> global = context->Global(); - global->Set(gin::StringToV8(isolate, "plugin"), - gin::CreateHandle(isolate, this).ToV8()); +v8::Local<v8::Value> MobileYouTubePlugin::GetV8Handle(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, this).ToV8(); } gin::ObjectTemplateBuilder MobileYouTubePlugin::GetObjectTemplateBuilder( v8::Isolate* isolate) { - return PluginPlaceholder::GetObjectTemplateBuilder(isolate) - .SetMethod("openYoutubeURL", &MobileYouTubePlugin::OpenYoutubeUrlCallback); + return gin::Wrappable<MobileYouTubePlugin>::GetObjectTemplateBuilder(isolate) + .SetMethod("openYoutubeURL", + &MobileYouTubePlugin::OpenYoutubeUrlCallback); } } // namespace plugins diff --git a/components/plugins/renderer/mobile_youtube_plugin.h b/components/plugins/renderer/mobile_youtube_plugin.h index 99a6213..9d46700 100644 --- a/components/plugins/renderer/mobile_youtube_plugin.h +++ b/components/plugins/renderer/mobile_youtube_plugin.h @@ -14,13 +14,15 @@ namespace plugins { // of http://www.youtube.com/v/VIDEO_ID. This placeholder replaces the url with // a simple html page and clicking the play image redirects the user to the // mobile youtube app. -class MobileYouTubePlugin : public PluginPlaceholder { +class MobileYouTubePlugin final : public PluginPlaceholderBase, + public gin::Wrappable<MobileYouTubePlugin> { public: + static gin::WrapperInfo kWrapperInfo; + MobileYouTubePlugin(content::RenderFrame* render_frame, blink::WebLocalFrame* frame, const blink::WebPluginParams& params, - base::StringPiece& template_html, - GURL placeholderDataUrl); + base::StringPiece& template_html); // Whether this is a youtube url. static bool IsYouTubeURL(const GURL& url, const std::string& mime_type); @@ -31,12 +33,12 @@ class MobileYouTubePlugin : public PluginPlaceholder { // Opens a youtube app in the current tab. void OpenYoutubeUrlCallback(); - // WebViewPlugin::Delegate (via PluginPlaceholder) method - void BindWebFrame(blink::WebFrame* frame) override; + // WebViewPlugin::Delegate methods: + v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) override; // gin::Wrappable (via PluginPlaceholder) method gin::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate) override; + v8::Isolate* isolate) final; DISALLOW_COPY_AND_ASSIGN(MobileYouTubePlugin); }; diff --git a/components/plugins/renderer/plugin_placeholder.cc b/components/plugins/renderer/plugin_placeholder.cc index 180e913..98fc8cb 100644 --- a/components/plugins/renderer/plugin_placeholder.cc +++ b/components/plugins/renderer/plugin_placeholder.cc @@ -4,18 +4,26 @@ #include "components/plugins/renderer/plugin_placeholder.h" +#include "base/strings/string_util.h" #include "content/public/common/web_preferences.h" #include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_thread.h" +#include "gin/object_template_builder.h" +#include "third_party/WebKit/public/web/WebElement.h" +#include "third_party/WebKit/public/web/WebPluginContainer.h" +#include "third_party/re2/re2/re2.h" namespace plugins { -gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; +// The placeholder is loaded in normal web renderer processes, so it should not +// have a chrome:// scheme that might let it be confused with a WebUI page. +const char kPluginPlaceholderDataURL[] = "data:text/html,pluginplaceholderdata"; -PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - const std::string& html_data, - GURL placeholderDataUrl) +PluginPlaceholderBase::PluginPlaceholderBase( + content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + const std::string& html_data) : content::RenderFrameObserver(render_frame), frame_(frame), plugin_params_(params), @@ -24,36 +32,116 @@ PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, ? render_frame->GetWebkitPreferences() : content::WebPreferences(), html_data, - placeholderDataUrl)) { - DCHECK(placeholderDataUrl.is_valid()) - << "Blink requires the placeholder to have a valid URL."; + GURL(kPluginPlaceholderDataURL))), + hidden_(false) { } -PluginPlaceholder::~PluginPlaceholder() {} +PluginPlaceholderBase::~PluginPlaceholderBase() { +} -const blink::WebPluginParams& PluginPlaceholder::GetPluginParams() const { +const blink::WebPluginParams& PluginPlaceholderBase::GetPluginParams() const { return plugin_params_; } -void PluginPlaceholder::ShowContextMenu(const blink::WebMouseEvent& event) { +void PluginPlaceholderBase::ShowContextMenu(const blink::WebMouseEvent& event) { // Does nothing by default. Will be overridden if a specific browser wants // a context menu. return; } -void PluginPlaceholder::PluginDestroyed() { +void PluginPlaceholderBase::PluginDestroyed() { plugin_ = NULL; } -v8::Local<v8::Object> PluginPlaceholder::GetV8ScriptableObject( +v8::Local<v8::Object> PluginPlaceholderBase::GetV8ScriptableObject( v8::Isolate* isolate) const { return v8::Local<v8::Object>(); } -void PluginPlaceholder::OnDestruct() { +void PluginPlaceholderBase::HidePlugin() { + hidden_ = true; + if (!plugin()) + return; + blink::WebPluginContainer* container = plugin()->container(); + blink::WebElement element = container->element(); + element.setAttribute("style", "display: none;"); + // If we have a width and height, search for a parent (often <div>) with the + // same dimensions. If we find such a parent, hide that as well. + // This makes much more uncovered page content usable (including clickable) + // as opposed to merely visible. + // TODO(cevans) -- it's a foul heuristic but we're going to tolerate it for + // now for these reasons: + // 1) Makes the user experience better. + // 2) Foulness is encapsulated within this single function. + // 3) Confidence in no fasle positives. + // 4) Seems to have a good / low false negative rate at this time. + if (element.hasAttribute("width") && element.hasAttribute("height")) { + std::string width_str("width:[\\s]*"); + width_str += element.getAttribute("width").utf8().data(); + if (EndsWith(width_str, "px", false)) { + width_str = width_str.substr(0, width_str.length() - 2); + } + base::TrimWhitespace(width_str, base::TRIM_TRAILING, &width_str); + width_str += "[\\s]*px"; + std::string height_str("height:[\\s]*"); + height_str += element.getAttribute("height").utf8().data(); + if (EndsWith(height_str, "px", false)) { + height_str = height_str.substr(0, height_str.length() - 2); + } + base::TrimWhitespace(height_str, base::TRIM_TRAILING, &height_str); + height_str += "[\\s]*px"; + blink::WebNode parent = element; + while (!parent.parentNode().isNull()) { + parent = parent.parentNode(); + if (!parent.isElementNode()) + continue; + element = parent.toConst<blink::WebElement>(); + if (element.hasAttribute("style")) { + std::string style_str = element.getAttribute("style").utf8(); + if (RE2::PartialMatch(style_str, width_str) && + RE2::PartialMatch(style_str, height_str)) + element.setAttribute("style", "display: none;"); + } + } + } +} + +void PluginPlaceholderBase::HideCallback() { + content::RenderThread::Get()->RecordAction( + base::UserMetricsAction("Plugin_Hide_Click")); + HidePlugin(); +} + +void PluginPlaceholderBase::OnDestruct() { frame_ = NULL; } -blink::WebLocalFrame* PluginPlaceholder::GetFrame() { return frame_; } +blink::WebLocalFrame* PluginPlaceholderBase::GetFrame() { + return frame_; +} + +// static +gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; + +PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + const std::string& html_data) + : PluginPlaceholderBase(render_frame, frame, params, html_data) { +} + +PluginPlaceholder::~PluginPlaceholder() { +} + +v8::Local<v8::Value> PluginPlaceholder::GetV8Handle(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, this).ToV8(); +} + +gin::ObjectTemplateBuilder PluginPlaceholder::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) + .SetMethod<void (plugins::PluginPlaceholder::*)()>( + "hide", &PluginPlaceholder::HideCallback); +} } // namespace plugins diff --git a/components/plugins/renderer/plugin_placeholder.h b/components/plugins/renderer/plugin_placeholder.h index 5d9caa1..63a1d08 100644 --- a/components/plugins/renderer/plugin_placeholder.h +++ b/components/plugins/renderer/plugin_placeholder.h @@ -8,30 +8,29 @@ #include "base/memory/weak_ptr.h" #include "components/plugins/renderer/webview_plugin.h" #include "content/public/renderer/render_frame_observer.h" +#include "gin/handle.h" #include "gin/wrappable.h" +#include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebPluginParams.h" namespace plugins { -class PluginPlaceholder : public content::RenderFrameObserver, - public WebViewPlugin::Delegate, - public gin::Wrappable<PluginPlaceholder> { +// This abstract class is the base class of all plugin placeholders. +class PluginPlaceholderBase : public content::RenderFrameObserver, + public WebViewPlugin::Delegate { public: - static gin::WrapperInfo kWrapperInfo; - - WebViewPlugin* plugin() { return plugin_; } - - protected: // |render_frame| and |frame| are weak pointers. If either one is going away, // our |plugin_| will be destroyed as well and will notify us. - PluginPlaceholder(content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - const std::string& html_data, - GURL placeholderDataUrl); + PluginPlaceholderBase(content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + const std::string& html_data); - ~PluginPlaceholder() override; + ~PluginPlaceholderBase() override; + + WebViewPlugin* plugin() { return plugin_; } + protected: blink::WebLocalFrame* GetFrame(); const blink::WebPluginParams& GetPluginParams() const; @@ -41,6 +40,14 @@ class PluginPlaceholder : public content::RenderFrameObserver, v8::Local<v8::Object> GetV8ScriptableObject( v8::Isolate* isolate) const override; + protected: + // Hide this placeholder. + void HidePlugin(); + bool hidden() { return hidden_; } + + // JavaScript callbacks: + void HideCallback(); + private: // RenderFrameObserver methods: void OnDestruct() override; @@ -49,7 +56,30 @@ class PluginPlaceholder : public content::RenderFrameObserver, blink::WebPluginParams plugin_params_; WebViewPlugin* plugin_; - DISALLOW_COPY_AND_ASSIGN(PluginPlaceholder); + bool hidden_; + + DISALLOW_COPY_AND_ASSIGN(PluginPlaceholderBase); +}; + +// A basic placeholder that supports only hiding. +class PluginPlaceholder final : public PluginPlaceholderBase, + public gin::Wrappable<PluginPlaceholder> { + public: + static gin::WrapperInfo kWrapperInfo; + + PluginPlaceholder(content::RenderFrame* render_frame, + blink::WebLocalFrame* frame, + const blink::WebPluginParams& params, + const std::string& html_data); + ~PluginPlaceholder() override; + + private: + // WebViewPlugin::Delegate methods: + v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) final; + + // gin::Wrappable method: + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; }; } // namespace plugins diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc index 43cd43e..0779566 100644 --- a/components/plugins/renderer/webview_plugin.cc +++ b/components/plugins/renderer/webview_plugin.cc @@ -9,6 +9,7 @@ #include "base/numerics/safe_conversions.h" #include "content/public/common/web_preferences.h" #include "content/public/renderer/render_view.h" +#include "gin/converter.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/platform/WebURL.h" @@ -61,6 +62,7 @@ WebViewPlugin* WebViewPlugin::Create(WebViewPlugin::Delegate* delegate, const WebPreferences& preferences, const std::string& html_data, const GURL& url) { + DCHECK(url.is_valid()) << "Blink requires the WebView to have a valid URL."; WebViewPlugin* plugin = new WebViewPlugin(delegate, preferences); plugin->web_view()->mainFrame()->loadHTMLString(html_data, url); return plugin; @@ -264,8 +266,19 @@ void WebViewPlugin::scheduleAnimation() { } void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame) { - if (delegate_) - delegate_->BindWebFrame(frame); + if (!delegate_) + return; + + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = frame->mainWorldScriptContext(); + DCHECK(!context.IsEmpty()); + + v8::Context::Scope context_scope(context); + v8::Local<v8::Object> global = context->Global(); + + global->Set(gin::StringToV8(isolate, "plugin"), + delegate_->GetV8Handle(isolate)); } void WebViewPlugin::didReceiveResponse(WebLocalFrame* frame, diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h index 3286fae..fdb9777 100644 --- a/components/plugins/renderer/webview_plugin.h +++ b/components/plugins/renderer/webview_plugin.h @@ -13,6 +13,7 @@ #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/web/WebFrameClient.h" +#include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebPlugin.h" #include "third_party/WebKit/public/web/WebViewClient.h" @@ -42,10 +43,8 @@ class WebViewPlugin : public blink::WebPlugin, public: class Delegate { public: - // Bind |frame| to a Javascript object, enabling the delegate to receive - // callback methods from Javascript inside the WebFrame. - // This method is called from WebFrameClient::didClearWindowObject. - virtual void BindWebFrame(blink::WebFrame* frame) = 0; + // Called to get the V8 handle used to bind the lifetime to the frame. + virtual v8::Local<v8::Value> GetV8Handle(v8::Isolate*) = 0; // Called upon a context menu event. virtual void ShowContextMenu(const blink::WebMouseEvent&) = 0; |