Index: content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
index dfa654843f8986525d0c5b97d0c879bc5a4fcd5d..d089f630a6f417b832ff7a3695518a569903c72a 100644
|
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
@@ -22,8 +22,6 @@
|
#include "content/browser/renderer_host/render_view_host_factory.h"
|
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
#include "content/browser/web_contents/web_contents_impl.h"
|
-#include "content/public/browser/notification_service.h"
|
-#include "content/public/browser/notification_types.h"
|
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
|
#include "content/public/browser/web_contents_media_capture_id.h"
|
#include "content/public/test/mock_render_process_host.h"
|
@@ -60,7 +58,8 @@ const SkColor kNotInterested = ~kNothingYet;
|
|
void DeadlineExceeded(base::Closure quit_closure) {
|
if (!base::debug::BeingDebugged()) {
|
- quit_closure.Run();
|
+ if (!quit_closure.is_null())
|
+ quit_closure.Run();
|
FAIL() << "Deadline exceeded while waiting, quitting";
|
} else {
|
LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
|
@@ -94,8 +93,7 @@ class CaptureTestSourceController {
|
CaptureTestSourceController()
|
: color_(SK_ColorMAGENTA),
|
copy_result_size_(kTestWidth, kTestHeight),
|
- can_copy_to_video_frame_(false),
|
- use_frame_subscriber_(false) {}
|
+ can_copy_to_video_frame_(true) {}
|
|
void SetSolidColor(SkColor color) {
|
base::AutoLock guard(lock_);
|
@@ -136,16 +134,6 @@ class CaptureTestSourceController {
|
return can_copy_to_video_frame_;
|
}
|
|
- void SetUseFrameSubscriber(bool value) {
|
- base::AutoLock guard(lock_);
|
- use_frame_subscriber_ = value;
|
- }
|
-
|
- bool CanUseFrameSubscriber() {
|
- base::AutoLock guard(lock_);
|
- return use_frame_subscriber_;
|
- }
|
-
|
void WaitForNextCopy() {
|
{
|
base::AutoLock guard(lock_);
|
@@ -160,7 +148,6 @@ class CaptureTestSourceController {
|
SkColor color_;
|
gfx::Size copy_result_size_;
|
bool can_copy_to_video_frame_;
|
- bool use_frame_subscriber_;
|
base::Closure copy_done_;
|
|
DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
|
@@ -487,8 +474,7 @@ class StubClientObserver {
|
public:
|
StubClientObserver()
|
: error_encountered_(false),
|
- wait_color_yuv_(0xcafe1950),
|
- wait_size_(kTestWidth, kTestHeight) {
|
+ wait_color_yuv_(0xcafe1950) {
|
client_.reset(new StubClient(
|
base::Bind(&StubClientObserver::DidDeliverFrame,
|
base::Unretained(this)),
|
@@ -503,28 +489,35 @@ class StubClientObserver {
|
|
void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
|
base::AutoLock guard(lock_);
|
- if (error_encountered_)
|
- base::MessageLoop::current()->QuitWhenIdle();
|
- else if (wait_color_yuv_ == color && wait_size_.IsEmpty())
|
- base::MessageLoop::current()->QuitWhenIdle();
|
- else if (wait_color_yuv_ == color && wait_size_ == size)
|
+ if (error_encountered_ || wait_color_yuv_ == kNotInterested ||
|
+ wait_color_yuv_ == color) {
|
+ last_frame_color_yuv_ = color;
|
+ last_frame_size_ = size;
|
base::MessageLoop::current()->QuitWhenIdle();
|
+ }
|
}
|
|
- // Run the current loop until a frame is delivered with the |expected_color|
|
- // and any non-empty frame size.
|
- void WaitForNextColor(SkColor expected_color) {
|
- WaitForNextColorAndFrameSize(expected_color, gfx::Size());
|
+ // Run the current loop until the next frame is delivered. Returns the YUV
|
+ // color and frame size.
|
+ std::pair<SkColor, gfx::Size> WaitForNextFrame() {
|
+ {
|
+ base::AutoLock guard(lock_);
|
+ wait_color_yuv_ = kNotInterested;
|
+ error_encountered_ = false;
|
+ }
|
+ RunCurrentLoopWithDeadline();
|
+ {
|
+ base::AutoLock guard(lock_);
|
+ CHECK(!error_encountered_);
|
+ return std::make_pair(last_frame_color_yuv_, last_frame_size_);
|
+ }
|
}
|
|
- // Run the current loop until a frame is delivered with the |expected_color|
|
- // and is of the |expected_size|.
|
- void WaitForNextColorAndFrameSize(SkColor expected_color,
|
- const gfx::Size& expected_size) {
|
+ // Run the current loop until a frame is delivered with the |expected_color|.
|
+ void WaitForNextColor(SkColor expected_color) {
|
{
|
base::AutoLock guard(lock_);
|
wait_color_yuv_ = ConvertRgbToYuv(expected_color);
|
- wait_size_ = expected_size;
|
error_encountered_ = false;
|
}
|
RunCurrentLoopWithDeadline();
|
@@ -538,7 +531,6 @@ class StubClientObserver {
|
{
|
base::AutoLock guard(lock_);
|
wait_color_yuv_ = kNotInterested;
|
- wait_size_ = gfx::Size();
|
error_encountered_ = false;
|
}
|
RunCurrentLoopWithDeadline();
|
@@ -577,7 +569,8 @@ class StubClientObserver {
|
base::Lock lock_;
|
bool error_encountered_;
|
SkColor wait_color_yuv_;
|
- gfx::Size wait_size_;
|
+ SkColor last_frame_color_yuv_;
|
+ gfx::Size last_frame_size_;
|
scoped_ptr<StubClient> client_;
|
|
DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
|
@@ -686,19 +679,30 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
|
}
|
|
void SimulateDrawEvent() {
|
- if (source()->CanUseFrameSubscriber()) {
|
- // Print
|
- CaptureTestView* test_view = static_cast<CaptureTestView*>(
|
- web_contents_->GetRenderViewHost()->GetWidget()->GetView());
|
- test_view->SimulateUpdate();
|
- } else {
|
- // Simulate a non-accelerated paint.
|
- NotificationService::current()->Notify(
|
- NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
|
- Source<RenderWidgetHost>(
|
- web_contents_->GetRenderViewHost()->GetWidget()),
|
- NotificationService::NoDetails());
|
- }
|
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
+
|
+ // Force at least one frame period's worth of time to pass. Otherwise,
|
+ // internal logic may decide not to capture a frame because the draw events
|
+ // are more frequent that kTestFramesPerSecond.
|
+ //
|
+ // TODO(miu): Instead of physically waiting, we should inject simulated
|
+ // clocks for testing.
|
+ base::RunLoop run_loop;
|
+ BrowserThread::PostDelayedTask(
|
+ BrowserThread::UI, FROM_HERE,
|
+ run_loop.QuitClosure(),
|
+ base::TimeDelta::FromMicroseconds(
|
+ base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
|
+ run_loop.Run();
|
+
|
+ // Schedule the update to occur when the test runs the event loop (and not
|
+ // before expectations have been set).
|
+ CaptureTestView* test_view = static_cast<CaptureTestView*>(
|
+ web_contents_->GetRenderViewHost()->GetWidget()->GetView());
|
+ BrowserThread::PostTask(
|
+ BrowserThread::UI, FROM_HERE,
|
+ base::Bind(&CaptureTestView::SimulateUpdate,
|
+ base::Unretained(test_view)));
|
}
|
|
void SimulateSourceSizeChange(const gfx::Size& size) {
|
@@ -717,6 +721,45 @@ class MAYBE_WebContentsVideoCaptureDeviceTest : public testing::Test {
|
as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true);
|
}
|
|
+ // Repeatedly schedules draw events and scans for frames until the output from
|
+ // the capture device matches the given RGB |color| and frame |size|.
|
+ void SimulateDrawsUntilNewFrameSizeArrives(SkColor color,
|
+ const gfx::Size& size) {
|
+ const base::TimeTicks start_time = base::TimeTicks::Now();
|
+ while ((base::TimeTicks::Now() - start_time) <
|
+ TestTimeouts::action_max_timeout()) {
|
+ SimulateDrawEvent();
|
+ const auto color_and_size = client_observer()->WaitForNextFrame();
|
+ if (color_and_size.first == ConvertRgbToYuv(color) &&
|
+ color_and_size.second == size) {
|
+ return;
|
+ }
|
+ }
|
+ DeadlineExceeded(base::Closure());
|
+ }
|
+
|
+ void SimulateRefreshFrameRequest() {
|
+ // Force at least three frame period's worth of time to pass. The wait is
|
+ // needed because refresh frame requests are only honored when drawing
|
+ // events, which trigger frame captures, are not occurring frequently
|
+ // enough.
|
+ //
|
+ // TODO(miu): Instead of physically waiting, we should inject simulated
|
+ // clocks for testing.
|
+ base::RunLoop run_loop;
|
+ BrowserThread::PostDelayedTask(
|
+ BrowserThread::UI, FROM_HERE,
|
+ run_loop.QuitClosure(),
|
+ base::TimeDelta::FromMicroseconds(
|
+ 3 * base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
|
+ run_loop.Run();
|
+
|
+ BrowserThread::PostTask(
|
+ BrowserThread::UI, FROM_HERE,
|
+ base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame,
|
+ base::Unretained(device_.get())));
|
+ }
|
+
|
void DestroyVideoCaptureDevice() { device_.reset(); }
|
|
StubClientObserver* client_observer() {
|
@@ -781,7 +824,9 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) {
|
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
- // Do one capture to prove
|
+
|
+ // Do one capture to prove the tab is initially open and being captured
|
+ // normally.
|
source()->SetSolidColor(SK_ColorRED);
|
SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
@@ -821,9 +866,9 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
}
|
|
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
|
- // Set up the test to use RGB copies and an normal
|
+ // Set up the test to use RGB captures into SkBitmaps instead of YUV captures
|
+ // into VideoFrames.
|
source()->SetCanCopyToVideoFrame(false);
|
- source()->SetUseFrameSubscriber(false);
|
media::VideoCaptureParams capture_params;
|
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
@@ -832,7 +877,7 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
|
|
base::RunLoop().RunUntilIdle();
|
|
- for (int i = 0; i < 10; ++i)
|
+ for (int i = 0; i < 3; ++i)
|
SimulateDrawEvent();
|
|
ASSERT_FALSE(client_observer()->HasError());
|
@@ -878,8 +923,8 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, DeviceRestart) {
|
|
// The "happy case" test. No scaling is needed, so we should be able to change
|
// the picture emitted from the source and expect to see each delivered to the
|
-// consumer. The test will alternate between the three capture paths, simulating
|
-// falling in and out of accelerated compositing.
|
+// consumer. The test will alternate between the RGB/SkBitmap and YUV/VideoFrame
|
+// capture paths.
|
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
|
media::VideoCaptureParams capture_params;
|
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
@@ -887,26 +932,14 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
|
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
- for (int i = 0; i < 6; i++) {
|
+ for (int i = 0; i < 4; i++) {
|
const char* name = NULL;
|
- switch (i % 3) {
|
- case 0:
|
- source()->SetCanCopyToVideoFrame(true);
|
- source()->SetUseFrameSubscriber(false);
|
- name = "VideoFrame";
|
- break;
|
- case 1:
|
- source()->SetCanCopyToVideoFrame(false);
|
- source()->SetUseFrameSubscriber(true);
|
- name = "Subscriber";
|
- break;
|
- case 2:
|
- source()->SetCanCopyToVideoFrame(false);
|
- source()->SetUseFrameSubscriber(false);
|
- name = "SkBitmap";
|
- break;
|
- default:
|
- FAIL();
|
+ if (i % 2) {
|
+ source()->SetCanCopyToVideoFrame(false);
|
+ name = "SkBitmap";
|
+ } else {
|
+ source()->SetCanCopyToVideoFrame(true);
|
+ name = "VideoFrame";
|
}
|
|
SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
|
@@ -942,17 +975,18 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
|
|
// These frames ought to be dropped during the Render stage. Let
|
// several captures to happen.
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ for (int i = 0; i < 3; ++i) {
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ }
|
|
// Now push some good frames through; they should be processed normally.
|
source()->SetCopyResultSize(kTestWidth, kTestHeight);
|
source()->SetSolidColor(SK_ColorGREEN);
|
+ SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
source()->SetSolidColor(SK_ColorRED);
|
+ SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
|
device()->StopAndDeAllocate();
|
@@ -972,17 +1006,14 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
- source()->SetUseFrameSubscriber(true);
|
-
|
// Source size equals maximum size. Expect delivered frames to be
|
// kTestWidth by kTestHeight.
|
source()->SetSolidColor(SK_ColorRED);
|
const float device_scale_factor = GetDeviceScaleFactor();
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
|
|
// Source size is half in both dimensions. Expect delivered frames to be of
|
// the same aspect ratio as kTestWidth by kTestHeight, but larger than the
|
@@ -990,27 +1021,24 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
source()->SetSolidColor(SK_ColorGREEN);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180));
|
|
// Source size changes aspect ratio. Expect delivered frames to be padded
|
// in the horizontal dimension to preserve aspect ratio.
|
source()->SetSolidColor(SK_ColorBLUE);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight));
|
|
// Source size changes aspect ratio again. Expect delivered frames to be
|
// padded in the vertical dimension to preserve aspect ratio.
|
source()->SetSolidColor(SK_ColorBLACK);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight / 2)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight));
|
|
device()->StopAndDeAllocate();
|
}
|
@@ -1029,26 +1057,22 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
- source()->SetUseFrameSubscriber(true);
|
-
|
// Source size equals maximum size. Expect delivered frames to be
|
// kTestWidth by kTestHeight.
|
source()->SetSolidColor(SK_ColorRED);
|
const float device_scale_factor = GetDeviceScaleFactor();
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
|
|
// Source size is half in both dimensions. Expect delivered frames to also
|
// be half in both dimensions.
|
source()->SetSolidColor(SK_ColorGREEN);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
+ SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2));
|
|
// Source size changes to something arbitrary. Since the source size is
|
// less than the maximum size, expect delivered frames to be the same size
|
@@ -1057,9 +1081,7 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
|
arbitrary_source_size));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
- SK_ColorBLUE, arbitrary_source_size));
|
+ SimulateDrawsUntilNewFrameSizeArrives(SK_ColorBLUE, arbitrary_source_size);
|
|
// Source size changes to something arbitrary that exceeds the maximum frame
|
// size. Since the source size exceeds the maximum size, expect delivered
|
@@ -1068,11 +1090,10 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
arbitrary_source_size = gfx::Size(kTestWidth * 2, kTestHeight / 2);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
|
arbitrary_source_size));
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SimulateDrawsUntilNewFrameSizeArrives(
|
SK_ColorBLACK, gfx::Size(kTestWidth,
|
kTestWidth * arbitrary_source_size.height() /
|
- arbitrary_source_size.width())));
|
+ arbitrary_source_size.width()));
|
|
device()->StopAndDeAllocate();
|
}
|
@@ -1171,5 +1192,36 @@ TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest,
|
}
|
}
|
|
+// Tests the RequestRefreshFrame() functionality.
|
+TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, ProvidesRefreshFrames) {
|
+ media::VideoCaptureParams capture_params;
|
+ capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
+ capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
+ capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
+ device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
+
|
+ // Request a refresh frame before the first frame has been drawn. This forces
|
+ // a capture.
|
+ source()->SetSolidColor(SK_ColorRED);
|
+ SimulateRefreshFrameRequest();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
+
|
+ // Now, draw a frame and wait for a normal frame capture to occur.
|
+ source()->SetSolidColor(SK_ColorGREEN);
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
+
|
+ // Now, make three more refresh frame requests. Although the source has
|
+ // changed to BLUE, no draw event has occurred. Therefore, expect the refresh
|
+ // frames to contain the content from the last drawn frame, which is GREEN.
|
+ source()->SetSolidColor(SK_ColorBLUE);
|
+ for (int i = 0; i < 3; ++i) {
|
+ SimulateRefreshFrameRequest();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
+ }
|
+
|
+ device()->StopAndDeAllocate();
|
+}
|
+
|
} // namespace
|
} // namespace content
|
|