summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvictorhsieh@chromium.org <victorhsieh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-27 20:54:03 +0000
committervictorhsieh@chromium.org <victorhsieh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-27 20:54:03 +0000
commit29652cf5d1121cdc8833106c98f3808a7620fdee (patch)
tree068a51c1e73f4ac3b4ceff0a5049712576f9f4d8
parent4e62b3d0ac881be70f5dca51ffc249522d0db7ab (diff)
downloadchromium_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.cc1
-rw-r--r--ppapi/tests/test_graphics_2d.cc87
-rw-r--r--ppapi/tests/test_graphics_2d.h21
-rw-r--r--webkit/plugins/ppapi/ppb_graphics_2d_impl.cc30
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) {