| OLD | NEW |
| (Empty) |
| 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 | |
| 23 using namespace blink; | |
| 24 using testing::Test; | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 class FakeImageBufferClient : public ImageBufferClient, public WebThread::TaskOb
server { | |
| 29 public: | |
| 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 | |
| 70 private: | |
| 71 bool m_isDirty; | |
| 72 ImageBuffer* m_imageBuffer; | |
| 73 int m_frameCount; | |
| 74 }; | |
| 75 | |
| 76 } // unnamed namespace | |
| 77 | |
| 78 class RecordingImageBufferSurfaceTest : public Test { | |
| 79 protected: | |
| 80 RecordingImageBufferSurfaceTest() | |
| 81 { | |
| 82 OwnPtr<RecordingImageBufferSurface> testSurface = adoptPtr(new Recording
ImageBufferSurface(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_imageBuff
er.get())); | |
| 88 m_imageBuffer->setClient(m_fakeImageBufferClient.get()); | |
| 89 } | |
| 90 | |
| 91 public: | |
| 92 void testEmptyPicture() | |
| 93 { | |
| 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); | |
| 99 } | |
| 100 | |
| 101 void testNoFallbackWithClear() | |
| 102 { | |
| 103 m_testSurface->initializeCurrentFrame(); | |
| 104 m_testSurface->didClearCanvas(); | |
| 105 m_testSurface->getPicture(); | |
| 106 EXPECT_EQ(1, m_fakeImageBufferClient->frameCount()); | |
| 107 expectDisplayListEnabled(true); | |
| 108 } | |
| 109 | |
| 110 void testNonAnimatedCanvasUpdate() | |
| 111 { | |
| 112 m_testSurface->initializeCurrentFrame(); | |
| 113 // acquire picture twice to simulate a static canvas: nothing drawn betw
een updates | |
| 114 m_fakeImageBufferClient->fakeDraw(); | |
| 115 m_testSurface->getPicture(); | |
| 116 m_testSurface->getPicture(); | |
| 117 EXPECT_EQ(2, m_fakeImageBufferClient->frameCount()); | |
| 118 expectDisplayListEnabled(true); | |
| 119 } | |
| 120 | |
| 121 void testAnimatedWithoutClear() | |
| 122 { | |
| 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); | |
| 132 } | |
| 133 | |
| 134 void testFrameFinalizedByTaskObserver1() | |
| 135 { | |
| 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 | |
| 151 } | |
| 152 void testFrameFinalizedByTaskObserver2() | |
| 153 { | |
| 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); | |
| 162 } | |
| 163 | |
| 164 void testAnimatedWithClear() | |
| 165 { | |
| 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); | |
| 174 // clear after use | |
| 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); | |
| 181 } | |
| 182 | |
| 183 void testClearRect() | |
| 184 { | |
| 185 m_testSurface->initializeCurrentFrame(); | |
| 186 m_testSurface->getPicture(); | |
| 187 m_imageBuffer->context()->clearRect(FloatRect(FloatPoint(0, 0), FloatSiz
e(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); | |
| 193 } | |
| 194 | |
| 195 void expectDisplayListEnabled(bool displayListEnabled) | |
| 196 { | |
| 197 EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get())
; | |
| 198 EXPECT_EQ(!displayListEnabled, (bool)m_testSurface->m_rasterCanvas.get()
); | |
| 199 } | |
| 200 | |
| 201 private: | |
| 202 RecordingImageBufferSurface* m_testSurface; | |
| 203 OwnPtr<FakeImageBufferClient> m_fakeImageBufferClient; | |
| 204 OwnPtr<ImageBuffer> m_imageBuffer; | |
| 205 }; | |
| 206 | |
| 207 namespace { | |
| 208 | |
| 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-de
layed task | |
| 211 // and registering a single task observer. The run loop exits immediately after
running | |
| 212 // the single task. | |
| 213 class AutoInstallCurrentThreadPlatformMock { | |
| 214 public: | |
| 215 AutoInstallCurrentThreadPlatformMock() | |
| 216 { | |
| 217 m_oldPlatform = Platform::current(); | |
| 218 Platform::initialize(&m_mockPlatform); | |
| 219 } | |
| 220 | |
| 221 ~AutoInstallCurrentThreadPlatformMock() | |
| 222 { | |
| 223 Platform::initialize(m_oldPlatform); | |
| 224 } | |
| 225 | |
| 226 private: | |
| 227 class CurrentThreadMock : public WebThread { | |
| 228 public: | |
| 229 CurrentThreadMock() : m_taskObserver(0), m_task(0) { } | |
| 230 | |
| 231 virtual ~CurrentThreadMock() | |
| 232 { | |
| 233 EXPECT_EQ((Task*)0, m_task); | |
| 234 } | |
| 235 | |
| 236 virtual void postTask(Task* task) | |
| 237 { | |
| 238 EXPECT_EQ((Task*)0, m_task); | |
| 239 m_task = task; | |
| 240 } | |
| 241 | |
| 242 virtual void postDelayedTask(Task*, long long delayMs) OVERRIDE { ASSERT
_NOT_REACHED(); }; | |
| 243 | |
| 244 virtual bool isCurrentThread() const OVERRIDE { return true; } | |
| 245 virtual PlatformThreadId threadId() const OVERRIDE | |
| 246 { | |
| 247 ASSERT_NOT_REACHED(); | |
| 248 return 0; | |
| 249 } | |
| 250 | |
| 251 virtual void addTaskObserver(TaskObserver* taskObserver) OVERRIDE | |
| 252 { | |
| 253 EXPECT_EQ((TaskObserver*)0, m_taskObserver); | |
| 254 m_taskObserver = taskObserver; | |
| 255 } | |
| 256 | |
| 257 virtual void removeTaskObserver(TaskObserver* taskObserver) OVERRIDE | |
| 258 { | |
| 259 EXPECT_EQ(m_taskObserver, taskObserver); | |
| 260 m_taskObserver = 0; | |
| 261 } | |
| 262 | |
| 263 virtual void enterRunLoop() OVERRIDE | |
| 264 { | |
| 265 if (m_taskObserver) | |
| 266 m_taskObserver->willProcessTask(); | |
| 267 if (m_task) { | |
| 268 m_task->run(); | |
| 269 delete m_task; | |
| 270 m_task = 0; | |
| 271 } | |
| 272 if (m_taskObserver) | |
| 273 m_taskObserver->didProcessTask(); | |
| 274 } | |
| 275 | |
| 276 virtual void exitRunLoop() OVERRIDE { ASSERT_NOT_REACHED(); } | |
| 277 | |
| 278 private: | |
| 279 TaskObserver* m_taskObserver; | |
| 280 Task* m_task; | |
| 281 }; | |
| 282 | |
| 283 class CurrentThreadPlatformMock : public Platform { | |
| 284 public: | |
| 285 CurrentThreadPlatformMock() { } | |
| 286 virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t
length) { ASSERT_NOT_REACHED(); } | |
| 287 virtual WebThread* currentThread() OVERRIDE { return &m_currentThread; } | |
| 288 private: | |
| 289 CurrentThreadMock m_currentThread; | |
| 290 }; | |
| 291 | |
| 292 CurrentThreadPlatformMock m_mockPlatform; | |
| 293 Platform* m_oldPlatform; | |
| 294 }; | |
| 295 | |
| 296 | |
| 297 #define DEFINE_TEST_TASK_WRAPPER_CLASS(TEST_METHOD)
\ | |
| 298 class TestWrapperTask_ ## TEST_METHOD : public WebThread::Task {
\ | |
| 299 public:
\ | |
| 300 TestWrapperTask_ ## TEST_METHOD(RecordingImageBufferSurfaceTest* test) :
m_test(test) { } \ | |
| 301 virtual void run() OVERRIDE { m_test->TEST_METHOD(); }
\ | |
| 302 private:
\ | |
| 303 RecordingImageBufferSurfaceTest* m_test;
\ | |
| 304 }; | |
| 305 | |
| 306 #define CALL_TEST_TASK_WRAPPER(TEST_METHOD)
\ | |
| 307 {
\ | |
| 308 AutoInstallCurrentThreadPlatformMock ctpm;
\ | |
| 309 Platform::current()->currentThread()->postTask(new TestWrapperTask_ ## T
EST_METHOD(this)); \ | |
| 310 Platform::current()->currentThread()->enterRunLoop();
\ | |
| 311 } | |
| 312 | |
| 313 TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture) | |
| 314 { | |
| 315 testEmptyPicture(); | |
| 316 } | |
| 317 | |
| 318 TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear) | |
| 319 { | |
| 320 testNoFallbackWithClear(); | |
| 321 } | |
| 322 | |
| 323 DEFINE_TEST_TASK_WRAPPER_CLASS(testNonAnimatedCanvasUpdate) | |
| 324 TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate) | |
| 325 { | |
| 326 CALL_TEST_TASK_WRAPPER(testNonAnimatedCanvasUpdate) | |
| 327 expectDisplayListEnabled(true); | |
| 328 } | |
| 329 | |
| 330 DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithoutClear) | |
| 331 TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear) | |
| 332 { | |
| 333 CALL_TEST_TASK_WRAPPER(testAnimatedWithoutClear) | |
| 334 expectDisplayListEnabled(false); | |
| 335 } | |
| 336 | |
| 337 DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver1) | |
| 338 DEFINE_TEST_TASK_WRAPPER_CLASS(testFrameFinalizedByTaskObserver2) | |
| 339 TEST_F(RecordingImageBufferSurfaceTest, testFrameFinalizedByTaskObserver) | |
| 340 { | |
| 341 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver1) | |
| 342 expectDisplayListEnabled(false); | |
| 343 CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver2) | |
| 344 expectDisplayListEnabled(false); | |
| 345 } | |
| 346 | |
| 347 DEFINE_TEST_TASK_WRAPPER_CLASS(testAnimatedWithClear) | |
| 348 TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear) | |
| 349 { | |
| 350 CALL_TEST_TASK_WRAPPER(testAnimatedWithClear) | |
| 351 expectDisplayListEnabled(true); | |
| 352 } | |
| 353 | |
| 354 DEFINE_TEST_TASK_WRAPPER_CLASS(testClearRect) | |
| 355 TEST_F(RecordingImageBufferSurfaceTest, testClearRect) | |
| 356 { | |
| 357 CALL_TEST_TASK_WRAPPER(testClearRect); | |
| 358 expectDisplayListEnabled(true); | |
| 359 } | |
| 360 | |
| 361 } // namespace | |
| OLD | NEW |