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. 4 5#include "config.h" 6 7#include "platform/graphics/RecordingImageBufferSurface.h" 8 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" 19 20#include <gmock/gmock.h> 21#include <gtest/gtest.h> 22 23using namespace blink; 24using testing::Test; 25 26namespace { 27 28class FakeImageBufferClient : public ImageBufferClient, public WebThread::TaskObserver { 29public: 30 FakeImageBufferClient(ImageBuffer* imageBuffer) 31 : m_isDirty(false) 32 , m_imageBuffer(imageBuffer) 33 , m_frameCount(0) 34 { } 35 36 virtual ~FakeImageBufferClient() { } 37 38 // ImageBufferClient implementation 39 virtual void notifySurfaceInvalid() { } 40 virtual bool isDirty() { return m_isDirty; }; 41 virtual void didFinalizeFrame() 42 { 43 if (m_isDirty) { 44 Platform::current()->currentThread()->removeTaskObserver(this); 45 m_isDirty = false; 46 } 47 ++m_frameCount; 48 } 49 50 // TaskObserver implementation 51 virtual void willProcessTask() OVERRIDE { ASSERT_NOT_REACHED(); } 52 virtual void didProcessTask() OVERRIDE 53 { 54 ASSERT_TRUE(m_isDirty); 55 FloatRect dirtyRect(0, 0, 1, 1); 56 m_imageBuffer->finalizeFrame(dirtyRect); 57 ASSERT_FALSE(m_isDirty); 58 } 59 60 void fakeDraw() 61 { 62 if (m_isDirty) 63 return; 64 m_isDirty = true; 65 Platform::current()->currentThread()->addTaskObserver(this); 66 } 67 68 int frameCount() { return m_frameCount; } 69 70private: 71 bool m_isDirty; 72 ImageBuffer* m_imageBuffer; 73 int m_frameCount; 74}; 75 76} // unnamed namespace 77 78class RecordingImageBufferSurfaceTest : public Test { 79protected: 80 RecordingImageBufferSurfaceTest() 81 { 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 EXPECT_FALSE(!m_imageBuffer); 88 m_fakeImageBufferClient = adoptPtr(new FakeImageBufferClient(m_imageBuffer.get())); 89 m_imageBuffer->setClient(m_fakeImageBufferClient.get()); 90 } 91 92public: 93 void testEmptyPicture() 94 { 95 m_testSurface->initializeCurrentFrame(); 96 RefPtr<SkPicture> picture = m_testSurface->getPicture(); 97 EXPECT_TRUE((bool)picture.get()); 98 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 99 expectDisplayListEnabled(true); 100 } 101 102 void testNoFallbackWithClear() 103 { 104 m_testSurface->initializeCurrentFrame(); 105 m_testSurface->didClearCanvas(); 106 m_testSurface->getPicture(); 107 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 108 expectDisplayListEnabled(true); 109 } 110 111 void testNonAnimatedCanvasUpdate() 112 { 113 m_testSurface->initializeCurrentFrame(); 114 // acquire picture twice to simulate a static canvas: nothing drawn between updates 115 m_fakeImageBufferClient->fakeDraw(); 116 m_testSurface->getPicture(); 117 m_testSurface->getPicture(); 118 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 119 expectDisplayListEnabled(true); 120 } 121 122 void testAnimatedWithoutClear() 123 { 124 m_testSurface->initializeCurrentFrame(); 125 m_fakeImageBufferClient->fakeDraw(); 126 m_testSurface->getPicture(); 127 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 128 expectDisplayListEnabled(true); // first frame has an implicit clear 129 m_fakeImageBufferClient->fakeDraw(); 130 m_testSurface->getPicture(); 131 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 132 expectDisplayListEnabled(false); 133 } 134 135 void testFrameFinalizedByTaskObserver1() 136 { 137 m_testSurface->initializeCurrentFrame(); 138 expectDisplayListEnabled(true); 139 m_testSurface->getPicture(); 140 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 141 expectDisplayListEnabled(true); 142 m_fakeImageBufferClient->fakeDraw(); 143 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 144 expectDisplayListEnabled(true); 145 m_testSurface->getPicture(); 146 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 147 expectDisplayListEnabled(true); 148 m_fakeImageBufferClient->fakeDraw(); 149 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 150 expectDisplayListEnabled(true); 151 // Display list will be disabled only after exiting the runLoop 152 } 153 void testFrameFinalizedByTaskObserver2() 154 { 155 EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); 156 expectDisplayListEnabled(false); 157 m_testSurface->getPicture(); 158 EXPECT_EQ(4, m_fakeImageBufferClient->frameCount()); 159 expectDisplayListEnabled(false); 160 m_fakeImageBufferClient->fakeDraw(); 161 EXPECT_EQ(4, m_fakeImageBufferClient->frameCount()); 162 expectDisplayListEnabled(false); 163 } 164 165 void testAnimatedWithClear() 166 { 167 m_testSurface->initializeCurrentFrame(); 168 m_testSurface->getPicture(); 169 m_testSurface->didClearCanvas(); 170 m_fakeImageBufferClient->fakeDraw(); 171 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 172 m_testSurface->getPicture(); 173 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 174 expectDisplayListEnabled(true); 175 // clear after use 176 m_fakeImageBufferClient->fakeDraw(); 177 m_testSurface->didClearCanvas(); 178 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 179 m_testSurface->getPicture(); 180 EXPECT_EQ(3, m_fakeImageBufferClient->frameCount()); 181 expectDisplayListEnabled(true); 182 } 183 184 void testClearRect() 185 { 186 m_testSurface->initializeCurrentFrame(); 187 m_testSurface->getPicture(); 188 m_imageBuffer->context()->clearRect(FloatRect(FloatPoint(0, 0), FloatSize(m_testSurface->size()))); 189 m_fakeImageBufferClient->fakeDraw(); 190 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); 191 m_testSurface->getPicture(); 192 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); 193 expectDisplayListEnabled(true); 194 } 195 196 void expectDisplayListEnabled(bool displayListEnabled) 197 { 198 EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get()); 199 EXPECT_EQ(!displayListEnabled, (bool)m_testSurface->m_rasterCanvas.get()); 200 } 201 202private: 203 RecordingImageBufferSurface* m_testSurface; 204 OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient; 205 OwnPtr<ImageBuffer> m_imageBuffer; 206}; 207 208namespace { 209 210// The following test helper class installs a mock platform that provides a mock WebThread 211// for the current thread. The Mock thread is capable of queuing a single non-delayed task 212// and registering a single task observer. The run loop exits immediately after running 213// the single task. 214class AutoInstallCurrentThreadPlatformMock { 215public: 216 AutoInstallCurrentThreadPlatformMock() 217 { 218 m_oldPlatform = Platform::current(); 219 Platform::initialize(&m_mockPlatform); 220 } 221 222 ~AutoInstallCurrentThreadPlatformMock() 223 { 224 Platform::initialize(m_oldPlatform); 225 } 226 227private: 228 class CurrentThreadMock : public WebThread { 229 public: 230 CurrentThreadMock() : m_taskObserver(0), m_task(0) { } 231 232 virtual ~CurrentThreadMock() 233 { 234 EXPECT_EQ((Task*)0, m_task); 235 } 236 237 virtual void postTask(Task* task) 238 { 239 EXPECT_EQ((Task*)0, m_task); 240 m_task = task; 241 } 242 243 virtual void postDelayedTask(Task*, long long delayMs) OVERRIDE { ASSERT_NOT_REACHED(); }; 244 245 virtual bool isCurrentThread() const OVERRIDE { return true; } 246 virtual PlatformThreadId threadId() const OVERRIDE 247 { 248 ASSERT_NOT_REACHED(); 249 return 0; 250 } 251 252 virtual void addTaskObserver(TaskObserver* taskObserver) OVERRIDE 253 { 254 EXPECT_EQ((TaskObserver*)0, m_taskObserver); 255 m_taskObserver = taskObserver; 256 } 257 258 virtual void removeTaskObserver(TaskObserver* taskObserver) OVERRIDE 259 { 260 EXPECT_EQ(m_taskObserver, taskObserver); 261 m_taskObserver = 0; 262 } 263 264 virtual void enterRunLoop() OVERRIDE 265 { 266 if (m_taskObserver) 267 m_taskObserver->willProcessTask(); 268 if (m_task) { 269 m_task->run(); 270 delete m_task; 271 m_task = 0; 272 } 273 if (m_taskObserver) 274 m_taskObserver->didProcessTask(); 275 } 276 277 virtual void exitRunLoop() OVERRIDE { ASSERT_NOT_REACHED(); } 278 279 private: 280 TaskObserver* m_taskObserver; 281 Task* m_task; 282 }; 283 284 class CurrentThreadPlatformMock : public Platform { 285 public: 286 CurrentThreadPlatformMock() { } 287 virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); } 288 virtual WebThread* currentThread() OVERRIDE { return &m_currentThread; } 289 private: 290 CurrentThreadMock m_currentThread; 291 }; 292 293 CurrentThreadPlatformMock m_mockPlatform; 294 Platform* m_oldPlatform; 295}; 296 297 298#define DEFINE_TEST_TASK_WRAPPER_CLASS(TEST_METHOD) \ 299class TestWrapperTask_ ## TEST_METHOD : public WebThread::Task { \ 300 public: \ 301 TestWrapperTask_ ## TEST_METHOD(RecordingImageBufferSurfaceTest* test) : m_test(test) { } \ 302 virtual void run() OVERRIDE { m_test->TEST_METHOD(); } \ 303 private: \ 304 RecordingImageBufferSurfaceTest* m_test; \ 305}; 306 307#define CALL_TEST_TASK_WRAPPER(TEST_METHOD) \ 308 { \ 309 AutoInstallCurrentThreadPlatformMock ctpm; \ 310 Platform::current()->currentThread()->postTask(new TestWrapperTask_ ## TEST_METHOD(this)); \ 311 Platform::current()->currentThread()->enterRunLoop(); \ 312 } 313 314TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture) 315{ 316 testEmptyPicture(); 317} 318 319TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear) 320{ 321 testNoFallbackWithClear(); 322} 323 324DEFINE_TEST_TASK_WRAPPER_CLASS(testNonAnimatedCanvasUpdate) 325TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate) 326{ 327 CALL_TEST_TASK_WRAPPER(testNonAnimatedCanvasUpdate) 328 expectDisplayListEnabled(true); 329} 330 331DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithoutClear) 332TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear) 333{ 334 CALL_TEST_TASK_WRAPPER(testAnimatedWithoutClear) 335 expectDisplayListEnabled(false); 336} 337 338DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver1) 339DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver2) 340TEST_F(RecordingImageBufferSurfaceTest, testFrameFinalizedByTaskObserver) 341{ 342 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver1) 343 expectDisplayListEnabled(false); 344 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver2) 345 expectDisplayListEnabled(false); 346} 347 348DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithClear) 349TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear) 350{ 351 CALL_TEST_TASK_WRAPPER(testAnimatedWithClear) 352 expectDisplayListEnabled(true); 353} 354 355DEFINE_TEST_TASK_WRAPPER_CLASS(testClearRect) 356TEST_F(RecordingImageBufferSurfaceTest, testClearRect) 357{ 358 CALL_TEST_TASK_WRAPPER(testClearRect); 359 expectDisplayListEnabled(true); 360} 361 362} // namespace 363