blob: 3ea2a9e61457c5eaacb3eb4ba48e76ec726c5289 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/graphics/RecordingImageBufferSurface.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/ImageBuffer.h"
#include "platform/graphics/ImageBufferClient.h"
#include "platform/graphics/UnacceleratedImageBufferSurface.h"
#include "platform/testing/TestingPlatformSupport.h"
#include "public/platform/Platform.h"
#include "public/platform/WebTaskRunner.h"
#include "public/platform/WebThread.h"
#include "public/platform/WebTraceLocation.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "wtf/PtrUtil.h"
#include "wtf/RefPtr.h"
#include <memory>
using testing::Test;
namespace blink {
class FakeImageBufferClient : public ImageBufferClient,
public WebThread::TaskObserver {
public:
FakeImageBufferClient(ImageBuffer* imageBuffer)
: m_isDirty(false), m_imageBuffer(imageBuffer), m_frameCount(0) {}
~FakeImageBufferClient() override {}
// ImageBufferClient implementation
void notifySurfaceInvalid() override {}
bool isDirty() override { return m_isDirty; }
void didDisableAcceleration() override {}
void didFinalizeFrame() override {
if (m_isDirty) {
Platform::current()->currentThread()->removeTaskObserver(this);
m_isDirty = false;
}
++m_frameCount;
}
// TaskObserver implementation
void willProcessTask() override { NOTREACHED(); }
void didProcessTask() override {
ASSERT_TRUE(m_isDirty);
FloatRect dirtyRect(0, 0, 1, 1);
m_imageBuffer->finalizeFrame(dirtyRect);
ASSERT_FALSE(m_isDirty);
}
void restoreCanvasMatrixClipStack(SkCanvas*) const override {}
void fakeDraw() {
if (m_isDirty)
return;
m_isDirty = true;
Platform::current()->currentThread()->addTaskObserver(this);
}
int frameCount() { return m_frameCount; }
private:
bool m_isDirty;
ImageBuffer* m_imageBuffer;
int m_frameCount;
};
class MockSurfaceFactory : public RecordingImageBufferFallbackSurfaceFactory {
public:
MockSurfaceFactory() : m_createSurfaceCount(0) {}
virtual std::unique_ptr<ImageBufferSurface> createSurface(
const IntSize& size,
OpacityMode opacityMode,
sk_sp<SkColorSpace> colorSpace) {
m_createSurfaceCount++;
return wrapUnique(new UnacceleratedImageBufferSurface(
size, opacityMode, InitializeImagePixels, std::move(colorSpace)));
}
virtual ~MockSurfaceFactory() {}
int createSurfaceCount() { return m_createSurfaceCount; }
private:
int m_createSurfaceCount;
};
class RecordingImageBufferSurfaceTest : public Test {
protected:
RecordingImageBufferSurfaceTest() {
std::unique_ptr<MockSurfaceFactory> surfaceFactory =
wrapUnique(new MockSurfaceFactory());
m_surfaceFactory = surfaceFactory.get();
std::unique_ptr<RecordingImageBufferSurface> testSurface =
wrapUnique(new RecordingImageBufferSurface(
IntSize(10, 10), std::move(surfaceFactory), NonOpaque, nullptr));
m_testSurface = testSurface.get();
// We create an ImageBuffer in order for the testSurface to be
// properly initialized with a GraphicsContext
m_imageBuffer = ImageBuffer::create(std::move(testSurface));
EXPECT_FALSE(!m_imageBuffer);
m_fakeImageBufferClient =
wrapUnique(new FakeImageBufferClient(m_imageBuffer.get()));
m_imageBuffer->setClient(m_fakeImageBufferClient.get());
}
public:
void testEmptyPicture() {
m_testSurface->initializeCurrentFrame();
sk_sp<SkPicture> picture = m_testSurface->getPicture();
EXPECT_TRUE((bool)picture.get());
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
}
void testNoFallbackWithClear() {
m_testSurface->initializeCurrentFrame();
m_testSurface->willOverwriteCanvas();
m_testSurface->getPicture();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
}
void testNonAnimatedCanvasUpdate() {
m_testSurface->initializeCurrentFrame();
// Acquire picture twice to simulate a static canvas: nothing drawn between
// updates.
m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture();
m_testSurface->getPicture();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
}
void testAnimatedWithoutClear() {
m_testSurface->initializeCurrentFrame();
m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
EXPECT_EQ(0, m_surfaceFactory->createSurfaceCount());
expectDisplayListEnabled(true); // first frame has an implicit clear
m_fakeImageBufferClient->fakeDraw();
m_testSurface->getPicture();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
}
void testFrameFinalizedByTaskObserver1() {
m_testSurface->initializeCurrentFrame();
expectDisplayListEnabled(true);
m_testSurface->getPicture();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
m_testSurface->getPicture();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
// Display list will be disabled only after exiting the runLoop
}
void testFrameFinalizedByTaskObserver2() {
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
m_testSurface->getPicture();
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(false);
}
void testAnimatedWithClear() {
m_testSurface->initializeCurrentFrame();
m_testSurface->getPicture();
m_testSurface->willOverwriteCanvas();
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
m_testSurface->getPicture();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
// clear after use
m_fakeImageBufferClient->fakeDraw();
m_testSurface->willOverwriteCanvas();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
m_testSurface->getPicture();
EXPECT_EQ(3, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
}
void testClearRect() {
m_testSurface->initializeCurrentFrame();
m_testSurface->getPicture();
SkPaint clearPaint;
clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
m_imageBuffer->canvas()->drawRect(
SkRect::MakeWH(m_testSurface->size().width(),
m_testSurface->size().height()),
clearPaint);
m_fakeImageBufferClient->fakeDraw();
EXPECT_EQ(1, m_fakeImageBufferClient->frameCount());
m_testSurface->getPicture();
EXPECT_EQ(2, m_fakeImageBufferClient->frameCount());
expectDisplayListEnabled(true);
}
void expectDisplayListEnabled(bool displayListEnabled) {
EXPECT_EQ(displayListEnabled, (bool)m_testSurface->m_currentFrame.get());
EXPECT_EQ(!displayListEnabled,
(bool)m_testSurface->m_fallbackSurface.get());
int expectedSurfaceCreationCount = displayListEnabled ? 0 : 1;
EXPECT_EQ(expectedSurfaceCreationCount,
m_surfaceFactory->createSurfaceCount());
}
private:
MockSurfaceFactory* m_surfaceFactory;
RecordingImageBufferSurface* m_testSurface;
std::unique_ptr<FakeImageBufferClient> m_fakeImageBufferClient;
std::unique_ptr<ImageBuffer> m_imageBuffer;
};
#define CALL_TEST_TASK_WRAPPER(TEST_METHOD) \
{ \
TestingPlatformSupportWithMockScheduler testingPlatform; \
Platform::current()->currentThread()->getWebTaskRunner()->postTask( \
BLINK_FROM_HERE, \
WTF::bind(&RecordingImageBufferSurfaceTest::TEST_METHOD, \
WTF::unretained(this))); \
testingPlatform.runUntilIdle(); \
}
TEST_F(RecordingImageBufferSurfaceTest, testEmptyPicture) {
testEmptyPicture();
}
TEST_F(RecordingImageBufferSurfaceTest, testNoFallbackWithClear) {
testNoFallbackWithClear();
}
TEST_F(RecordingImageBufferSurfaceTest, testNonAnimatedCanvasUpdate) {
CALL_TEST_TASK_WRAPPER(testNonAnimatedCanvasUpdate)
expectDisplayListEnabled(true);
}
TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithoutClear) {
CALL_TEST_TASK_WRAPPER(testAnimatedWithoutClear)
expectDisplayListEnabled(false);
}
TEST_F(RecordingImageBufferSurfaceTest, testFrameFinalizedByTaskObserver) {
CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver1)
expectDisplayListEnabled(false);
CALL_TEST_TASK_WRAPPER(testFrameFinalizedByTaskObserver2)
expectDisplayListEnabled(false);
}
TEST_F(RecordingImageBufferSurfaceTest, testAnimatedWithClear) {
CALL_TEST_TASK_WRAPPER(testAnimatedWithClear)
expectDisplayListEnabled(true);
}
TEST_F(RecordingImageBufferSurfaceTest, testClearRect) {
CALL_TEST_TASK_WRAPPER(testClearRect);
expectDisplayListEnabled(true);
}
} // namespace blink