Index: content/browser/renderer_host/render_widget_host_view_browsertest.cc |
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc |
index 2235486de06d10e9c562f9f8a73b9eebf561fc14..75718aad56c551bd0c28b979cf61d0ab631c07c6 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc |
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc |
@@ -13,69 +13,132 @@ |
#include "content/public/browser/render_view_host.h" |
#include "content/public/browser/web_contents.h" |
#include "content/public/common/content_paths.h" |
+#include "content/public/common/content_switches.h" |
#include "content/shell/shell.h" |
#include "content/test/content_browser_test.h" |
#include "content/test/content_browser_test_utils.h" |
#include "media/base/video_frame.h" |
#include "net/base/net_util.h" |
-#include "skia/ext/platform_canvas.h" |
#include "ui/compositor/compositor_setup.h" |
#if defined(OS_MACOSX) |
#include "ui/surface/io_surface_support_mac.h" |
#endif |
namespace content { |
+namespace { |
+// Common base class for browser tests. This is subclassed twice: Once to test |
+// the browser in forced-compositing mode, and once to test with compositing |
+// mode disabled. |
class RenderWidgetHostViewBrowserTest : public ContentBrowserTest { |
public: |
- RenderWidgetHostViewBrowserTest() : finish_called_(false), size_(400, 300) {} |
+ RenderWidgetHostViewBrowserTest() |
+ : frame_size_(400, 300), |
+ callback_invoke_count_(0), |
+ frames_captured_(0) {} |
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { |
+ ui::DisableTestCompositor(); |
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_)); |
} |
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
- ui::DisableTestCompositor(); |
+ // Overridden in subclasses to source either a compositing surface or a |
+ // backing store. |
+ virtual void SetUpSourceSurface() = 0; |
+ virtual bool IsCopySourceReady() = 0; |
+ |
+ int callback_invoke_count() const { |
+ return callback_invoke_count_; |
} |
- bool CheckAcceleratedCompositingActive() { |
- RenderWidgetHostImpl* impl = |
- RenderWidgetHostImpl::From( |
- shell()->web_contents()->GetRenderWidgetHostView()-> |
- GetRenderWidgetHost()); |
- return impl->is_accelerated_compositing_active(); |
+ int frames_captured() const { |
+ return frames_captured_; |
} |
- bool CheckCompositingSurface() { |
-#if defined(OS_WIN) |
- if (!GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) |
- return false; |
-#endif |
+ const gfx::Size& frame_size() const { |
+ return frame_size_; |
+ } |
- RenderViewHost* const rwh = |
- shell()->web_contents()->GetRenderViewHost(); |
- RenderWidgetHostViewPort* rwhvp = |
- static_cast<RenderWidgetHostViewPort*>(rwh->GetView()); |
- bool ret = !rwhvp->GetCompositingSurface().is_null(); |
-#if defined(OS_MACOSX) |
- ret &= rwhvp->HasAcceleratedSurface(gfx::Size()); |
-#endif |
- return ret; |
+ const base::FilePath& test_dir() const { |
+ return test_dir_; |
} |
- bool SetupCompositingSurface() { |
-#if defined(OS_MACOSX) |
- if (!IOSurfaceSupport::Initialize()) |
- return false; |
-#endif |
- NavigateToURL(shell(), net::FilePathToFileURL( |
- test_dir_.AppendASCII("rwhv_compositing_animation.html"))); |
- if (!CheckAcceleratedCompositingActive()) |
- return false; |
+ RenderViewHost* GetRenderViewHost() const { |
+ RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost(); |
+ CHECK(rvh); |
+ return rvh; |
+ } |
- // The page is now accelerated composited but a compositing surface might |
- // not be available immediately so wait for it. |
- while (!CheckCompositingSurface()) { |
+ RenderWidgetHostImpl* GetRenderWidgetHost() const { |
+ RenderWidgetHostImpl* const rwh = RenderWidgetHostImpl::From( |
+ shell()->web_contents()->GetRenderWidgetHostView()-> |
+ GetRenderWidgetHost()); |
+ CHECK(rwh); |
+ return rwh; |
+ } |
+ |
+ RenderWidgetHostViewPort* GetRenderWidgetHostViewPort() const { |
+ RenderWidgetHostViewPort* const view = |
+ RenderWidgetHostViewPort::FromRWHV(GetRenderViewHost()->GetView()); |
+ CHECK(view); |
+ return view; |
+ } |
+ |
+ // Callback when using CopyFromBackingStore() API. |
+ void FinishCopyFromBackingStore(const base::Closure& quit_closure, |
+ bool frame_captured, |
+ const SkBitmap& bitmap) { |
+ ++callback_invoke_count_; |
+ if (frame_captured) { |
+ ++frames_captured_; |
+ EXPECT_FALSE(bitmap.empty()); |
+ } |
+ if (!quit_closure.is_null()) |
+ quit_closure.Run(); |
+ } |
+ |
+ // Callback when using CopyFromCompositingSurfaceToVideoFrame() API. |
+ void FinishCopyFromCompositingSurface(const base::Closure& quit_closure, |
+ bool frame_captured) { |
+ ++callback_invoke_count_; |
+ if (frame_captured) |
+ ++frames_captured_; |
+ if (!quit_closure.is_null()) |
+ quit_closure.Run(); |
+ } |
+ |
+ // Callback when using frame subscriber API. |
+ void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop, |
+ base::Closure quit_closure, |
+ base::Time timestamp, |
+ bool frame_captured) { |
+ ++callback_invoke_count_; |
+ if (frame_captured) |
+ ++frames_captured_; |
+ if (!quit_closure.is_null()) |
+ loop->PostTask(FROM_HERE, quit_closure); |
+ } |
+ |
+ // Copy one frame using the CopyFromBackingStore API. |
+ void RunBasicCopyFromBackingStoreTest() { |
+ SetUpSourceSurface(); |
+ |
+ base::RunLoop run_loop; |
+ GetRenderViewHost()->CopyFromBackingStore( |
+ gfx::Rect(), |
+ frame_size(), |
+ base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore, |
+ base::Unretained(this), run_loop.QuitClosure())); |
+ run_loop.Run(); |
+ |
+ EXPECT_EQ(1, callback_invoke_count()); |
+ EXPECT_EQ(1, frames_captured()); |
+ } |
+ |
+ protected: |
+ // Waits until the source is available for copying. |
+ void WaitForCopySourceReady() { |
+ while (!IsCopySourceReady()) { |
base::RunLoop run_loop; |
MessageLoop::current()->PostDelayedTask( |
FROM_HERE, |
@@ -83,39 +146,72 @@ class RenderWidgetHostViewBrowserTest : public ContentBrowserTest { |
base::TimeDelta::FromMilliseconds(10)); |
run_loop.Run(); |
} |
- return true; |
} |
- bool SetupNonCompositing() { |
+ private: |
+ const gfx::Size frame_size_; |
+ base::FilePath test_dir_; |
+ int callback_invoke_count_; |
+ int frames_captured_; |
+}; |
+ |
+class RenderWidgetHostViewBrowserTest_Compositing |
Ken Russell (switch to Gerrit)
2013/04/30 23:23:02
The "_" here and in the subclass below doesn't rea
miu
2013/05/01 00:19:36
Done. Was concerned about what people might try i
|
+ : public RenderWidgetHostViewBrowserTest { |
+ public: |
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
+ command_line->AppendSwitch(switches::kForceCompositingMode); |
+ } |
+ |
+ virtual void SetUpSourceSurface() OVERRIDE { |
+#if defined(OS_MACOSX) |
+ ASSERT_TRUE(IOSurfaceSupport::Initialize()); |
+#endif |
NavigateToURL(shell(), net::FilePathToFileURL( |
- test_dir_.AppendASCII("rwhv_compositing_static.html"))); |
- return !CheckCompositingSurface(); |
+ test_dir().AppendASCII("rwhv_compositing_animation.html"))); |
+#if !defined(USE_AURA) |
+ ASSERT_TRUE(GetRenderWidgetHost()->is_accelerated_compositing_active()); |
+#endif |
+ |
+ // The page is now accelerated composited but a compositing surface might |
+ // not be available immediately so wait for it. |
+ WaitForCopySourceReady(); |
} |
- void FinishCopyFromBackingStore(bool expected_result, |
- const base::Closure& quit_closure, |
- bool result, |
- const SkBitmap& bitmap) { |
- quit_closure.Run(); |
- EXPECT_EQ(expected_result, result); |
- if (expected_result) |
- EXPECT_FALSE(bitmap.empty()); |
- finish_called_ = true; |
+ virtual bool IsCopySourceReady() OVERRIDE { |
+#if defined(OS_WIN) |
+ if (!GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) |
+ return false; |
+#endif |
+ |
+ RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); |
+ bool ret = !view->GetCompositingSurface().is_null(); |
+#if defined(OS_MACOSX) |
+ ret &= view->HasAcceleratedSurface(gfx::Size()); |
+#endif |
+ return ret; |
+ } |
+}; |
+ |
+class RenderWidgetHostViewBrowserTest_NonCompositing |
+ : public RenderWidgetHostViewBrowserTest { |
+ public: |
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
+ command_line->AppendSwitch(switches::kDisableAcceleratedCompositing); |
} |
- void FinishCopyFromCompositingSurface(bool expected_result, |
- const base::Closure& quit_closure, |
- bool result) { |
- if (!quit_closure.is_null()) |
- quit_closure.Run(); |
- EXPECT_EQ(expected_result, result); |
- finish_called_ = true; |
+ virtual void SetUpSourceSurface() OVERRIDE { |
+ // Assumption: Browser-internal pages will cause RenderWidget to turn off |
+ // compositing. |
Ken Russell (switch to Gerrit)
2013/04/30 23:23:02
Wasn't the point of the subclass to avoid these as
miu
2013/05/01 00:19:36
Ah! A should have removed the comment. The comma
|
+ NavigateToURL(shell(), GURL("about:blank")); |
+ WaitForCopySourceReady(); |
} |
- protected: |
- base::FilePath test_dir_; |
- bool finish_called_; |
- gfx::Size size_; |
+ virtual bool IsCopySourceReady() OVERRIDE { |
+ // Note: Passing false to GetBackingStore() asks for the backing store |
+ // without forcing its creation. We want to the browser to create it via |
+ // its normal mechanism. |
+ return GetRenderWidgetHost()->GetBackingStore(false) != NULL; |
Ken Russell (switch to Gerrit)
2013/04/30 23:23:02
Do you want to make assertions that the composited
miu
2013/05/01 00:19:36
Good point. Done.
|
+ } |
}; |
class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
@@ -146,177 +242,142 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
DeliverFrameCallback callback_; |
}; |
-#if defined(OS_MACOSX) || defined(OS_WIN) |
+// Disable tests for Android and IOS as these platforms have incomplete |
+// implementation. |
+#if !defined(OS_ANDROID) && !defined(OS_IOS) |
-static void DeliverFrameFunc(const scoped_refptr<base::MessageLoopProxy>& loop, |
- base::Closure quit_closure, |
- bool* frame_captured_out, |
- base::Time timestamp, |
- bool frame_captured) { |
- *frame_captured_out = frame_captured; |
- if (!quit_closure.is_null()) |
- loop->PostTask(FROM_HERE, quit_closure); |
+// The CopyFromBackingStore() API should work on all platforms when compositing |
+// is enabled. |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_Compositing, |
+ CopyFromBackingStore) { |
+ RunBasicCopyFromBackingStoreTest(); |
} |
-#endif |
+// The CopyFromBackingStore() API should work on all platforms when compositing |
+// is disabled. |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_NonCompositing, |
+ CopyFromBackingStore) { |
+ RunBasicCopyFromBackingStoreTest(); |
+} |
-#if defined(OS_MACOSX) |
-// Tests that the callback passed to CopyFromBackingStore is always called, even |
-// when the RenderWidgetHost is deleting in the middle of an async copy. |
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest, |
- MacAsyncCopyFromBackingStoreCallbackTest) { |
- if (!SetupCompositingSurface()) { |
- LOG(WARNING) << "Accelerated compositing not running."; |
- return; |
- } |
+// Tests that the callback passed to CopyFromBackingStore is always called, |
+// even when the RenderWidgetHost is deleting in the middle of an async copy. |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_Compositing, |
+ CopyFromBackingStore_CallbackDespiteDelete) { |
+ SetUpSourceSurface(); |
base::RunLoop run_loop; |
- RenderViewHost* const rwh = |
- shell()->web_contents()->GetRenderViewHost(); |
- RenderWidgetHostViewPort* rwhvp = |
- static_cast<RenderWidgetHostViewPort*>(rwh->GetView()); |
- |
- rwh->CopyFromBackingStore( |
+ GetRenderViewHost()->CopyFromBackingStore( |
gfx::Rect(), |
- size_, |
+ frame_size(), |
base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore, |
- base::Unretained(this), false, run_loop.QuitClosure())); |
- |
- // Delete the surface before the callback is run. This is synchronous until |
- // we get to the copy_timer_, so we will always end up in the destructor |
- // before the timer fires. |
- rwhvp->AcceleratedSurfaceRelease(); |
+ base::Unretained(this), run_loop.QuitClosure())); |
+ // Delete the surface before the callback is run. |
+ GetRenderWidgetHostViewPort()->AcceleratedSurfaceRelease(); |
run_loop.Run(); |
- EXPECT_TRUE(finish_called_); |
+ EXPECT_EQ(1, callback_invoke_count()); |
} |
// Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is |
// always called, even when the RenderWidgetHost is deleting in the middle of |
// an async copy. |
-IN_PROC_BROWSER_TEST_F( |
- RenderWidgetHostViewBrowserTest, |
- MacAsyncCopyFromCompositingSurfaceToVideoFrameCallbackTest) { |
- if (!SetupCompositingSurface()) { |
- LOG(WARNING) << "Accelerated compositing not running."; |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_Compositing, |
+ CopyFromCompositingSurface_CallbackDespiteDelete) { |
+ SetUpSourceSurface(); |
+ RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); |
+ if (!view->CanCopyToVideoFrame()) { |
+ LOG(WARNING) << ("CopyFromCompositingSurfaceToVideoFrame() not supported " |
+ "on this platform."); |
return; |
} |
base::RunLoop run_loop; |
- RenderViewHost* const rwh = |
- shell()->web_contents()->GetRenderViewHost(); |
- RenderWidgetHostViewPort* rwhvp = |
- static_cast<RenderWidgetHostViewPort*>(rwh->GetView()); |
- |
scoped_refptr<media::VideoFrame> dest = |
- media::VideoFrame::CreateBlackFrame(size_); |
- rwhvp->CopyFromCompositingSurfaceToVideoFrame( |
- gfx::Rect(rwhvp->GetViewBounds().size()), dest, base::Bind( |
+ media::VideoFrame::CreateBlackFrame(frame_size()); |
+ view->CopyFromCompositingSurfaceToVideoFrame( |
+ gfx::Rect(view->GetViewBounds().size()), dest, base::Bind( |
&RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface, |
- base::Unretained(this), false, run_loop.QuitClosure())); |
- |
- // Delete the surface before the callback is run. This is synchronous until |
- // we get to the copy_timer_, so we will always end up in the destructor |
- // before the timer fires. |
- rwhvp->AcceleratedSurfaceRelease(); |
+ base::Unretained(this), run_loop.QuitClosure())); |
+ // Delete the surface before the callback is run. |
+ view->AcceleratedSurfaceRelease(); |
run_loop.Run(); |
- ASSERT_TRUE(finish_called_); |
+ EXPECT_EQ(1, callback_invoke_count()); |
} |
-#endif |
- |
-#if (defined(OS_WIN) && !defined(USE_AURA)) || defined(OS_MACOSX) |
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest, |
- FrameSubscriberTest) { |
- if (!SetupCompositingSurface()) { |
- LOG(WARNING) << "Accelerated compositing not running."; |
- return; |
- } |
- base::RunLoop run_loop; |
- RenderWidgetHostViewPort* view = RenderWidgetHostViewPort::FromRWHV( |
- shell()->web_contents()->GetRenderViewHost()->GetView()); |
- ASSERT_TRUE(view); |
+// With compositing turned off, no platforms should support the |
+// CopyFromCompositingSurfaceToVideoFrame() API. |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_NonCompositing, |
+ CopyFromCompositingSurfaceToVideoFrameCallbackTest) { |
+ SetUpSourceSurface(); |
+ EXPECT_FALSE(GetRenderWidgetHostViewPort()->CanCopyToVideoFrame()); |
+} |
+// Test basic frame subscription functionality. We subscribe, and then run |
+// until at least one DeliverFrameCallback has been invoked. |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_Compositing, |
+ FrameSubscriberTest) { |
+ SetUpSourceSurface(); |
+ RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); |
if (!view->CanSubscribeFrame()) { |
- LOG(WARNING) << "Frame subscription no supported on this platform."; |
+ LOG(WARNING) << "Frame subscription not supported on this platform."; |
return; |
ncarter (slow)
2013/05/01 00:04:32
I expect this will happen on XP.
|
} |
- bool frame_captured = false; |
+ base::RunLoop run_loop; |
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
- new FakeFrameSubscriber(base::Bind(&DeliverFrameFunc, |
- base::MessageLoopProxy::current(), |
- run_loop.QuitClosure(), |
- &frame_captured))); |
+ new FakeFrameSubscriber( |
+ base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, |
+ base::Unretained(this), |
+ base::MessageLoopProxy::current(), |
+ run_loop.QuitClosure()))); |
view->BeginFrameSubscription(subscriber.Pass()); |
run_loop.Run(); |
view->EndFrameSubscription(); |
- EXPECT_TRUE(frame_captured); |
-} |
-// Test copying from backing store when page is non-accelerated-composited. |
-// Flaky. http://crbug.com/224351 |
-#if defined(OS_MACOSX) || defined(OS_WIN) |
-#define MAYBE_CopyFromBackingStore DISABLED_CopyFromBackingStore |
-#else |
-#define MAYBE_CopyFromBackingStore CopyFromBackingStore |
-#endif |
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest, |
- MAYBE_CopyFromBackingStore) { |
- SetupNonCompositing(); |
- base::RunLoop run_loop; |
- |
- shell()->web_contents()->GetRenderViewHost()->CopyFromBackingStore( |
- gfx::Rect(), |
- size_, |
- base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore, |
- base::Unretained(this), true, run_loop.QuitClosure())); |
- run_loop.Run(); |
- |
- EXPECT_TRUE(finish_called_); |
+ EXPECT_LE(1, callback_invoke_count()); |
+ EXPECT_LE(1, frames_captured()); |
} |
-#endif |
-#if defined(OS_MACOSX) |
// Test that we can copy twice from an accelerated composited page. |
-// This test is only running on Mac because this is the only platform that |
-// we can reliably detect that accelerated surface is in use. |
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest, CopyTwice) { |
- if (!SetupCompositingSurface()) { |
- LOG(WARNING) << "Accelerated compositing not running."; |
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTest_Compositing, CopyTwice) { |
+ SetUpSourceSurface(); |
+ RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort(); |
+ if (!view->CanCopyToVideoFrame()) { |
+ LOG(WARNING) << ("CopyFromCompositingSurfaceToVideoFrame() not supported " |
+ "on this platform."); |
ncarter (slow)
2013/05/01 00:04:32
I expect this will happen on XP.
|
return; |
} |
base::RunLoop run_loop; |
- RenderViewHost* const rwh = |
- shell()->web_contents()->GetRenderViewHost(); |
- RenderWidgetHostViewPort* rwhvp = |
- static_cast<RenderWidgetHostViewPort*>(rwh->GetView()); |
- scoped_refptr<media::VideoFrame> dest = |
- media::VideoFrame::CreateBlackFrame(size_); |
- |
- bool first_frame_captured = false; |
- bool second_frame_captured = false; |
- rwhvp->CopyFromCompositingSurfaceToVideoFrame( |
- gfx::Rect(rwhvp->GetViewBounds().size()), dest, |
- base::Bind(&DeliverFrameFunc, |
+ scoped_refptr<media::VideoFrame> first_output = |
+ media::VideoFrame::CreateBlackFrame(frame_size()); |
+ ASSERT_TRUE(first_output); |
+ scoped_refptr<media::VideoFrame> second_output = |
+ media::VideoFrame::CreateBlackFrame(frame_size()); |
+ ASSERT_TRUE(second_output); |
+ view->CopyFromCompositingSurfaceToVideoFrame( |
+ gfx::Rect(view->GetViewBounds().size()), first_output, |
+ base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, |
+ base::Unretained(this), |
base::MessageLoopProxy::current(), |
base::Closure(), |
- &first_frame_captured, |
base::Time::Now())); |
- rwhvp->CopyFromCompositingSurfaceToVideoFrame( |
- gfx::Rect(rwhvp->GetViewBounds().size()), dest, |
- base::Bind(&DeliverFrameFunc, |
+ view->CopyFromCompositingSurfaceToVideoFrame( |
+ gfx::Rect(view->GetViewBounds().size()), second_output, |
+ base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered, |
+ base::Unretained(this), |
base::MessageLoopProxy::current(), |
run_loop.QuitClosure(), |
- &second_frame_captured, |
base::Time::Now())); |
run_loop.Run(); |
- EXPECT_TRUE(first_frame_captured); |
- EXPECT_TRUE(second_frame_captured); |
+ EXPECT_EQ(2, callback_invoke_count()); |
+ EXPECT_EQ(2, frames_captured()); |
} |
-#endif |
+#endif // !defined(OS_ANDROID) && !defined(OS_IOS) |
+ |
+} // namespace |
} // namespace content |