diff options
author | tommycli <tommycli@chromium.org> | 2015-05-05 12:40:49 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-05 19:41:15 +0000 |
commit | ee0a49b6fa5c285ec3069f858ee9ba839570eddb (patch) | |
tree | 9fc3ae8130d2fc6890f651f7cbde6603c43ef133 | |
parent | 6ec419de92d2a868d26de12b9795e5985b850113 (diff) | |
download | chromium_src-ee0a49b6fa5c285ec3069f858ee9ba839570eddb.zip chromium_src-ee0a49b6fa5c285ec3069f858ee9ba839570eddb.tar.gz chromium_src-ee0a49b6fa5c285ec3069f858ee9ba839570eddb.tar.bz2 |
Plugin Power Saver: Make PPS work well with prerendered pages.
This patch does two things:
1. Fixes PPS interaction with prerender. This is done by having ChromePluginPlaceholder create a PluginPreroller along with the throttler.
2. Adds a browsertest for the above process.
a. This required adding a IsThrottled method to PPB_Testing_Private.
b. This required modifying the PPS Test Plugin to paint some dummy 'interesting' frames.
BUG=471427
Review URL: https://codereview.chromium.org/1114623002
Cr-Commit-Position: refs/heads/master@{#328381}
22 files changed, 305 insertions, 106 deletions
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc index 21336ad..c1314b6 100644 --- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc +++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc @@ -40,22 +40,22 @@ class PluginPowerSaverBrowserTest : virtual public InProcessBrowserTest { bool IsPluginPeripheral(const char* element_id) { std::string script = base::StringPrintf( "var plugin = window.document.getElementById('%s');" - "function handleEvent() {" + "function handleEvent(event) {" " if (event.data.isPeripheral != undefined &&" - " event.data.source == 'getPeripheralStatusResponse') {" + " event.data.source === 'getPowerSaverStatusResponse') {" " window.domAutomationController.send(" " event.data.isPeripheral ? 'peripheral' : 'essential');" " plugin.removeEventListener('message', handleEvent);" " }" "}" - "if (plugin == undefined ||" + "if (plugin === undefined ||" " (plugin.nodeName != 'OBJECT' && plugin.nodeName != 'EMBED')) {" " window.domAutomationController.send('error');" - "} else if (plugin.postMessage == undefined) {" + "} else if (plugin.postMessage === undefined) {" " window.domAutomationController.send('peripheral');" "} else {" " plugin.addEventListener('message', handleEvent);" - " plugin.postMessage('getPeripheralStatus');" + " plugin.postMessage('getPowerSaverStatus');" "}", element_id); @@ -71,7 +71,7 @@ class PluginPowerSaverBrowserTest : virtual public InProcessBrowserTest { // status message during: // - Plugin creation, to handle a plugin freshly created from a poster. // - Peripheral status change. - // - In response to the explicit 'getPeripheralStatus' request, in case the + // - In response to the explicit 'getPowerSaverStatus' request, in case the // test has missed the above two events. void SimulateClickAndAwaitMarkedEssential(const char* element_id, const gfx::Point& point) { @@ -80,19 +80,19 @@ class PluginPowerSaverBrowserTest : virtual public InProcessBrowserTest { std::string script = base::StringPrintf( "var plugin = window.document.getElementById('%s');" - "function handleEvent() {" - " if (event.data.isPeripheral == false) {" + "function handleEvent(event) {" + " if (event.data.isPeripheral === false) {" " window.domAutomationController.send('essential');" " plugin.removeEventListener('message', handleEvent);" " }" "}" - "if (plugin == undefined ||" + "if (plugin === undefined ||" " (plugin.nodeName != 'OBJECT' && plugin.nodeName != 'EMBED')) {" " window.domAutomationController.send('error');" "} else {" " plugin.addEventListener('message', handleEvent);" " if (plugin.postMessage != undefined) {" - " plugin.postMessage('getPeripheralStatus');" + " plugin.postMessage('getPowerSaverStatus');" " }" "}", element_id); diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc index 9aca6168..3f98385 100644 --- a/chrome/browser/prerender/prerender_browsertest.cc +++ b/chrome/browser/prerender/prerender_browsertest.cc @@ -103,6 +103,7 @@ #include "net/url_request/url_request_filter.h" #include "net/url_request/url_request_interceptor.h" #include "net/url_request/url_request_job.h" +#include "ppapi/shared_impl/ppapi_switches.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" @@ -1108,7 +1109,9 @@ class PrerenderBrowserTest : virtual public InProcessBrowserTest { void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitchASCII(switches::kPrerenderMode, switches::kPrerenderModeSwitchValueEnabled); - ASSERT_TRUE(ppapi::RegisterTestPlugin(command_line)); + command_line->AppendSwitch(switches::kEnablePepperTesting); + + ASSERT_TRUE(ppapi::RegisterPowerSaverTestPlugin(command_line)); } void SetUpOnMainThread() override { @@ -1968,8 +1971,8 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderAlertAfterOnload) { // Checks that plugins are not loaded while a page is being preloaded, but // are loaded when the page is displayed. IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderDelayLoadPlugin) { - PrerenderTestURL("files/prerender/plugin_delay_load.html", FINAL_STATUS_USED, - 1); + PrerenderTestURL("files/prerender/prerender_plugin_delay_load.html", + FINAL_STATUS_USED, 1); NavigateToDestURL(); } @@ -1981,9 +1984,16 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderContentSettingDetect) { content_settings_map->SetDefaultContentSetting( CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_DETECT_IMPORTANT_CONTENT); - PrerenderTestURL("files/prerender/plugin_delay_load.html", FINAL_STATUS_USED, - 1); + PrerenderTestURL("files/prerender/prerender_plugin_power_saver.html", + FINAL_STATUS_USED, 1); + + DisableJavascriptCalls(); NavigateToDestURL(); + bool second_placeholder_present = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + GetActiveWebContents(), "AwaitPluginPrerollAndPlaceholder();", + &second_placeholder_present)); + EXPECT_TRUE(second_placeholder_present); } // For Content Setting BLOCK, checks that plugins are never loaded. @@ -1993,8 +2003,8 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderContentSettingBlock) { content_settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK); - PrerenderTestURL("files/prerender/plugin_never_load.html", FINAL_STATUS_USED, - 1); + PrerenderTestURL("files/prerender/prerender_plugin_never_load.html", + FINAL_STATUS_USED, 1); NavigateToDestURL(); } diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 22e914e..03f520d 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc @@ -858,16 +858,12 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin( bool is_prerendering = prerender::PrerenderHelper::IsPrerendering(render_frame); - // TODO(tommycli): Plugin Power Saver is disabled on prerendered pages. + // TODO(tommycli): Background tab plugin deferral is disabled. // This is because the placeholder does not feed back into // ChromeContentRendererClient::CreatePlugin. Because of this, it does // not handle the preroll to UI overlay placeholder flow correctly. - // - // Background tab plugin deferral is disabled for the same reason. - // // https://crbug.com/471427 bool power_saver_enabled = - !is_prerendering && status == ChromeViewHostMsg_GetPluginInfo_Status::kPlayImportantContent; diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.cc b/chrome/renderer/plugins/chrome_plugin_placeholder.cc index c532fdd..402bfb6 100644 --- a/chrome/renderer/plugins/chrome_plugin_placeholder.cc +++ b/chrome/renderer/plugins/chrome_plugin_placeholder.cc @@ -13,6 +13,7 @@ #include "chrome/grit/renderer_resources.h" #include "chrome/renderer/chrome_content_renderer_client.h" #include "chrome/renderer/custom_menu_commands.h" +#include "chrome/renderer/plugins/plugin_preroller.h" #include "chrome/renderer/plugins/plugin_uma.h" #include "components/content_settings/content/common/content_settings_messages.h" #include "content/app/strings/grit/content_strings.h" @@ -366,6 +367,24 @@ void ChromePluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) { #endif // OS_ANDROID } +blink::WebPlugin* ChromePluginPlaceholder::CreatePlugin() { + scoped_ptr<content::PluginInstanceThrottler> throttler; +#if defined(ENABLE_PLUGINS) + // 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(); + // PluginPreroller manages its own lifetime. + new PluginPreroller(render_frame(), GetFrame(), GetPluginParams(), + GetPluginInfo(), GetIdentifier(), title_, + l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, title_), + throttler.get()); + } +#endif + return render_frame()->CreatePlugin(GetFrame(), GetPluginInfo(), + GetPluginParams(), throttler.Pass()); +} + gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder( v8::Isolate* isolate) { return LoadablePluginPlaceholder::GetObjectTemplateBuilder(isolate).SetMethod( diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.h b/chrome/renderer/plugins/chrome_plugin_placeholder.h index bdcf02c..d5fb2f9 100644 --- a/chrome/renderer/plugins/chrome_plugin_placeholder.h +++ b/chrome/renderer/plugins/chrome_plugin_placeholder.h @@ -69,6 +69,9 @@ class ChromePluginPlaceholder : public plugins::LoadablePluginPlaceholder, const base::string16& title); ~ChromePluginPlaceholder() override; + // content::LoadablePluginPlaceholder method + blink::WebPlugin* CreatePlugin() override; + // gin::Wrappable (via PluginPlaceholder) method gin::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; diff --git a/chrome/test/data/prerender/prerender_iframe_plugin_delay_load.html b/chrome/test/data/prerender/prerender_iframe_plugin_delay_load.html index a13af56..dfa0254 100644 --- a/chrome/test/data/prerender/prerender_iframe_plugin_delay_load.html +++ b/chrome/test/data/prerender/prerender_iframe_plugin_delay_load.html @@ -20,6 +20,6 @@ function DidDisplayPass() { } </script> <body> -<iframe src="plugin_delay_load.html" id="plugin_iframe"></iframe> +<iframe src="prerender_plugin_delay_load.html" id="plugin_iframe"></iframe> </body> </html> diff --git a/chrome/test/data/prerender/plugin_delay_load.html b/chrome/test/data/prerender/prerender_plugin_delay_load.html index 4a84c73..4a84c73 100644 --- a/chrome/test/data/prerender/plugin_delay_load.html +++ b/chrome/test/data/prerender/prerender_plugin_delay_load.html diff --git a/chrome/test/data/prerender/plugin_never_load.html b/chrome/test/data/prerender/prerender_plugin_never_load.html index 84dc722..84dc722 100644 --- a/chrome/test/data/prerender/plugin_never_load.html +++ b/chrome/test/data/prerender/prerender_plugin_never_load.html diff --git a/chrome/test/data/prerender/prerender_plugin_power_saver.html b/chrome/test/data/prerender/prerender_plugin_power_saver.html new file mode 100644 index 0000000..18cb87e --- /dev/null +++ b/chrome/test/data/prerender/prerender_plugin_power_saver.html @@ -0,0 +1,54 @@ +<html> +<!-- +This test checks the interaction between prerendering and the Plugin Power Saver +feature. It expects: + - The plugin is not loaded during prerender. + - It is loaded (briefly) during the preroll of the plugin. + - It is replaced by the power saver placeholder after the preroll is over. + +This test relies on the Pepper plugin (but not the placeholder) implementing +the postMessage() function on the plugin object. +--> +<head> +<title>Prerender Plugin Delay Loading</title> + +<script> +// Make sure plugin was not loaded while prerendering. +function DidPrerenderPass() { + // |plugin| should be the blocked plugin placeholder, rather than the + // test plugin. + var plugin = window.document.getElementById('plugin'); + return plugin.postMessage === undefined; +} + +// Make sure the plugin briefly exists, then is replaced with a placeholder. +function AwaitPluginPrerollAndPlaceholder() { + var plugin = window.document.getElementById('plugin'); + function handleEvent(event) { + // We should eventually get a message indicating that the plugin has been + // throttled and replaced with a static placeholder. + if (event.data.isThrottled && event.data.isHiddenForPlaceholder) { + plugin.removeEventListener('message', handleEvent); + window.domAutomationController.send(true); + } + } + + plugin.addEventListener('message', handleEvent); + + // If postMessage is not defined, the plugin is still the initial placeholder. + // When the real plugin loads, we will still get the initial power saver + // status notifications. + if (plugin.postMessage !== undefined) { + plugin.postMessage('getPowerSaverStatus'); + } +} +</script> + +</head> +<body> + +<object id="plugin" type="application/x-ppapi-tests" height='100' width='100'> +</object> + +</body> +</html> diff --git a/components/plugins/renderer/loadable_plugin_placeholder.cc b/components/plugins/renderer/loadable_plugin_placeholder.cc index d3af1fc..b1567c8 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.cc +++ b/components/plugins/renderer/loadable_plugin_placeholder.cc @@ -292,20 +292,7 @@ void LoadablePluginPlaceholder::LoadPlugin() { ReplacePlugin(premade_throttler_->GetWebPlugin()); premade_throttler_ = nullptr; } else { - // TODO(mmenke): In the case of prerendering, feed into - // ChromeContentRendererClient::CreatePlugin instead, to - // reduce the chance of future regressions. - scoped_ptr<PluginInstanceThrottler> throttler; -#if defined(ENABLE_PLUGINS) - // 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 = PluginInstanceThrottler::Create(); -#endif - WebPlugin* plugin = render_frame()->CreatePlugin( - GetFrame(), plugin_info_, GetPluginParams(), throttler.Pass()); - - ReplacePlugin(plugin); + ReplacePlugin(CreatePlugin()); } } @@ -348,6 +335,10 @@ void LoadablePluginPlaceholder::SetIdentifier(const std::string& identifier) { identifier_ = identifier; } +const std::string& LoadablePluginPlaceholder::GetIdentifier() const { + return identifier_; +} + bool LoadablePluginPlaceholder::LoadingBlocked() const { DCHECK(allow_loading_); return is_blocked_for_background_tab_ || is_blocked_for_power_saver_poster_ || diff --git a/components/plugins/renderer/loadable_plugin_placeholder.h b/components/plugins/renderer/loadable_plugin_placeholder.h index 841115b..4ddbaac 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.h +++ b/components/plugins/renderer/loadable_plugin_placeholder.h @@ -24,6 +24,8 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { } #if defined(ENABLE_PLUGINS) + bool power_saver_enabled() const { return power_saver_enabled_; } + void set_power_saver_enabled(bool power_saver_enabled) { power_saver_enabled_ = power_saver_enabled; } @@ -58,6 +60,7 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { void SetPluginInfo(const content::WebPluginInfo& plugin_info); const content::WebPluginInfo& GetPluginInfo() const; void SetIdentifier(const std::string& identifier); + const std::string& GetIdentifier() const; bool LoadingAllowed() const { return allow_loading_; } // Replace this placeholder with a different plugin (which could be @@ -93,6 +96,9 @@ class LoadablePluginPlaceholder : public PluginPlaceholder { bool LoadingBlocked() const; + // Plugin creation is embedder-specific. + virtual blink::WebPlugin* CreatePlugin() = 0; + content::WebPluginInfo plugin_info_; base::string16 message_; diff --git a/content/public/renderer/plugin_instance_throttler.h b/content/public/renderer/plugin_instance_throttler.h index 0b33cc4..025ccbd 100644 --- a/content/public/renderer/plugin_instance_throttler.h +++ b/content/public/renderer/plugin_instance_throttler.h @@ -62,6 +62,8 @@ class CONTENT_EXPORT PluginInstanceThrottler { virtual void OnThrottleStateChange() {} + virtual void OnPeripheralStateChange() {} + // Called when the plugin should be hidden due to a placeholder. virtual void OnHiddenForPlaceholder(bool hidden) {} diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.cc b/content/renderer/pepper/plugin_instance_throttler_impl.cc index 6936a1a..a73a224 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.cc +++ b/content/renderer/pepper/plugin_instance_throttler_impl.cc @@ -9,11 +9,8 @@ #include "content/public/common/content_constants.h" #include "content/public/renderer/render_thread.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" -#include "content/renderer/pepper/pepper_webplugin_impl.h" #include "content/renderer/render_frame_impl.h" #include "ppapi/shared_impl/ppapi_constants.h" -#include "ppapi/shared_impl/scoped_pp_var.h" -#include "ppapi/shared_impl/var.h" #include "third_party/WebKit/public/platform/WebRect.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/WebPluginParams.h" @@ -98,16 +95,10 @@ void PluginInstanceThrottlerImpl::MarkPluginEssential( state_ = THROTTLER_STATE_MARKED_ESSENTIAL; RecordUnthrottleMethodMetric(method); + FOR_EACH_OBSERVER(Observer, observer_list_, OnPeripheralStateChange()); + if (was_throttled) FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottleStateChange()); - - // Notify the Power Saver test plugin of a peripheral status change. - if (web_plugin_ && web_plugin_->instance() && - plugin_module_name_ == ppapi::kPowerSaverTestPluginName) { - web_plugin_->instance()->HandleMessage(ppapi::ScopedPPVar( - ppapi::ScopedPPVar::PassRef(), - ppapi::StringVar::StringToPPVar("peripheralStatusChange"))); - } } void PluginInstanceThrottlerImpl::SetHiddenForPlaceholder(bool hidden) { @@ -115,7 +106,7 @@ void PluginInstanceThrottlerImpl::SetHiddenForPlaceholder(bool hidden) { FOR_EACH_OBSERVER(Observer, observer_list_, OnHiddenForPlaceholder(hidden)); } -blink::WebPlugin* PluginInstanceThrottlerImpl::GetWebPlugin() const { +PepperWebPluginImpl* PluginInstanceThrottlerImpl::GetWebPlugin() const { DCHECK(web_plugin_); return web_plugin_; } @@ -140,7 +131,7 @@ void PluginInstanceThrottlerImpl::Initialize( const GURL& content_origin, const std::string& plugin_module_name, const gfx::Size& unobscured_size) { - plugin_module_name_ = plugin_module_name; + DCHECK(unobscured_size_.IsEmpty()); unobscured_size_ = unobscured_size; // |frame| may be nullptr in tests. @@ -151,7 +142,9 @@ void PluginInstanceThrottlerImpl::Initialize( unobscured_size.width(), unobscured_size.height(), &cross_origin_main_content)) { + DCHECK_NE(THROTTLER_STATE_MARKED_ESSENTIAL, state_); state_ = THROTTLER_STATE_MARKED_ESSENTIAL; + FOR_EACH_OBSERVER(Observer, observer_list_, OnPeripheralStateChange()); if (cross_origin_main_content) helper->WhitelistContentOrigin(content_origin); diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.h b/content/renderer/pepper/plugin_instance_throttler_impl.h index 9bd9357..ec3eed68 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.h +++ b/content/renderer/pepper/plugin_instance_throttler_impl.h @@ -11,6 +11,7 @@ #include "base/timer/timer.h" #include "content/common/content_export.h" #include "content/public/renderer/plugin_instance_throttler.h" +#include "content/renderer/pepper/pepper_webplugin_impl.h" #include "ppapi/shared_impl/ppb_view_shared.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/size.h" @@ -39,7 +40,7 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl bool IsHiddenForPlaceholder() const override; void MarkPluginEssential(PowerSaverUnthrottleMethod method) override; void SetHiddenForPlaceholder(bool hidden) override; - blink::WebPlugin* GetWebPlugin() const override; + PepperWebPluginImpl* GetWebPlugin() const override; const gfx::Size& GetSize() const override; void NotifyAudioThrottled() override; @@ -98,9 +99,6 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl // Number of frames we've examined to find a keyframe. int frames_examined_; - // Plugin module name as of initialization. - std::string plugin_module_name_; - // Plugin's unobscured dimensions as of initialization. gfx::Size unobscured_size_; diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc index 1cbdcaf..bb7b5e8 100644 --- a/content/renderer/pepper/plugin_module.cc +++ b/content/renderer/pepper/plugin_module.cc @@ -135,6 +135,7 @@ #include "ppapi/c/trusted/ppb_file_chooser_trusted.h" #include "ppapi/c/trusted/ppb_url_loader_trusted.h" #include "ppapi/shared_impl/callback_tracker.h" +#include "ppapi/shared_impl/dictionary_var.h" #include "ppapi/shared_impl/ppapi_preferences.h" #include "ppapi/shared_impl/ppapi_switches.h" #include "ppapi/shared_impl/ppb_input_event_shared.h" @@ -181,6 +182,59 @@ PluginModuleSet* GetLivePluginSet() { return &live_plugin_libs; } +class PowerSaverTestPluginDelegate : public PluginInstanceThrottler::Observer { + public: + explicit PowerSaverTestPluginDelegate(PluginInstanceThrottlerImpl* throttler) + : throttler_(throttler) { + throttler_->AddObserver(this); + PostPowerSaverStatusToJavaScript(throttler_, "initial"); + } + + virtual ~PowerSaverTestPluginDelegate() { throttler_->RemoveObserver(this); } + + static void PostPowerSaverStatusToJavaScript( + PluginInstanceThrottlerImpl* throttler, + const std::string& source) { + if (!throttler->GetWebPlugin() || !throttler->GetWebPlugin()->instance()) + return; + + PepperPluginInstanceImpl* instance = throttler->GetWebPlugin()->instance(); + + // Refcounted by the returned PP_Var. + ppapi::DictionaryVar* dictionary = new ppapi::DictionaryVar; + dictionary->Set(ppapi::StringVar::StringToPPVar("source"), + ppapi::StringVar::StringToPPVar(source)); + dictionary->Set( + ppapi::StringVar::StringToPPVar("isHiddenForPlaceholder"), + PP_MakeBool(PP_FromBool(throttler->IsHiddenForPlaceholder()))); + dictionary->Set(ppapi::StringVar::StringToPPVar("isPeripheral"), + PP_MakeBool(PP_FromBool(throttler->power_saver_enabled()))); + dictionary->Set(ppapi::StringVar::StringToPPVar("isThrottled"), + PP_MakeBool(PP_FromBool(throttler->IsThrottled()))); + + instance->PostMessageToJavaScript(dictionary->GetPPVar()); + } + + private: + void OnThrottleStateChange() override { + PostPowerSaverStatusToJavaScript(throttler_, "throttleStatusChange"); + } + + void OnPeripheralStateChange() override { + PostPowerSaverStatusToJavaScript(throttler_, "peripheralStatusChange"); + } + + void OnHiddenForPlaceholder(bool hidden) override { + PostPowerSaverStatusToJavaScript(throttler_, + "hiddenForPlaceholderStatusChange"); + } + + void OnThrottlerDestroyed() override { delete this; } + + // Non-owning pointer. + PluginInstanceThrottlerImpl* const throttler_; +}; + // PPB_Core -------------------------------------------------------------------- void AddRefResource(PP_Resource resource) { @@ -246,12 +300,24 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { PP_Bool IsOutOfProcess() { return PP_FALSE; } -PP_Bool IsPeripheral(PP_Instance instance_id) { +void PostPowerSaverStatus(PP_Instance instance_id) { PepperPluginInstanceImpl* plugin_instance = host_globals->GetInstance(instance_id); if (!plugin_instance || !plugin_instance->throttler()) - return PP_FALSE; - return PP_FromBool(plugin_instance->throttler()->power_saver_enabled()); + return; + + PowerSaverTestPluginDelegate::PostPowerSaverStatusToJavaScript( + plugin_instance->throttler(), "getPowerSaverStatusResponse"); +} + +void SubscribeToPowerSaverNotifications(PP_Instance instance_id) { + PepperPluginInstanceImpl* plugin_instance = + host_globals->GetInstance(instance_id); + if (!plugin_instance || !plugin_instance->throttler()) + return; + + // Manages its own lifetime. + new PowerSaverTestPluginDelegate(plugin_instance->throttler()); } void SimulateInputEvent(PP_Instance instance, PP_Resource input_event) { @@ -302,7 +368,8 @@ const PPB_Testing_Private testing_interface = { &QuitMessageLoop, &GetLiveObjectsForInstance, &IsOutOfProcess, - &IsPeripheral, + &PostPowerSaverStatus, + &SubscribeToPowerSaverNotifications, &SimulateInputEvent, &GetDocumentURL, &GetLiveVars, diff --git a/ppapi/api/private/ppb_testing_private.idl b/ppapi/api/private/ppb_testing_private.idl index 8de73f7..c2aed41 100644 --- a/ppapi/api/private/ppb_testing_private.idl +++ b/ppapi/api/private/ppb_testing_private.idl @@ -77,11 +77,20 @@ interface PPB_Testing_Private { * otherwise. */ PP_Bool IsOutOfProcess(); - + + /** + * Posts the plugin's current Power Saver status to JavaScript. The plugin + * itself does not recieve anything. This is not idiomatic for Pepper, + * but convenient for testing. + */ + void PostPowerSaverStatus([in] PP_Instance instance); + /** - * Returns PP_TRUE if the plugin is peripheral, PP_FALSE otherwise. + * Subscribes to changes to the plugin's Power Saver status. The status + * changes are not forwarded to the plugin itself, but posted to JavaScript. + * This is not idiomatic for Pepper, but conveienent for testing. */ - PP_Bool IsPeripheral([in] PP_Instance instance); + void SubscribeToPowerSaverNotifications([in] PP_Instance instance); /** * Passes the input event to the browser, which sends it back to the diff --git a/ppapi/c/private/ppb_testing_private.h b/ppapi/c/private/ppb_testing_private.h index 5003d75..efe456a 100644 --- a/ppapi/c/private/ppb_testing_private.h +++ b/ppapi/c/private/ppb_testing_private.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From private/ppb_testing_private.idl modified Mon Jul 28 15:12:12 2014. */ +/* From private/ppb_testing_private.idl modified Fri May 1 13:14:52 2015. */ #ifndef PPAPI_C_PRIVATE_PPB_TESTING_PRIVATE_H_ #define PPAPI_C_PRIVATE_PPB_TESTING_PRIVATE_H_ @@ -93,9 +93,17 @@ struct PPB_Testing_Private_1_0 { */ PP_Bool (*IsOutOfProcess)(void); /** - * Returns PP_TRUE if the plugin is peripheral, PP_FALSE otherwise. + * Posts the plugin's current Power Saver status to JavaScript. The plugin + * itself does not recieve anything. This is not idiomatic for Pepper, + * but convenient for testing. */ - PP_Bool (*IsPeripheral)(PP_Instance instance); + void (*PostPowerSaverStatus)(PP_Instance instance); + /** + * Subscribes to changes to the plugin's Power Saver status. The status + * changes are not forwarded to the plugin itself, but posted to JavaScript. + * This is not idiomatic for Pepper, but conveienent for testing. + */ + void (*SubscribeToPowerSaverNotifications)(PP_Instance instance); /** * Passes the input event to the browser, which sends it back to the * plugin. The plugin should implement PPP_InputEvent and register for diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index 022430a..b217310 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c @@ -4133,9 +4133,14 @@ static PP_Bool Pnacl_M33_PPB_Testing_Private_IsOutOfProcess(void) { return iface->IsOutOfProcess(); } -static PP_Bool Pnacl_M33_PPB_Testing_Private_IsPeripheral(PP_Instance instance) { +static void Pnacl_M33_PPB_Testing_Private_PostPowerSaverStatus(PP_Instance instance) { const struct PPB_Testing_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_Testing_Private_1_0.real_iface; - return iface->IsPeripheral(instance); + iface->PostPowerSaverStatus(instance); +} + +static void Pnacl_M33_PPB_Testing_Private_SubscribeToPowerSaverNotifications(PP_Instance instance) { + const struct PPB_Testing_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_Testing_Private_1_0.real_iface; + iface->SubscribeToPowerSaverNotifications(instance); } static void Pnacl_M33_PPB_Testing_Private_SimulateInputEvent(PP_Instance instance, PP_Resource input_event) { @@ -5633,7 +5638,8 @@ static const struct PPB_Testing_Private_1_0 Pnacl_Wrappers_PPB_Testing_Private_1 .QuitMessageLoop = (void (*)(PP_Instance instance))&Pnacl_M33_PPB_Testing_Private_QuitMessageLoop, .GetLiveObjectsForInstance = (uint32_t (*)(PP_Instance instance))&Pnacl_M33_PPB_Testing_Private_GetLiveObjectsForInstance, .IsOutOfProcess = (PP_Bool (*)(void))&Pnacl_M33_PPB_Testing_Private_IsOutOfProcess, - .IsPeripheral = (PP_Bool (*)(PP_Instance instance))&Pnacl_M33_PPB_Testing_Private_IsPeripheral, + .PostPowerSaverStatus = (void (*)(PP_Instance instance))&Pnacl_M33_PPB_Testing_Private_PostPowerSaverStatus, + .SubscribeToPowerSaverNotifications = (void (*)(PP_Instance instance))&Pnacl_M33_PPB_Testing_Private_SubscribeToPowerSaverNotifications, .SimulateInputEvent = (void (*)(PP_Instance instance, PP_Resource input_event))&Pnacl_M33_PPB_Testing_Private_SimulateInputEvent, .GetDocumentURL = (struct PP_Var (*)(PP_Instance instance, struct PP_URLComponents_Dev* components))&Pnacl_M33_PPB_Testing_Private_GetDocumentURL, .GetLiveVars = (uint32_t (*)(struct PP_Var live_vars[], uint32_t array_size))&Pnacl_M33_PPB_Testing_Private_GetLiveVars, diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 1c978843..9f692e2 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -1204,9 +1204,11 @@ IPC_SYNC_MESSAGE_ROUTED3_1( IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, PP_Instance /* instance */, uint32 /* result */) -IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBTesting_IsPeripheral, - PP_Instance /* instance */, - PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBTesting_PostPowerSaverStatus, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED1_0( + PpapiHostMsg_PPBTesting_SubscribeToPowerSaverNotifications, + PP_Instance /* instance */) IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBTesting_SimulateInputEvent, PP_Instance /* instance */, ppapi::InputEventData /* input_event */) diff --git a/ppapi/proxy/ppb_testing_proxy.cc b/ppapi/proxy/ppb_testing_proxy.cc index 914eb44..4381798 100644 --- a/ppapi/proxy/ppb_testing_proxy.cc +++ b/ppapi/proxy/ppb_testing_proxy.cc @@ -80,16 +80,25 @@ PP_Bool IsOutOfProcess() { return PP_TRUE; } -PP_Bool IsPeripheral(PP_Instance instance_id) { +void PostPowerSaverStatus(PP_Instance instance_id) { ProxyAutoLock lock; PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); if (!dispatcher) - return PP_FALSE; + return; - PP_Bool result = PP_FALSE; - dispatcher->Send(new PpapiHostMsg_PPBTesting_IsPeripheral( - API_ID_PPB_TESTING, instance_id, &result)); - return result; + dispatcher->Send(new PpapiHostMsg_PPBTesting_PostPowerSaverStatus( + API_ID_PPB_TESTING, instance_id)); +} + +void SubscribeToPowerSaverNotifications(PP_Instance instance_id) { + ProxyAutoLock lock; + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return; + + dispatcher->Send( + new PpapiHostMsg_PPBTesting_SubscribeToPowerSaverNotifications( + API_ID_PPB_TESTING, instance_id)); } void SimulateInputEvent(PP_Instance instance_id, PP_Resource input_event) { @@ -150,7 +159,8 @@ const PPB_Testing_Private testing_interface = { &QuitMessageLoop, &GetLiveObjectsForInstance, &IsOutOfProcess, - &IsPeripheral, + &PostPowerSaverStatus, + &SubscribeToPowerSaverNotifications, &SimulateInputEvent, &GetDocumentURL, &GetLiveVars, @@ -186,7 +196,11 @@ bool PPB_Testing_Proxy::OnMessageReceived(const IPC::Message& msg) { OnMsgReadImageData) IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, OnMsgGetLiveObjectsForInstance) - IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_IsPeripheral, OnMsgIsPeripheral) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_PostPowerSaverStatus, + OnMsgPostPowerSaverStatus) + IPC_MESSAGE_HANDLER( + PpapiHostMsg_PPBTesting_SubscribeToPowerSaverNotifications, + OnMsgSubscribeToPowerSaverNotifications) IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_SimulateInputEvent, OnMsgSimulateInputEvent) IPC_MESSAGE_HANDLER( @@ -219,9 +233,13 @@ void PPB_Testing_Proxy::OnMsgGetLiveObjectsForInstance(PP_Instance instance, *result = ppb_testing_impl_->GetLiveObjectsForInstance(instance); } -void PPB_Testing_Proxy::OnMsgIsPeripheral(PP_Instance instance, - PP_Bool* result) { - *result = ppb_testing_impl_->IsPeripheral(instance); +void PPB_Testing_Proxy::OnMsgPostPowerSaverStatus(PP_Instance instance) { + ppb_testing_impl_->PostPowerSaverStatus(instance); +} + +void PPB_Testing_Proxy::OnMsgSubscribeToPowerSaverNotifications( + PP_Instance instance) { + ppb_testing_impl_->SubscribeToPowerSaverNotifications(instance); } void PPB_Testing_Proxy::OnMsgSimulateInputEvent( diff --git a/ppapi/proxy/ppb_testing_proxy.h b/ppapi/proxy/ppb_testing_proxy.h index dd8a6e8..7640291 100644 --- a/ppapi/proxy/ppb_testing_proxy.h +++ b/ppapi/proxy/ppb_testing_proxy.h @@ -39,7 +39,8 @@ class PPB_Testing_Proxy : public InterfaceProxy { void OnMsgRunMessageLoop(PP_Instance instance); void OnMsgQuitMessageLoop(PP_Instance instance); void OnMsgGetLiveObjectsForInstance(PP_Instance instance, uint32_t* result); - void OnMsgIsPeripheral(PP_Instance instance, PP_Bool* result); + void OnMsgPostPowerSaverStatus(PP_Instance instance); + void OnMsgSubscribeToPowerSaverNotifications(PP_Instance instance); void OnMsgSimulateInputEvent(PP_Instance instance, const ppapi::InputEventData& input_event); void OnMsgSetMinimumArrayBufferSizeForShmem(uint32_t threshold); diff --git a/ppapi/tests/power_saver_test_plugin.cc b/ppapi/tests/power_saver_test_plugin.cc index f14c5fe..44aef4d 100644 --- a/ppapi/tests/power_saver_test_plugin.cc +++ b/ppapi/tests/power_saver_test_plugin.cc @@ -4,10 +4,10 @@ #include <algorithm> +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/module.h" -#include "ppapi/cpp/var.h" -#include "ppapi/cpp/var_dictionary.h" #include "ppapi/tests/test_utils.h" // Windows defines 'PostMessage', so we have to undef it. @@ -19,42 +19,58 @@ class PowerSaverTestInstance : public pp::Instance { public: explicit PowerSaverTestInstance(PP_Instance instance) - : pp::Instance(instance), received_first_did_change_view_(false) {} + : pp::Instance(instance), callback_factory_(this) {} ~PowerSaverTestInstance() override {} - // For browser tests, responds to: - // - When postMessage("isPeripheral") is called on the plugin DOM element. - // - When the plugin throttler posts a message notifying us that our - // peripheral status has changed. + bool Init(uint32_t argc, const char* argn[], const char* argv[]) { + GetTestingInterface()->SubscribeToPowerSaverNotifications(pp_instance()); + return true; + } + void HandleMessage(const pp::Var& message_data) override { - if (message_data.is_string()) { - if (message_data.AsString() == "getPeripheralStatus") - BroadcastIsPeripheralStatus("getPeripheralStatusResponse"); - else if (message_data.AsString() == "peripheralStatusChange") - BroadcastIsPeripheralStatus("peripheralStatusChange"); + if (message_data.is_string() && + message_data.AsString() == "getPowerSaverStatus") { + GetTestingInterface()->PostPowerSaverStatus(pp_instance()); } } // Broadcast our peripheral status after the initial view data. This is for // tests that await initial plugin creation. void DidChangeView(const pp::View& view) override { - if (!received_first_did_change_view_) { - BroadcastIsPeripheralStatus("initial"); - received_first_did_change_view_ = true; - } + view_ = view; + device_context_ = pp::Graphics2D(this, view_.GetRect().size(), true); + if (!BindGraphics(device_context_)) + return; + + Paint(); } + void OnFlush(int32_t) { Paint(); } + private: - void BroadcastIsPeripheralStatus(const std::string& source) { - pp::VarDictionary message; - message.Set( - "isPeripheral", - pp::Var(PP_ToBool(GetTestingInterface()->IsPeripheral(pp_instance())))); - message.Set("source", pp::Var(source)); - PostMessage(message); + void Paint() { + pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, + view_.GetRect().size(), true); + if (image.is_null()) + return; + + // Draw black and white stripes to present an "interesting" keyframe. + for (int y = 0; y < view_.GetRect().size().height(); ++y) { + for (int x = 0; x < view_.GetRect().size().width(); ++x) { + uint32_t color = x % 2 ? 0xFF0000FF : 0xFFFFFFFF; + *image.GetAddr32(pp::Point(x, y)) = color; + } + } + + device_context_.ReplaceContents(&image); + device_context_.Flush( + callback_factory_.NewCallback(&PowerSaverTestInstance::OnFlush)); } - bool received_first_did_change_view_; + pp::View view_; + pp::Graphics2D device_context_; + + pp::CompletionCallbackFactory<PowerSaverTestInstance> callback_factory_; }; class PowerSaverTestModule : public pp::Module { |