1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "platform/graphics/RecordingImageBufferSurface.h"
9 #include "platform/graphics/GraphicsContext.h"
10 #include "platform/graphics/ImageBuffer.h"
11 #include "platform/graphics/ImageBufferClient.h"
12 #include "public/platform/Platform.h"
13 #include "public/platform/WebThread.h"
14 #include "third_party/skia/include/core/SkCanvas.h"
15 #include "third_party/skia/include/core/SkPictureRecorder.h"
16 #include "wtf/OwnPtr.h"
17 #include "wtf/PassOwnPtr.h"
18 #include "wtf/RefPtr.h"
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
23 using namespace blink;
28 class FakeImageBufferClient : public ImageBufferClient, public WebThread::TaskObserver {
30 FakeImageBufferClient(ImageBuffer* imageBuffer)
32 , m_imageBuffer(imageBuffer)
36 virtual ~FakeImageBufferClient() { }
38 // ImageBufferClient implementation
39 virtual void notifySurfaceInvalid() { }
40 virtual bool isDirty() { return m_isDirty; };
41 virtual void didFinalizeFrame()
44 Platform::current()->currentThread()->removeTaskObserver(this);
50 // TaskObserver implementation
51 virtual void willProcessTask() OVERRIDE { ASSERT_NOT_REACHED(); }
52 virtual void didProcessTask() OVERRIDE
54 ASSERT_TRUE(m_isDirty);
55 FloatRect dirtyRect(0, 0, 1, 1);
56 m_imageBuffer->finalizeFrame(dirtyRect);
57 ASSERT_FALSE(m_isDirty);
65 Platform::current()->currentThread()->addTaskObserver(this);
68 int frameCount() { return m_frameCount; }
72 ImageBuffer* m_imageBuffer;
76 } // unnamed namespace
78 class RecordingImageBufferSurfaceTest : public Test {
80 RecordingImageBufferSurfaceTest()
82 OwnPtr<RecordingImageBufferSurface> testSurface = adoptPtr(new RecordingImageBufferSurface(IntSize(10, 10)));
83 m_testSurface = testSurface.get();
84 // We create an ImageBuffer in order for the testSurface to be
85 // properly initialized with a GraphicsContext
86 m_imageBuffer = ImageBuffer::create(testSurface.release());
87 m_fakeImageBufferClient = adoptPtr(new FakeImageBufferClient(m_imageBuffer.get()));
88 m_imageBuffer->setClient(m_fakeImageBufferClient.get());
92 void testEmptyPicture()
94 m_testSurface->initializeCurrentFrame();
95 RefPtr<SkPicture> picture = m_testSurface->getPicture();
96 EXPECT_TRUE((bool)picture.get());
97 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
98 expectDisplayListEnabled(true);
101 void testNoFallbackWithClear()
103 m_testSurface->initializeCurrentFrame();
104 m_testSurface->didClearCanvas();
105 m_testSurface->getPicture();
106 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
107 expectDisplayListEnabled(true);
110 void testNonAnimatedCanvasUpdate()
112 m_testSurface->initializeCurrentFrame();
113 // acquire picture twice to simulate a static canvas: nothing drawn between updates
114 m_fakeImageBufferClient->fakeDraw();
115 m_testSurface->getPicture();
116 m_testSurface->getPicture();
117 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
118 expectDisplayListEnabled(true);
121 void testAnimatedWithoutClear()
123 m_testSurface->initializeCurrentFrame();
124 m_fakeImageBufferClient->fakeDraw();
125 m_testSurface->getPicture();
126 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
127 expectDisplayListEnabled(true); // first frame has an implicit clear
128 m_fakeImageBufferClient->fakeDraw();
129 m_testSurface->getPicture();
130 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
131 expectDisplayListEnabled(false);
134 void testFrameFinalizedByTaskObserver1()
136 m_testSurface->initializeCurrentFrame();
137 expectDisplayListEnabled(true);
138 m_testSurface->getPicture();
139 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
140 expectDisplayListEnabled(true);
141 m_fakeImageBufferClient->fakeDraw();
142 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
143 expectDisplayListEnabled(true);
144 m_testSurface->getPicture();
145 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
146 expectDisplayListEnabled(true);
147 m_fakeImageBufferClient->fakeDraw();
148 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
149 expectDisplayListEnabled(true);
150 // Display list will be disabled only after exiting the runLoop
152 void testFrameFinalizedByTaskObserver2()
154 EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
155 expectDisplayListEnabled(false);
156 m_testSurface->getPicture();
157 EXPECT_EQ(4, m_fakeImageBufferClient->frameCount());
158 expectDisplayListEnabled(false);
159 m_fakeImageBufferClient->fakeDraw();
160 EXPECT_EQ(4, m_fakeImageBufferClient->frameCount());
161 expectDisplayListEnabled(false);
164 void testAnimatedWithClear()
166 m_testSurface->initializeCurrentFrame();
167 m_testSurface->getPicture();
168 m_testSurface->didClearCanvas();
169 m_fakeImageBufferClient->fakeDraw();
170 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
171 m_testSurface->getPicture();
172 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
173 expectDisplayListEnabled(true);
175 m_fakeImageBufferClient->fakeDraw();
176 m_testSurface->didClearCanvas();
177 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
178 m_testSurface->getPicture();
179 EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
180 expectDisplayListEnabled(true);
185 m_testSurface->initializeCurrentFrame();
186 m_testSurface->getPicture();
187 m_imageBuffer->context()->clearRect(FloatRect(FloatPoint(0, 0), FloatSize(m_testSurface->size())));
188 m_fakeImageBufferClient->fakeDraw();
189 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
190 m_testSurface->getPicture();
191 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
192 expectDisplayListEnabled(true);
195 void expectDisplayListEnabled(bool displayListEnabled)
197 EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get());
198 EXPECT_EQ(!displayListEnabled, (bool)m_testSurface->m_rasterCanvas.get());
202 RecordingImageBufferSurface* m_testSurface;
203 OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient;
204 OwnPtr<ImageBuffer> m_imageBuffer;
209 // The following test helper class installs a mock platform that provides a mock WebThread
210 // for the current thread. The Mock thread is capable of queuing a single non-delayed task
211 // and registering a single task observer. The run loop exits immediately after running
213 class AutoInstallCurrentThreadPlatformMock {
215 AutoInstallCurrentThreadPlatformMock()
217 m_oldPlatform = Platform::current();
218 Platform::initialize(&m_mockPlatform);
221 ~AutoInstallCurrentThreadPlatformMock()
223 Platform::initialize(m_oldPlatform);
227 class CurrentThreadMock : public WebThread {
229 CurrentThreadMock() : m_taskObserver(0), m_task(0) { }
231 virtual ~CurrentThreadMock()
233 EXPECT_EQ((Task*)0, m_task);
236 virtual void postTask(Task* task)
238 EXPECT_EQ((Task*)0, m_task);
242 virtual void postDelayedTask(Task*, long long delayMs) OVERRIDE { ASSERT_NOT_REACHED(); };
244 virtual bool isCurrentThread() const OVERRIDE { return true; }
246 virtual void addTaskObserver(TaskObserver* taskObserver) OVERRIDE
248 EXPECT_EQ((TaskObserver*)0, m_taskObserver);
249 m_taskObserver = taskObserver;
252 virtual void removeTaskObserver(TaskObserver* taskObserver) OVERRIDE
254 EXPECT_EQ(m_taskObserver, taskObserver);
258 virtual void enterRunLoop() OVERRIDE
261 m_taskObserver->willProcessTask();
268 m_taskObserver->didProcessTask();
271 virtual void exitRunLoop() OVERRIDE { ASSERT_NOT_REACHED(); }
274 TaskObserver* m_taskObserver;
278 class CurrentThreadPlatformMock : public Platform {
280 CurrentThreadPlatformMock() { }
281 virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); }
282 virtual WebThread* currentThread() OVERRIDE { return &m_currentThread; }
284 CurrentThreadMock m_currentThread;
287 CurrentThreadPlatformMock m_mockPlatform;
288 Platform* m_oldPlatform;
292 #define DEFINE_TEST_TASK_WRAPPER_CLASS(TEST_METHOD) \
293 class TestWrapperTask_ ## TEST_METHOD : public WebThread::Task { \
295 TestWrapperTask_ ## TEST_METHOD(RecordingImageBufferSurfaceTest* test) : m_test(test) { } \
296 virtual void run() OVERRIDE { m_test->TEST_METHOD(); } \
298 RecordingImageBufferSurfaceTest* m_test; \
301 #define CALL_TEST_TASK_WRAPPER(TEST_METHOD) \
303 AutoInstallCurrentThreadPlatformMock ctpm; \
304 Platform::current()->currentThread()->postTask(new TestWrapperTask_ ## TEST_METHOD(this)); \
305 Platform::current()->currentThread()->enterRunLoop(); \
308 TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture)
313 TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear)
315 testNoFallbackWithClear();
318 DEFINE_TEST_TASK_WRAPPER_CLASS(testNonAnimatedCanvasUpdate)
319 TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate)
321 CALL_TEST_TASK_WRAPPER(testNonAnimatedCanvasUpdate)
322 expectDisplayListEnabled(true);
325 DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithoutClear)
326 TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear)
328 CALL_TEST_TASK_WRAPPER(testAnimatedWithoutClear)
329 expectDisplayListEnabled(false);
332 DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver1)
333 DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver2)
334 TEST_F(RecordingImageBufferSurfaceTest, testFrameFinalizedByTaskObserver)
336 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver1)
337 expectDisplayListEnabled(false);
338 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver2)
339 expectDisplayListEnabled(false);
342 DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithClear)
343 TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear)
345 CALL_TEST_TASK_WRAPPER(testAnimatedWithClear)
346 expectDisplayListEnabled(true);
349 DEFINE_TEST_TASK_WRAPPER_CLASS(testClearRect)
350 TEST_F(RecordingImageBufferSurfaceTest, testClearRect)
352 CALL_TEST_TASK_WRAPPER(testClearRect);
353 expectDisplayListEnabled(true);