diff options
Diffstat (limited to 'chromium/chrome/renderer/plugins')
15 files changed, 1407 insertions, 0 deletions
diff --git a/chromium/chrome/renderer/plugins/DEPS b/chromium/chrome/renderer/plugins/DEPS new file mode 100644 index 00000000000..39298501524 --- /dev/null +++ b/chromium/chrome/renderer/plugins/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+gin", + "+third_party/widevine", +] diff --git a/chromium/chrome/renderer/plugins/OWNERS b/chromium/chrome/renderer/plugins/OWNERS new file mode 100644 index 00000000000..f8cf45de415 --- /dev/null +++ b/chromium/chrome/renderer/plugins/OWNERS @@ -0,0 +1,2 @@ +tommycli@chromium.org +# COMPONENT: Internals>Plugins diff --git a/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.cc b/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.cc new file mode 100644 index 00000000000..205c7398f82 --- /dev/null +++ b/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.cc @@ -0,0 +1,399 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/plugins/chrome_plugin_placeholder.h" + +#include <memory> +#include <utility> + +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/buildflags.h" +#include "chrome/common/chrome_features.h" +#include "chrome/common/prerender_messages.h" +#include "chrome/common/render_messages.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/grit/renderer_resources.h" +#include "chrome/renderer/chrome_content_renderer_client.h" +#include "chrome/renderer/content_settings_observer.h" +#include "chrome/renderer/custom_menu_commands.h" +#include "chrome/renderer/plugins/plugin_preroller.h" +#include "chrome/renderer/plugins/plugin_uma.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/context_menu_params.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_thread.h" +#include "gin/object_template_builder.h" +#include "ipc/ipc_sync_channel.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" +#include "third_party/blink/public/common/page/page_zoom.h" +#include "third_party/blink/public/platform/url_conversion.h" +#include "third_party/blink/public/platform/web_input_event.h" +#include "third_party/blink/public/platform/web_mouse_event.h" +#include "third_party/blink/public/web/web_document.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 "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/webui/jstemplate_builder.h" +#include "ui/gfx/geometry/size.h" +#include "url/origin.h" +#include "url/url_util.h" + +using base::UserMetricsAction; +using content::RenderThread; +using content::RenderView; + +namespace { +const ChromePluginPlaceholder* g_last_active_menu = nullptr; +} // namespace + +gin::WrapperInfo ChromePluginPlaceholder::kWrapperInfo = { + gin::kEmbedderNativeGin}; + +ChromePluginPlaceholder::ChromePluginPlaceholder( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const std::string& html_data, + const base::string16& title) + : plugins::LoadablePluginPlaceholder(render_frame, params, html_data), + status_(chrome::mojom::PluginStatus::kAllowed), + title_(title), + context_menu_request_id_(0) { + RenderThread::Get()->AddObserver(this); +} + +ChromePluginPlaceholder::~ChromePluginPlaceholder() { + RenderThread::Get()->RemoveObserver(this); + if (context_menu_request_id_ && render_frame()) + render_frame()->CancelContextMenu(context_menu_request_id_); +} + +mojo::PendingRemote<chrome::mojom::PluginRenderer> +ChromePluginPlaceholder::BindPluginRenderer() { + return plugin_renderer_receiver_.BindNewPipeAndPassRemote(); +} + +// TODO(bauerb): Move this method to NonLoadablePluginPlaceholder? +// static +ChromePluginPlaceholder* ChromePluginPlaceholder::CreateLoadableMissingPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params) { + const base::StringPiece template_html( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BLOCKED_PLUGIN_HTML)); + + base::DictionaryValue values; + values.SetString("name", ""); + values.SetString("message", + l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED)); + + std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); + + // Will destroy itself when its WebViewPlugin is going away. + return new ChromePluginPlaceholder(render_frame, params, html_data, + params.mime_type.Utf16()); +} + +// static +ChromePluginPlaceholder* ChromePluginPlaceholder::CreateBlockedPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const content::WebPluginInfo& info, + const std::string& identifier, + const base::string16& name, + int template_id, + const base::string16& message, + const PowerSaverInfo& power_saver_info) { + base::DictionaryValue values; + values.SetString("message", message); + values.SetString("name", name); + values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE)); + values.SetString( + "pluginType", + render_frame->IsMainFrame() && + render_frame->GetWebFrame()->GetDocument().IsPluginDocument() + ? "document" + : "embedded"); + + if (!power_saver_info.poster_attribute.empty()) { + values.SetString("poster", power_saver_info.poster_attribute); + values.SetString("baseurl", power_saver_info.base_url.spec()); + + if (!power_saver_info.custom_poster_size.IsEmpty()) { + float zoom_factor = blink::PageZoomLevelToZoomFactor( + render_frame->GetWebFrame()->View()->ZoomLevel()); + int width = + roundf(power_saver_info.custom_poster_size.width() / zoom_factor); + int height = + roundf(power_saver_info.custom_poster_size.height() / zoom_factor); + values.SetString("visibleWidth", base::NumberToString(width) + "px"); + values.SetString("visibleHeight", base::NumberToString(height) + "px"); + } else { + // Need to populate these to please $i18n{...} replacement mechanism. + // 'undefined' is used on purpose as an invalid value for width and + // height, which is ignored by CSS. + values.SetString("visibleWidth", "undefined"); + values.SetString("visibleHeight", "undefined"); + } + } + + const base::StringPiece template_html( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(template_id)); + + DCHECK(!template_html.empty()) << "unable to load template. ID: " + << template_id; + std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); + + // |blocked_plugin| will destroy itself when its WebViewPlugin is going away. + ChromePluginPlaceholder* blocked_plugin = + new ChromePluginPlaceholder(render_frame, params, html_data, name); + + if (!power_saver_info.poster_attribute.empty()) + blocked_plugin->BlockForPowerSaverPoster(); + blocked_plugin->SetPluginInfo(info); + blocked_plugin->SetIdentifier(identifier); + + blocked_plugin->set_power_saver_enabled(power_saver_info.power_saver_enabled); + blocked_plugin->set_blocked_for_background_tab( + power_saver_info.blocked_for_background_tab); + + return blocked_plugin; +} + +void ChromePluginPlaceholder::SetStatus(chrome::mojom::PluginStatus status) { + status_ = status; +} + +bool ChromePluginPlaceholder::OnMessageReceived(const IPC::Message& message) { + // We don't swallow these messages because multiple blocked plugins and other + // objects have an interest in them. + IPC_BEGIN_MESSAGE_MAP(ChromePluginPlaceholder, message) + IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetPrerenderMode) + IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins) + IPC_END_MESSAGE_MAP() + + return false; +} + +void ChromePluginPlaceholder::ShowPermissionBubbleCallback() { + mojo::AssociatedRemote<chrome::mojom::PluginHost> plugin_host; + render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( + plugin_host.BindNewEndpointAndPassReceiver()); + plugin_host->ShowFlashPermissionBubble(); +} + +void ChromePluginPlaceholder::FinishedDownloading() { + SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_UPDATING, plugin_name_)); +} + +void ChromePluginPlaceholder::UpdateDownloading() { + SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, plugin_name_)); +} + +void ChromePluginPlaceholder::UpdateSuccess() { + PluginListChanged(); +} + +void ChromePluginPlaceholder::UpdateFailure() { + SetMessage(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT, + plugin_name_)); +} + +void ChromePluginPlaceholder::OnSetPrerenderMode( + prerender::PrerenderMode mode, + const std::string& histogram_prefix) { + OnSetIsPrerendering(mode != prerender::NO_PRERENDER); +} + +void ChromePluginPlaceholder::PluginListChanged() { + if (!render_frame() || !plugin()) + return; + + chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New(); + std::string mime_type(GetPluginParams().mime_type.Utf8()); + + ChromeContentRendererClient::GetPluginInfoHost()->GetPluginInfo( + routing_id(), GURL(GetPluginParams().url), + render_frame()->GetWebFrame()->Top()->GetSecurityOrigin(), mime_type, + &plugin_info); + if (plugin_info->status == status_) + return; + blink::WebPlugin* new_plugin = ChromeContentRendererClient::CreatePlugin( + render_frame(), GetPluginParams(), *plugin_info); + ReplacePlugin(new_plugin); + if (!new_plugin) { + PluginUMAReporter::GetInstance()->ReportPluginMissing( + GetPluginParams().mime_type.Utf8(), GURL(GetPluginParams().url)); + } +} + +void ChromePluginPlaceholder::OnMenuAction(int request_id, unsigned action) { + DCHECK_EQ(context_menu_request_id_, request_id); + if (g_last_active_menu != this) + return; + switch (action) { + case MENU_COMMAND_PLUGIN_RUN: { + RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu")); + MarkPluginEssential( + content::PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK); + LoadPlugin(); + break; + } + case MENU_COMMAND_PLUGIN_HIDE: { + RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Menu")); + HidePlugin(); + break; + } + case MENU_COMMAND_ENABLE_FLASH: { + ShowPermissionBubbleCallback(); + break; + } + default: + NOTREACHED(); + } +} + +void ChromePluginPlaceholder::OnMenuClosed(int request_id) { + DCHECK_EQ(context_menu_request_id_, request_id); + context_menu_request_id_ = 0; +} + +v8::Local<v8::Value> ChromePluginPlaceholder::GetV8Handle( + v8::Isolate* isolate) { + return gin::CreateHandle(isolate, this).ToV8(); +} + +void ChromePluginPlaceholder::ShowContextMenu( + const blink::WebMouseEvent& event) { + if (context_menu_request_id_) + return; // Don't allow nested context menu requests. + if (!render_frame()) + return; + + content::ContextMenuParams params; + + if (!title_.empty()) { + content::MenuItem name_item; + name_item.label = title_; + params.custom_items.push_back(name_item); + + content::MenuItem separator_item; + separator_item.type = content::MenuItem::SEPARATOR; + params.custom_items.push_back(separator_item); + } + + bool flash_hidden = + status_ == chrome::mojom::PluginStatus::kFlashHiddenPreferHtml; + if (!GetPluginInfo().path.value().empty() && !flash_hidden) { + content::MenuItem run_item; + run_item.action = MENU_COMMAND_PLUGIN_RUN; + // Disable this menu item if the plugin is blocked by policy. + run_item.enabled = LoadingAllowed(); + run_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_RUN); + params.custom_items.push_back(run_item); + } + + if (flash_hidden) { + content::MenuItem enable_flash_item; + enable_flash_item.action = MENU_COMMAND_ENABLE_FLASH; + enable_flash_item.enabled = true; + enable_flash_item.label = + l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_ENABLE_FLASH); + params.custom_items.push_back(enable_flash_item); + } + + content::MenuItem hide_item; + hide_item.action = MENU_COMMAND_PLUGIN_HIDE; + bool is_main_frame_plugin_document = + render_frame()->IsMainFrame() && + render_frame()->GetWebFrame()->GetDocument().IsPluginDocument(); + hide_item.enabled = !is_main_frame_plugin_document; + hide_item.label = l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLUGIN_HIDE); + params.custom_items.push_back(hide_item); + + blink::WebPoint point(event.PositionInWidget().x, event.PositionInWidget().y); + if (plugin() && plugin()->Container()) + point = plugin()->Container()->LocalToRootFramePoint(point); + + params.x = point.x; + params.y = point.y; + + context_menu_request_id_ = render_frame()->ShowContextMenu(this, params); + g_last_active_menu = this; +} + +blink::WebPlugin* ChromePluginPlaceholder::CreatePlugin() { + std::unique_ptr<content::PluginInstanceThrottler> throttler; + // If the plugin has already been marked essential in its placeholder form, + // we shouldn't create a new throttler and start the process all over again. + if (power_saver_enabled()) { + throttler = content::PluginInstanceThrottler::Create( + heuristic_run_before_ ? content::RenderFrame::DONT_RECORD_DECISION + : content::RenderFrame::RECORD_DECISION); + // PluginPreroller manages its own lifetime. + new PluginPreroller(render_frame(), GetPluginParams(), GetPluginInfo(), + GetIdentifier(), title_, + l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, title_), + throttler.get()); + } + return render_frame()->CreatePlugin(GetPluginInfo(), GetPluginParams(), + std::move(throttler)); +} + +void ChromePluginPlaceholder::OnBlockedContent( + content::RenderFrame::PeripheralContentStatus status, + bool is_same_origin) { + DCHECK(render_frame()); + + if (status == + content::RenderFrame::PeripheralContentStatus::CONTENT_STATUS_TINY) { + ContentSettingsObserver::Get(render_frame()) + ->DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS, title_); + } + + std::string message = base::StringPrintf( + is_same_origin ? "Same-origin plugin content from %s must have a visible " + "size larger than 6 x 6 pixels, or it will be blocked. " + "Invisible content is always blocked." + : "Cross-origin plugin content from %s must have a " + "visible size larger than 400 x 300 pixels, or it will " + "be blocked. Invisible content is always blocked.", + GetPluginParams().url.GetString().Utf8().c_str()); + render_frame()->AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kInfo, + message); +} + +gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + gin::ObjectTemplateBuilder builder = + gin::Wrappable<ChromePluginPlaceholder>::GetObjectTemplateBuilder(isolate) + .SetMethod<void (ChromePluginPlaceholder::*)()>( + "hide", &ChromePluginPlaceholder::HideCallback) + .SetMethod<void (ChromePluginPlaceholder::*)()>( + "load", &ChromePluginPlaceholder::LoadCallback) + .SetMethod<void (ChromePluginPlaceholder::*)()>( + "didFinishLoading", + &ChromePluginPlaceholder::DidFinishLoadingCallback) + .SetMethod("showPermissionBubble", + &ChromePluginPlaceholder::ShowPermissionBubbleCallback); + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnablePluginPlaceholderTesting)) { + builder.SetMethod<void (ChromePluginPlaceholder::*)()>( + "notifyPlaceholderReadyForTesting", + &ChromePluginPlaceholder::NotifyPlaceholderReadyForTestingCallback); + } + + return builder; +} diff --git a/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.h b/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.h new file mode 100644 index 00000000000..738a37a2679 --- /dev/null +++ b/chromium/chrome/renderer/plugins/chrome_plugin_placeholder.h @@ -0,0 +1,105 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_CHROME_PLUGIN_PLACEHOLDER_H_ +#define CHROME_RENDERER_PLUGINS_CHROME_PLUGIN_PLACEHOLDER_H_ + +#include <stdint.h> +#include <string> + +#include "base/macros.h" +#include "chrome/common/buildflags.h" +#include "chrome/common/plugin.mojom.h" +#include "chrome/common/prerender_types.h" +#include "chrome/renderer/plugins/power_saver_info.h" +#include "components/plugins/renderer/loadable_plugin_placeholder.h" +#include "content/public/renderer/context_menu_client.h" +#include "content/public/renderer/render_thread_observer.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" + +class ChromePluginPlaceholder final + : public plugins::LoadablePluginPlaceholder, + public content::RenderThreadObserver, + public content::ContextMenuClient, + public chrome::mojom::PluginRenderer, + public gin::Wrappable<ChromePluginPlaceholder> { + public: + static gin::WrapperInfo kWrapperInfo; + + static ChromePluginPlaceholder* CreateBlockedPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const content::WebPluginInfo& info, + const std::string& identifier, + const base::string16& name, + int resource_id, + const base::string16& message, + const PowerSaverInfo& power_saver_info); + + // Creates a new WebViewPlugin with a MissingPlugin as a delegate. + static ChromePluginPlaceholder* CreateLoadableMissingPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params); + + void SetStatus(chrome::mojom::PluginStatus status); + + mojo::PendingRemote<chrome::mojom::PluginRenderer> BindPluginRenderer(); + + private: + ChromePluginPlaceholder(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const std::string& html_data, + const base::string16& title); + ~ChromePluginPlaceholder() override; + + // content::LoadablePluginPlaceholder overrides. + blink::WebPlugin* CreatePlugin() override; + void OnBlockedContent(content::RenderFrame::PeripheralContentStatus status, + bool is_same_origin) override; + + // gin::Wrappable (via PluginPlaceholder) method + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) final; + + // content::RenderViewObserver (via PluginPlaceholder) override: + bool OnMessageReceived(const IPC::Message& message) override; + + // WebViewPlugin::Delegate (via PluginPlaceholder) methods: + v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) override; + void ShowContextMenu(const blink::WebMouseEvent&) override; + + // content::RenderThreadObserver methods: + void PluginListChanged() override; + + // content::ContextMenuClient methods: + void OnMenuAction(int request_id, unsigned action) override; + void OnMenuClosed(int request_id) override; + + // Show the Plugins permission bubble. + void ShowPermissionBubbleCallback(); + + // chrome::mojom::PluginRenderer methods. + void FinishedDownloading() override; + void UpdateDownloading() override; + void UpdateSuccess() override; + void UpdateFailure() override; + + // IPC message handlers: + void OnSetPrerenderMode(prerender::PrerenderMode mode, + const std::string& histogram_prefix); + + chrome::mojom::PluginStatus status_; + + base::string16 title_; + + int context_menu_request_id_; // Nonzero when request pending. + base::string16 plugin_name_; + + mojo::Receiver<chrome::mojom::PluginRenderer> plugin_renderer_receiver_{this}; + + DISALLOW_COPY_AND_ASSIGN(ChromePluginPlaceholder); +}; + +#endif // CHROME_RENDERER_PLUGINS_CHROME_PLUGIN_PLACEHOLDER_H_ diff --git a/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc b/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc new file mode 100644 index 00000000000..d4e3c3b13f8 --- /dev/null +++ b/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc @@ -0,0 +1,64 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/plugins/non_loadable_plugin_placeholder.h" + +#include "base/files/file_path.h" +#include "base/values.h" +#include "chrome/common/plugin.mojom.h" +#include "chrome/grit/renderer_resources.h" +#include "components/plugins/renderer/plugin_placeholder.h" +#include "components/strings/grit/components_strings.h" +#include "content/public/renderer/render_frame.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/public/strings/grit/blink_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/webui/jstemplate_builder.h" + +// static +plugins::PluginPlaceholder* +NonLoadablePluginPlaceholder::CreateNotSupportedPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params) { + const base::StringPiece template_html( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BLOCKED_PLUGIN_HTML)); + + base::DictionaryValue values; + values.SetString("name", ""); + values.SetString("message", + l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED)); + + std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); + + // PluginPlaceholder will destroy itself when its WebViewPlugin is going away. + return new plugins::PluginPlaceholder(render_frame, params, html_data); +} + +// static +plugins::PluginPlaceholder* NonLoadablePluginPlaceholder::CreateErrorPlugin( + content::RenderFrame* render_frame, + const base::FilePath& file_path) { + base::DictionaryValue values; + values.SetString("name", ""); + values.SetString("message", + l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR)); + + const base::StringPiece template_html( + ui::ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BLOCKED_PLUGIN_HTML)); + std::string html_data = webui::GetI18nTemplateHtml(template_html, &values); + + blink::WebPluginParams params; + // PluginPlaceholder will destroy itself when its WebViewPlugin is going away. + plugins::PluginPlaceholder* plugin = + new plugins::PluginPlaceholder(render_frame, params, html_data); + + mojo::AssociatedRemote<chrome::mojom::PluginHost> plugin_host; + render_frame->GetRemoteAssociatedInterfaces()->GetInterface(&plugin_host); + plugin_host->CouldNotLoadPlugin(file_path); + + return plugin; +} diff --git a/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.h b/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.h new file mode 100644 index 00000000000..1b2c6d13dee --- /dev/null +++ b/chromium/chrome/renderer/plugins/non_loadable_plugin_placeholder.h @@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_ +#define CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_ + +#include "base/macros.h" + +namespace base { +class FilePath; +} + +namespace blink { +struct WebPluginParams; +} + +namespace content { +class RenderFrame; +} + +namespace plugins { +class PluginPlaceholder; +} + +class NonLoadablePluginPlaceholder { + public: + // Creates a non-loadable plugin placeholder for platforms without plugins. + static plugins::PluginPlaceholder* CreateNotSupportedPlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params); + + static plugins::PluginPlaceholder* CreateErrorPlugin( + content::RenderFrame* render_frame, + const base::FilePath& file_path); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(NonLoadablePluginPlaceholder); +}; + +#endif // CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_ diff --git a/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.cc b/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.cc new file mode 100644 index 00000000000..1a506d03253 --- /dev/null +++ b/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.cc @@ -0,0 +1,56 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/plugins/pdf_plugin_placeholder.h" + +#include "base/command_line.h" +#include "chrome/common/pdf_util.h" +#include "chrome/common/render_messages.h" +#include "content/public/common/content_switches.h" +#include "content/public/renderer/render_thread.h" +#include "gin/object_template_builder.h" + +gin::WrapperInfo PDFPluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; + +// static +PDFPluginPlaceholder* PDFPluginPlaceholder::CreatePDFPlaceholder( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params) { + std::string html_data = GetPDFPlaceholderHTML(params.url); + return new PDFPluginPlaceholder(render_frame, params, html_data); +} + +PDFPluginPlaceholder::PDFPluginPlaceholder(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const std::string& html_data) + : plugins::PluginPlaceholderBase(render_frame, params, html_data) {} + +PDFPluginPlaceholder::~PDFPluginPlaceholder() {} + +v8::Local<v8::Value> PDFPluginPlaceholder::GetV8Handle(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, this).ToV8(); +} + +gin::ObjectTemplateBuilder PDFPluginPlaceholder::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + gin::ObjectTemplateBuilder builder = + gin::Wrappable<PDFPluginPlaceholder>::GetObjectTemplateBuilder(isolate) + .SetMethod<void (PDFPluginPlaceholder::*)()>( + "openPDF", &PDFPluginPlaceholder::OpenPDFCallback); + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnablePluginPlaceholderTesting)) { + builder.SetMethod<void (PDFPluginPlaceholder::*)()>( + "notifyPlaceholderReadyForTesting", + &PDFPluginPlaceholder::NotifyPlaceholderReadyForTestingCallback); + } + + return builder; +} + +void PDFPluginPlaceholder::OpenPDFCallback() { + ReportPDFLoadStatus(PDFLoadStatus::kViewPdfClickedInPdfPluginPlaceholder); + content::RenderThread::Get()->Send( + new ChromeViewHostMsg_OpenPDF(routing_id(), GetPluginParams().url)); +} diff --git a/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.h b/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.h new file mode 100644 index 00000000000..987f1f9edca --- /dev/null +++ b/chromium/chrome/renderer/plugins/pdf_plugin_placeholder.h @@ -0,0 +1,40 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_PDF_PLUGIN_PLACEHOLDER_H_ +#define CHROME_RENDERER_PLUGINS_PDF_PLUGIN_PLACEHOLDER_H_ + +#include "components/plugins/renderer/plugin_placeholder.h" + +// Placeholder that allows users to click to download a PDF for when +// plugins are disabled and the PDF fails to load. +// TODO(amberwon): Flesh out the class more to download an embedded PDF when the +// PDF plugin is disabled or unavailable. +class PDFPluginPlaceholder : public plugins::PluginPlaceholderBase, + public gin::Wrappable<PDFPluginPlaceholder> { + public: + static gin::WrapperInfo kWrapperInfo; + + // Returned placeholder is owned by the associated plugin, which can be + // retrieved with PluginPlaceholderBase::plugin(). + static PDFPluginPlaceholder* CreatePDFPlaceholder( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params); + + private: + PDFPluginPlaceholder(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const std::string& html_data); + ~PDFPluginPlaceholder() final; + + // WebViewPlugin::Delegate methods: + v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) final; + + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) final; + + void OpenPDFCallback(); +}; + +#endif // CHROME_RENDERER_PLUGINS_PDF_PLUGIN_PLACEHOLDER_H_ diff --git a/chromium/chrome/renderer/plugins/plugin_preroller.cc b/chromium/chrome/renderer/plugins/plugin_preroller.cc new file mode 100644 index 00000000000..d6c3da86edc --- /dev/null +++ b/chromium/chrome/renderer/plugins/plugin_preroller.cc @@ -0,0 +1,92 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/plugins/plugin_preroller.h" + +#include "base/base64.h" +#include "chrome/grit/renderer_resources.h" +#include "chrome/renderer/plugins/chrome_plugin_placeholder.h" +#include "chrome/renderer/plugins/power_saver_info.h" +#include "third_party/blink/public/platform/web_rect.h" +#include "third_party/blink/public/web/web_element.h" +#include "third_party/blink/public/web/web_plugin.h" +#include "third_party/blink/public/web/web_plugin_container.h" +#include "ui/gfx/codec/png_codec.h" + +PluginPreroller::PluginPreroller(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const content::WebPluginInfo& info, + const std::string& identifier, + const base::string16& name, + const base::string16& message, + content::PluginInstanceThrottler* throttler) + : RenderFrameObserver(render_frame), + params_(params), + info_(info), + identifier_(identifier), + name_(name), + message_(message), + throttler_(throttler) { + DCHECK(throttler); + throttler_->AddObserver(this); +} + +PluginPreroller::~PluginPreroller() { + if (throttler_) + throttler_->RemoveObserver(this); +} + +void PluginPreroller::OnKeyframeExtracted(const SkBitmap* bitmap) { + std::vector<unsigned char> png_data; + if (!gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data)) { + DLOG(ERROR) << "Provided keyframe could not be encoded as PNG."; + return; + } + + base::StringPiece png_as_string(reinterpret_cast<char*>(&png_data[0]), + png_data.size()); + + std::string data_url_header = "data:image/png;base64,"; + std::string data_url_body; + base::Base64Encode(png_as_string, &data_url_body); + keyframe_data_url_ = GURL(data_url_header + data_url_body); +} + +void PluginPreroller::OnThrottleStateChange() { + if (!throttler_->IsThrottled()) + return; + + PowerSaverInfo power_saver_info; + power_saver_info.power_saver_enabled = true; + power_saver_info.poster_attribute = keyframe_data_url_.spec(); + power_saver_info.custom_poster_size = throttler_->GetSize(); + + ChromePluginPlaceholder* placeholder = + ChromePluginPlaceholder::CreateBlockedPlugin( + render_frame(), params_, info_, identifier_, name_, + IDR_PLUGIN_POSTER_HTML, message_, power_saver_info); + placeholder->SetPremadePlugin(throttler_); + placeholder->AllowLoading(); + + blink::WebPluginContainer* container = + throttler_->GetWebPlugin()->Container(); + container->SetPlugin(placeholder->plugin()); + + bool success = placeholder->plugin()->Initialize(container); + DCHECK(success); + + container->Invalidate(); + container->ReportGeometry(); + + delete this; +} + +void PluginPreroller::OnThrottlerDestroyed() { + throttler_ = nullptr; + delete this; +} + +void PluginPreroller::OnDestruct() { + delete this; +} diff --git a/chromium/chrome/renderer/plugins/plugin_preroller.h b/chromium/chrome/renderer/plugins/plugin_preroller.h new file mode 100644 index 00000000000..0f812302711 --- /dev/null +++ b/chromium/chrome/renderer/plugins/plugin_preroller.h @@ -0,0 +1,57 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_PLUGIN_PREROLLER_H_ +#define CHROME_RENDERER_PLUGINS_PLUGIN_PREROLLER_H_ + +#include "base/macros.h" +#include "content/public/common/webplugininfo.h" +#include "content/public/renderer/plugin_instance_throttler.h" +#include "content/public/renderer/render_frame_observer.h" +#include "third_party/blink/public/web/web_plugin_params.h" +#include "url/gurl.h" + +class SkBitmap; + +// This class manages a plugin briefly for the purposes of keyframe extraction. +// Once a keyframe has been extracted, this class will replace the plugin with +// a ChromePluginPlaceholder. The actual plugin will continue to live in a +// throttled state. This class manages its own lifetime. +class PluginPreroller : public content::PluginInstanceThrottler::Observer, + public content::RenderFrameObserver { + public: + // Does not take ownership of |render_frame|, |plugin|, or |throttler|. + PluginPreroller(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, + const content::WebPluginInfo& info, + const std::string& identifier, + const base::string16& name, + const base::string16& message, + content::PluginInstanceThrottler* throttler); + + ~PluginPreroller() override; + + private: + // content::PluginInstanceThrottler::Observer methods: + void OnKeyframeExtracted(const SkBitmap* bitmap) override; + void OnThrottleStateChange() override; + void OnThrottlerDestroyed() override; + + // content::RenderFrameObserver implementation. + void OnDestruct() override; + + blink::WebPluginParams params_; + content::WebPluginInfo info_; + std::string identifier_; + base::string16 name_; + base::string16 message_; + + content::PluginInstanceThrottler* throttler_; + + GURL keyframe_data_url_; + + DISALLOW_COPY_AND_ASSIGN(PluginPreroller); +}; + +#endif // CHROME_RENDERER_PLUGINS_PLUGIN_PREROLLER_H_ diff --git a/chromium/chrome/renderer/plugins/plugin_uma.cc b/chromium/chrome/renderer/plugins/plugin_uma.cc new file mode 100644 index 00000000000..201e41e501c --- /dev/null +++ b/chromium/chrome/renderer/plugins/plugin_uma.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/plugins/plugin_uma.h" + +#include <algorithm> +#include <cstring> + +#include "base/metrics/histogram_macros.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "content/public/common/content_constants.h" + +namespace { + +// String we will use to convert mime type to plugin type. +const char kWindowsMediaPlayerType[] = "application/x-mplayer2"; +const char kSilverlightTypePrefix[] = "application/x-silverlight"; +const char kRealPlayerTypePrefix[] = "audio/x-pn-realaudio"; +const char kJavaTypeSubstring[] = "application/x-java-applet"; +const char kQuickTimeType[] = "video/quicktime"; + +// Arrays containing file extensions connected with specific plugins. +// Note: THE ARRAYS MUST BE SORTED BECAUSE BINARY SEARCH IS USED ON THEM! +const char* const kWindowsMediaPlayerExtensions[] = {".asx"}; + +const char* const kRealPlayerExtensions[] = {".ra", ".ram", ".rm", + ".rmm", ".rmp", ".rpm"}; + +const char* const kQuickTimeExtensions[] = {".moov", ".mov", ".qif", + ".qt", ".qti", ".qtif"}; + +const char* const kShockwaveFlashExtensions[] = {".spl", ".swf"}; + +} // namespace. + +class UMASenderImpl : public PluginUMAReporter::UMASender { + void SendPluginUMA(PluginUMAReporter::ReportType report_type, + PluginUMAReporter::PluginType plugin_type) override; +}; + +void UMASenderImpl::SendPluginUMA(PluginUMAReporter::ReportType report_type, + PluginUMAReporter::PluginType plugin_type) { + // UMA_HISTOGRAM_ENUMERATION requires constant histogram name. Use string + // constants explicitly instead of trying to use variables for names. + switch (report_type) { + case PluginUMAReporter::MISSING_PLUGIN: + UMA_HISTOGRAM_ENUMERATION("Plugin.MissingPlugins", + plugin_type, + PluginUMAReporter::PLUGIN_TYPE_MAX); + break; + case PluginUMAReporter::DISABLED_PLUGIN: + UMA_HISTOGRAM_ENUMERATION("Plugin.DisabledPlugins", + plugin_type, + PluginUMAReporter::PLUGIN_TYPE_MAX); + break; + default: + NOTREACHED(); + } +} + +// static. +PluginUMAReporter* PluginUMAReporter::GetInstance() { + return base::Singleton<PluginUMAReporter>::get(); +} + +void PluginUMAReporter::ReportPluginMissing(const std::string& plugin_mime_type, + const GURL& plugin_src) { + report_sender_->SendPluginUMA(MISSING_PLUGIN, + GetPluginType(plugin_mime_type, plugin_src)); +} + +void PluginUMAReporter::ReportPluginDisabled( + const std::string& plugin_mime_type, + const GURL& plugin_src) { + report_sender_->SendPluginUMA(DISABLED_PLUGIN, + GetPluginType(plugin_mime_type, plugin_src)); +} + +PluginUMAReporter::PluginUMAReporter() : report_sender_(new UMASenderImpl()) {} + +PluginUMAReporter::~PluginUMAReporter() {} + +// static. +bool PluginUMAReporter::CompareCStrings(const char* first, const char* second) { + return strcmp(first, second) < 0; +} + +bool PluginUMAReporter::CStringArrayContainsCString(const char* const* array, + size_t array_size, + const char* str) { + return std::binary_search(array, array + array_size, str, CompareCStrings); +} + +void PluginUMAReporter::ExtractFileExtension(const GURL& src, + std::string* extension) { + std::string extension_file_path(src.ExtractFileName()); + if (extension_file_path.empty()) + extension_file_path = src.host(); + + size_t last_dot = extension_file_path.find_last_of('.'); + if (last_dot != std::string::npos) { + *extension = extension_file_path.substr(last_dot); + } else { + extension->clear(); + } + + *extension = base::ToLowerASCII(*extension); +} + +PluginUMAReporter::PluginType PluginUMAReporter::GetPluginType( + const std::string& plugin_mime_type, + const GURL& plugin_src) { + // If we know plugin's mime type, we use it to determine plugin's type. Else, + // we try to determine plugin type using plugin source's extension. + if (!plugin_mime_type.empty()) + return MimeTypeToPluginType(base::ToLowerASCII(plugin_mime_type)); + + return SrcToPluginType(plugin_src); +} + +PluginUMAReporter::PluginType PluginUMAReporter::SrcToPluginType( + const GURL& src) { + std::string file_extension; + ExtractFileExtension(src, &file_extension); + if (CStringArrayContainsCString(kWindowsMediaPlayerExtensions, + base::size(kWindowsMediaPlayerExtensions), + file_extension.c_str())) { + return WINDOWS_MEDIA_PLAYER; + } + + if (CStringArrayContainsCString(kQuickTimeExtensions, + base::size(kQuickTimeExtensions), + file_extension.c_str())) { + return QUICKTIME; + } + + if (CStringArrayContainsCString(kRealPlayerExtensions, + base::size(kRealPlayerExtensions), + file_extension.c_str())) { + return REALPLAYER; + } + + if (CStringArrayContainsCString(kShockwaveFlashExtensions, + base::size(kShockwaveFlashExtensions), + file_extension.c_str())) { + return SHOCKWAVE_FLASH; + } + + return UNSUPPORTED_EXTENSION; +} + +PluginUMAReporter::PluginType PluginUMAReporter::MimeTypeToPluginType( + const std::string& mime_type) { + if (mime_type == kWindowsMediaPlayerType) + return WINDOWS_MEDIA_PLAYER; + + size_t prefix_length = strlen(kSilverlightTypePrefix); + if (strncmp(mime_type.c_str(), kSilverlightTypePrefix, prefix_length) == 0) + return SILVERLIGHT; + + prefix_length = strlen(kRealPlayerTypePrefix); + if (strncmp(mime_type.c_str(), kRealPlayerTypePrefix, prefix_length) == 0) + return REALPLAYER; + + if (strstr(mime_type.c_str(), kJavaTypeSubstring)) + return JAVA; + + if (mime_type == kQuickTimeType) + return QUICKTIME; + + if (mime_type == content::kBrowserPluginMimeType) + return BROWSER_PLUGIN; + + if (mime_type == content::kFlashPluginSwfMimeType || + mime_type == content::kFlashPluginSplMimeType) { + return SHOCKWAVE_FLASH; + } + + return UNSUPPORTED_MIMETYPE; +} diff --git a/chromium/chrome/renderer/plugins/plugin_uma.h b/chromium/chrome/renderer/plugins/plugin_uma.h new file mode 100644 index 00000000000..d21498ad194 --- /dev/null +++ b/chromium/chrome/renderer/plugins/plugin_uma.h @@ -0,0 +1,91 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_PLUGIN_UMA_H_ +#define CHROME_RENDERER_PLUGINS_PLUGIN_UMA_H_ + +#include <stddef.h> + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "url/gurl.h" + +// Used to send UMA data about missing plugins to UMA histogram server. Method +// ReportPluginMissing should be called whenever plugin that is not available or +// enabled is called. We try to determine plugin's type by requested mime type, +// or, if mime type is unknown, by plugin's src url. +class PluginUMAReporter { + public: + enum ReportType { + MISSING_PLUGIN, + DISABLED_PLUGIN, + }; + + // Make sure the enum list in tools/histogram/histograms.xml is updated with + // any change in this list. + enum PluginType { + WINDOWS_MEDIA_PLAYER = 0, + SILVERLIGHT = 1, + REALPLAYER = 2, + JAVA = 3, + QUICKTIME = 4, + OTHER = 5, // This is obsolete and replaced by UNSUPPORTED_* types. + UNSUPPORTED_MIMETYPE, + UNSUPPORTED_EXTENSION, + // NOTE: Add new unsupported types only immediately above this line. + BROWSER_PLUGIN = 10, + SHOCKWAVE_FLASH, + WIDEVINE_CDM = 12, // Obsolete March 2018 + // NOTE: Add new plugin types only immediately above this line. + PLUGIN_TYPE_MAX + }; + + // Sends UMA data, i.e. plugin's type. + class UMASender { + public: + virtual ~UMASender() {} + virtual void SendPluginUMA(ReportType report_type, + PluginType plugin_type) = 0; + }; + + // Returns singleton instance. + static PluginUMAReporter* GetInstance(); + + void ReportPluginMissing(const std::string& plugin_mime_type, + const GURL& plugin_src); + + void ReportPluginDisabled(const std::string& plugin_mime_type, + const GURL& plugin_src); + + private: + friend struct base::DefaultSingletonTraits<PluginUMAReporter>; + friend class PluginUMATest; + + PluginUMAReporter(); + ~PluginUMAReporter(); + + static bool CompareCStrings(const char* first, const char* second); + bool CStringArrayContainsCString(const char* const* array, + size_t array_size, + const char* str); + // Extracts file extension from url. + void ExtractFileExtension(const GURL& src, std::string* extension); + + PluginType GetPluginType(const std::string& plugin_mime_type, + const GURL& plugin_src); + + // Converts plugin's src to plugin type. + PluginType SrcToPluginType(const GURL& src); + // Converts plugin's mime type to plugin type. + PluginType MimeTypeToPluginType(const std::string& mime_type); + + std::unique_ptr<UMASender> report_sender_; + + DISALLOW_COPY_AND_ASSIGN(PluginUMAReporter); +}; + +#endif // CHROME_RENDERER_PLUGINS_PLUGIN_UMA_H_ diff --git a/chromium/chrome/renderer/plugins/plugin_uma_unittest.cc b/chromium/chrome/renderer/plugins/plugin_uma_unittest.cc new file mode 100644 index 00000000000..33882b5cd0f --- /dev/null +++ b/chromium/chrome/renderer/plugins/plugin_uma_unittest.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include "chrome/renderer/plugins/plugin_uma.h" +#include "media/media_buildflags.h" +#include "ppapi/buildflags/buildflags.h" + +class PluginUMATest : public testing::Test { + public: + static void ExpectPluginType( + PluginUMAReporter::PluginType expected_plugin_type, + const std::string& plugin_mime_type, + const GURL& plugin_src) { + EXPECT_EQ(expected_plugin_type, + PluginUMAReporter::GetInstance()->GetPluginType(plugin_mime_type, + plugin_src)); + } +}; + +TEST_F(PluginUMATest, WindowsMediaPlayer) { + ExpectPluginType(PluginUMAReporter::WINDOWS_MEDIA_PLAYER, + "application/x-mplayer2", + GURL("file://some_file.mov")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "application/x-mplayer2-some_sufix", + GURL("file://some_file.mov")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "some-prefix-application/x-mplayer2", + GURL("file://some_file.mov")); +} + +TEST_F(PluginUMATest, Silverlight) { + ExpectPluginType(PluginUMAReporter::SILVERLIGHT, + "application/x-silverlight", + GURL("aaaa")); + ExpectPluginType(PluginUMAReporter::SILVERLIGHT, + "application/x-silverlight-some-sufix", + GURL("aaaa")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "some-prefix-application/x-silverlight", + GURL("aaaa")); +} + +TEST_F(PluginUMATest, RealPlayer) { + ExpectPluginType( + PluginUMAReporter::REALPLAYER, "audio/x-pn-realaudio", GURL("some url")); + ExpectPluginType(PluginUMAReporter::REALPLAYER, + "audio/x-pn-realaudio-some-sufix", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "some-prefix-audio/x-pn-realaudio", + GURL("some url")); +} + +TEST_F(PluginUMATest, Java) { + ExpectPluginType( + PluginUMAReporter::JAVA, "application/x-java-applet", GURL("some url")); + ExpectPluginType(PluginUMAReporter::JAVA, + "application/x-java-applet-some-sufix", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::JAVA, + "some-prefix-application/x-java-applet-sufix", + GURL("some url")); +} + +TEST_F(PluginUMATest, QuickTime) { + ExpectPluginType( + PluginUMAReporter::QUICKTIME, "video/quicktime", GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "video/quicktime-sufix", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "prefix-video/quicktime", + GURL("some url")); +} + +TEST_F(PluginUMATest, BrowserPlugin) { + ExpectPluginType(PluginUMAReporter::BROWSER_PLUGIN, + "application/browser-plugin", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "application/browser-plugin-sufix", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "prefix-application/browser-plugin", + GURL("some url")); +} + +TEST_F(PluginUMATest, ShockwaveFlash) { + ExpectPluginType(PluginUMAReporter::SHOCKWAVE_FLASH, + "application/x-shockwave-flash", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::SHOCKWAVE_FLASH, + "application/futuresplash", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "application/x-futuresplash", + GURL("some url")); + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "application/shockwave-flash", + GURL("some url")); +} + +TEST_F(PluginUMATest, BySrcExtension) { + ExpectPluginType( + PluginUMAReporter::QUICKTIME, std::string(), GURL("file://file.mov")); + + // When plugin's mime type is given, we don't check extension. + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_MIMETYPE, + "unknown-plugin", + GURL("http://file.mov")); + + ExpectPluginType(PluginUMAReporter::WINDOWS_MEDIA_PLAYER, + std::string(), + GURL("file://file.asx")); + ExpectPluginType( + PluginUMAReporter::REALPLAYER, std::string(), GURL("file://file.rm")); + ExpectPluginType(PluginUMAReporter::QUICKTIME, + std::string(), + GURL("http://aaa/file.mov?x=aaaa&y=b#c")); + ExpectPluginType(PluginUMAReporter::QUICKTIME, + std::string(), + GURL("http://file.mov?x=aaaa&y=b#c")); + ExpectPluginType(PluginUMAReporter::SHOCKWAVE_FLASH, + std::string(), + GURL("http://file.swf?x=aaaa&y=b#c")); + ExpectPluginType(PluginUMAReporter::SHOCKWAVE_FLASH, + std::string(), + GURL("http://file.spl?x=aaaa&y=b#c")); + + ExpectPluginType(PluginUMAReporter::UNSUPPORTED_EXTENSION, + std::string(), + GURL("http://file.unknown_extension")); + ExpectPluginType( + PluginUMAReporter::UNSUPPORTED_EXTENSION, std::string(), GURL("http://")); + ExpectPluginType( + PluginUMAReporter::UNSUPPORTED_EXTENSION, std::string(), GURL("mov")); +} + +TEST_F(PluginUMATest, CaseSensitivity) { + ExpectPluginType( + PluginUMAReporter::QUICKTIME, "video/QUICKTIME", GURL("http://file.aaa")); + ExpectPluginType( + PluginUMAReporter::QUICKTIME, std::string(), GURL("http://file.MoV")); +} diff --git a/chromium/chrome/renderer/plugins/power_saver_info.cc b/chromium/chrome/renderer/plugins/power_saver_info.cc new file mode 100644 index 00000000000..799c8f2d10c --- /dev/null +++ b/chromium/chrome/renderer/plugins/power_saver_info.cc @@ -0,0 +1,75 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> + +#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/renderer/plugins/power_saver_info.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/webplugininfo.h" +#include "content/public/renderer/render_frame.h" +#include "third_party/blink/public/platform/web_security_origin.h" +#include "third_party/blink/public/web/web_local_frame.h" +#include "third_party/blink/public/web/web_plugin_params.h" +#include "url/origin.h" + +namespace { + +std::string GetPluginInstancePosterAttribute( + const blink::WebPluginParams& params) { + DCHECK_EQ(params.attribute_names.size(), params.attribute_values.size()); + + for (size_t i = 0; i < params.attribute_names.size(); ++i) { + if (params.attribute_names[i].Utf8() == "poster" && + !params.attribute_values[i].IsEmpty()) { + return params.attribute_values[i].Utf8(); + } + } + return std::string(); +} + +bool GetPluginPowerSaverEnabled(bool power_saver_setting_on, bool is_flash) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + std::string override_for_testing = command_line->GetSwitchValueASCII( + switches::kOverridePluginPowerSaverForTesting); + + // This feature has only been tested thoroughly with Flash thus far. It is + // also enabled for the Power Saver test plugin for browser tests. + if (override_for_testing == "always") + return true; + else if (override_for_testing == "never") + return false; + else + return power_saver_setting_on && is_flash; +} + +} // namespace + +PowerSaverInfo::PowerSaverInfo() + : power_saver_enabled(false), blocked_for_background_tab(false) {} + +PowerSaverInfo::PowerSaverInfo(const PowerSaverInfo& other) = default; + +PowerSaverInfo PowerSaverInfo::Get(content::RenderFrame* render_frame, + bool power_saver_setting_on, + const blink::WebPluginParams& params, + const content::WebPluginInfo& plugin_info, + const GURL& document_url) { + bool is_flash = + plugin_info.name == base::ASCIIToUTF16(content::kFlashPluginName); + + PowerSaverInfo info; + info.power_saver_enabled = + GetPluginPowerSaverEnabled(power_saver_setting_on, is_flash); + + if (info.power_saver_enabled) { + info.blocked_for_background_tab = render_frame->IsHidden(); + info.poster_attribute = GetPluginInstancePosterAttribute(params); + info.base_url = document_url; + } + + return info; +} diff --git a/chromium/chrome/renderer/plugins/power_saver_info.h b/chromium/chrome/renderer/plugins/power_saver_info.h new file mode 100644 index 00000000000..ec1c5defcb4 --- /dev/null +++ b/chromium/chrome/renderer/plugins/power_saver_info.h @@ -0,0 +1,51 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_PLUGINS_POWER_SAVER_INFO_H_ +#define CHROME_RENDERER_PLUGINS_POWER_SAVER_INFO_H_ + +#include <string> + +#include "ui/gfx/geometry/size.h" +#include "url/gurl.h" + +namespace blink { +struct WebPluginParams; +} + +namespace content { +class RenderFrame; +struct WebPluginInfo; +} + +// This contains information specifying the plugin's Power Saver behavior. +// The default constructor has Plugin Power Saver disabled. +struct PowerSaverInfo { + PowerSaverInfo(); + PowerSaverInfo(const PowerSaverInfo& other); + + // Determines the PowerSaverInfo using the peripheral content heuristic. + static PowerSaverInfo Get(content::RenderFrame* render_frame, + bool power_saver_setting_on, + const blink::WebPluginParams& params, + const content::WebPluginInfo& plugin_info, + const GURL& document_url); + + // Whether power saver should be enabled. + bool power_saver_enabled; + + // Whether the plugin should be deferred because it is in a background tab. + bool blocked_for_background_tab; + + // The poster image specified in image 'srcset' attribute format. + std::string poster_attribute; + + // Used to resolve relative paths in |poster_attribute|. + GURL base_url; + + // Specify this to provide partially obscured plugins a centered poster image. + gfx::Size custom_poster_size; +}; + +#endif // CHROME_RENDERER_PLUGINS_POWER_SAVER_INFO_H_ |