diff options
author | victorhsieh@chromium.org <victorhsieh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-27 20:54:03 +0000 |
---|---|---|
committer | victorhsieh@chromium.org <victorhsieh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-27 20:54:03 +0000 |
commit | 29652cf5d1121cdc8833106c98f3808a7620fdee (patch) | |
tree | 068a51c1e73f4ac3b4ceff0a5049712576f9f4d8 | |
parent | 4e62b3d0ac881be70f5dca51ffc249522d0db7ab (diff) | |
download | chromium_src-29652cf5d1121cdc8833106c98f3808a7620fdee.zip chromium_src-29652cf5d1121cdc8833106c98f3808a7620fdee.tar.gz chromium_src-29652cf5d1121cdc8833106c98f3808a7620fdee.tar.bz2 |
Fix cpu draining callback in Graphics2D::Flush.
Graphics2D::Flush should delay callback when the update is invisible,
while the plugin is visible on current tab.
Contributed by victorhsieh@chromium.org
BUG=
Review URL: https://chromiumcodereview.appspot.com/10933107
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@159112 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/ppapi/ppapi_browsertest.cc | 1 | ||||
-rw-r--r-- | ppapi/tests/test_graphics_2d.cc | 87 | ||||
-rw-r--r-- | ppapi/tests/test_graphics_2d.h | 21 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppb_graphics_2d_impl.cc | 30 |
4 files changed, 129 insertions, 10 deletions
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index d3b728b..2c9753f 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc @@ -258,6 +258,7 @@ TEST_PPAPI_NACL_VIA_HTTP(Graphics2D_Paint) TEST_PPAPI_NACL_VIA_HTTP(Graphics2D_Scroll) TEST_PPAPI_NACL_VIA_HTTP(Graphics2D_Replace) TEST_PPAPI_NACL_VIA_HTTP(Graphics2D_Flush) +TEST_PPAPI_NACL_VIA_HTTP(Graphics2D_FlushOffscreenUpdate) TEST_PPAPI_IN_PROCESS(Graphics3D) TEST_PPAPI_OUT_OF_PROCESS(Graphics3D) diff --git a/ppapi/tests/test_graphics_2d.cc b/ppapi/tests/test_graphics_2d.cc index feefbd5..3418b1a 100644 --- a/ppapi/tests/test_graphics_2d.cc +++ b/ppapi/tests/test_graphics_2d.cc @@ -35,6 +35,12 @@ void FlushCallbackQuitMessageLoop(void* data, int32_t result) { } // namespace +TestGraphics2D::TestGraphics2D(TestingInstance* instance) + : TestCase(instance), + is_view_changed_(false), + post_quit_on_view_changed_(false) { +} + bool TestGraphics2D::Init() { graphics_2d_interface_ = static_cast<const PPB_Graphics2D*>( pp::Module::Get()->GetBrowserInterface(PPB_GRAPHICS_2D_INTERFACE)); @@ -54,6 +60,7 @@ void TestGraphics2D::RunTests(const std::string& filter) { RUN_TEST_FORCEASYNC_AND_NOT(Scroll, filter); RUN_TEST_FORCEASYNC_AND_NOT(Replace, filter); RUN_TEST_FORCEASYNC_AND_NOT(Flush, filter); + RUN_TEST_FORCEASYNC_AND_NOT(FlushOffscreenUpdate, filter); RUN_TEST(Dev, filter); RUN_TEST(ReplaceContentsCaching, filter); } @@ -649,6 +656,86 @@ std::string TestGraphics2D::TestFlush() { PASS(); } +void TestGraphics2D::DidChangeView(const pp::View& view) { + if (post_quit_on_view_changed_) { + post_quit_on_view_changed_ = false; + is_view_changed_ = true; + testing_interface_->QuitMessageLoop(instance_->pp_instance()); + } +} + +void TestGraphics2D::ResetViewChangedState() { + is_view_changed_ = false; +} + +bool TestGraphics2D::WaitUntilViewChanged() { + // Run a nested message loop. It will exit either on ViewChanged or if the + // timeout happens. + + // If view changed before we have chance to run message loop, return directly. + if (is_view_changed_) + return true; + + post_quit_on_view_changed_ = true; + testing_interface_->RunMessageLoop(instance_->pp_instance()); + post_quit_on_view_changed_ = false; + + return is_view_changed_; +} + +std::string TestGraphics2D::TestFlushOffscreenUpdate() { + // Tests that callback of offscreen updates should be delayed. + const PP_Time kFlushDelaySec = 1. / 30; // 30 fps + const int w = 80, h = 80; + pp::Graphics2D dc(instance_, pp::Size(w, h), true); + if (dc.is_null()) + return "Failure creating a boring device"; + if (!instance_->BindGraphics(dc)) + return "Failure to bind the boring device."; + + // Squeeze from top until bottom half of plugin is out of screen. + ResetViewChangedState(); + instance_->EvalScript( + "var big = document.createElement('div');" + "var offset = " + " window.innerHeight - plugin.offsetTop - plugin.offsetHeight / 2;" + "big.setAttribute('id', 'big-div');" + "big.setAttribute('style', 'height: ' + offset + '; width: 100%;');" + "document.body.insertBefore(big, document.body.firstChild);"); + if (!WaitUntilViewChanged()) + return "View didn't change as expected"; + + // Allocate a red image chunk + pp::ImageData chunk(instance_, PP_IMAGEDATAFORMAT_RGBA_PREMUL, + pp::Size(w/8, h/8), true); + if (chunk.is_null()) + return "Failure to allocate image"; + const uint32_t kRed = 0xff0000ff; + FillRectInImage(&chunk, pp::Rect(chunk.size()), kRed); + + // Paint a invisable chunk, expecting Flush to invoke callback slowly. + dc.PaintImageData(chunk, pp::Point(0, h*0.75)); + + PP_Time begin = pp::Module::Get()->core()->GetTime(); + if (!FlushAndWaitForDone(&dc)) + return "Couldn't flush an invisible paint"; + PP_Time actual_time_elapsed = pp::Module::Get()->core()->GetTime() - begin; + // Expect actual_time_elapsed >= kFlushDelaySec, but loose a bit to avoid + // precision issue. + if (actual_time_elapsed < kFlushDelaySec * 0.9) + return "Offscreen painting should be delayed"; + + // Remove the padding on the top since test cases here isn't independent. + instance_->EvalScript( + "var big = document.getElementById('big-div');" + "big.parentNode.removeChild(big);"); + ResetViewChangedState(); + if (!WaitUntilViewChanged()) + return "View didn't change as expected"; + + PASS(); +} + std::string TestGraphics2D::TestDev() { // Tests GetScale/SetScale via the Graphics2D_Dev C++ wrapper const int w = 20, h = 16; diff --git a/ppapi/tests/test_graphics_2d.h b/ppapi/tests/test_graphics_2d.h index 3c1fe32..193aa44 100644 --- a/ppapi/tests/test_graphics_2d.h +++ b/ppapi/tests/test_graphics_2d.h @@ -21,9 +21,10 @@ class Rect; class TestGraphics2D : public TestCase { public: - explicit TestGraphics2D(TestingInstance* instance) : TestCase(instance) {} + explicit TestGraphics2D(TestingInstance* instance); // TestCase implementation. + virtual void DidChangeView(const pp::View& view); virtual bool Init(); virtual void RunTests(const std::string& filter); @@ -78,6 +79,14 @@ class TestGraphics2D : public TestCase { PP_Resource ReplaceContentsAndReturnID(pp::Graphics2D* dc, const pp::Size& size); + // Resets the internal state of view change. + void ResetViewChangedState(); + + // Waits until we get a view change event. Note that it's possible to receive + // an unexpected event, thus post_quit_on_view_changed_ is introduced so that + // DidChangeView can check whether the event is from here. + bool WaitUntilViewChanged(); + std::string TestInvalidResource(); std::string TestInvalidSize(); std::string TestHumongous(); @@ -87,12 +96,22 @@ class TestGraphics2D : public TestCase { std::string TestScroll(); std::string TestReplace(); std::string TestFlush(); + std::string TestFlushOffscreenUpdate(); std::string TestDev(); std::string TestReplaceContentsCaching(); // Used by the tests that access the C API directly. const PPB_Graphics2D* graphics_2d_interface_; const PPB_ImageData* image_data_interface_; + + // Used to indicate that DidChangeView has happened, in order to make plugin + // and ui synchronous. + bool is_view_changed_; + + // Set to true to request that the next invocation of DidChangeView should + // post a quit to the message loop. DidChangeView will also reset the flag so + // this will only happen once. + bool post_quit_on_view_changed_; }; #endif // PPAPI_TESTS_TEST_GRAPHICS_2D_H_ diff --git a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc index a838f1f..ff5c523 100644 --- a/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc +++ b/webkit/plugins/ppapi/ppb_graphics_2d_impl.cc @@ -10,6 +10,7 @@ #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/message_loop.h" +#include "base/time.h" #include "skia/ext/platform_canvas.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/pp_rect.h" @@ -43,6 +44,8 @@ namespace ppapi { namespace { +const int64 kOffscreenCallbackDelayMs = 1000 / 30; // 30 fps + // Converts a rect inside an image of the given dimensions. The rect may be // NULL to indicate it should be the entire image. If the rect is outside of // the image, this will do nothing and return false. @@ -332,7 +335,8 @@ int32_t PPB_Graphics2D_Impl::Flush(scoped_refptr<TrackedCallback> callback, return PP_ERROR_INPROGRESS; bool done_replace_contents = false; - bool nothing_visible = true; + bool no_update_visible = true; + bool is_plugin_visible = true; for (size_t i = 0; i < queued_operations_.size(); i++) { QueuedOperation& operation = queued_operations_[i]; gfx::Rect op_rect; @@ -375,12 +379,14 @@ int32_t PPB_Graphics2D_Impl::Flush(scoped_refptr<TrackedCallback> callback, operation.type = QueuedOperation::PAINT; } - // Set |nothing_visible| to false if the change overlaps the visible area. - gfx::Rect visible_changed_rect = - PP_ToGfxRect(bound_instance_->view_data().clip_rect). - Intersect(op_rect); + gfx::Rect clip = PP_ToGfxRect(bound_instance_->view_data().clip_rect); + is_plugin_visible = !clip.IsEmpty(); + + // Set |no_update_visible| to false if the change overlaps the visible + // area. + gfx::Rect visible_changed_rect = clip.Intersect(op_rect); if (!visible_changed_rect.IsEmpty()) - nothing_visible = false; + no_update_visible = false; // Notify the plugin of the entire change (op_rect), even if it is // partially or completely off-screen. @@ -394,13 +400,18 @@ int32_t PPB_Graphics2D_Impl::Flush(scoped_refptr<TrackedCallback> callback, } queued_operations_.clear(); - if (nothing_visible) { + if (!bound_instance_) { + // As promised in the API, we always schedule callback when unbound. + ScheduleOffscreenCallback(FlushCallbackData(callback)); + } else if (no_update_visible && is_plugin_visible && + bound_instance_->view_data().is_page_visible) { // There's nothing visible to invalidate so just schedule the callback to // execute in the next round of the message loop. ScheduleOffscreenCallback(FlushCallbackData(callback)); } else { unpainted_flush_callback_.Set(callback); } + return PP_OK_COMPLETIONPENDING; } @@ -730,11 +741,12 @@ void PPB_Graphics2D_Impl::ScheduleOffscreenCallback( const FlushCallbackData& callback) { DCHECK(!HasPendingFlush()); offscreen_flush_pending_ = true; - MessageLoop::current()->PostTask( + MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&PPB_Graphics2D_Impl::ExecuteOffscreenCallback, weak_ptr_factory_.GetWeakPtr(), - callback)); + callback), + base::TimeDelta::FromMilliseconds(kOffscreenCallbackDelayMs)); } void PPB_Graphics2D_Impl::ExecuteOffscreenCallback(FlushCallbackData data) { |