summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp339
1 files changed, 339 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp
new file mode 100644
index 00000000000..a2f6b0c5da0
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "platform/graphics/Canvas2DLayerManager.h"
+
+#include "SkDevice.h"
+#include "SkSurface.h"
+#include "platform/graphics/test/MockWebGraphicsContext3D.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebGraphicsContext3DProvider.h"
+#include "public/platform/WebThread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+using testing::InSequence;
+using testing::Return;
+using testing::Test;
+
+namespace {
+
+class MockWebGraphicsContext3DProvider : public blink::WebGraphicsContext3DProvider {
+public:
+ MockWebGraphicsContext3DProvider(blink::WebGraphicsContext3D* context3d)
+ : m_context3d(context3d) { }
+
+ blink::WebGraphicsContext3D* context3d()
+ {
+ return m_context3d;
+ }
+
+ GrContext* grContext()
+ {
+ return 0;
+ }
+
+private:
+ blink::WebGraphicsContext3D* m_context3d;
+};
+
+class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge {
+public:
+ FakeCanvas2DLayerBridge(blink::WebGraphicsContext3D* context, PassOwnPtr<SkDeferredCanvas> canvas)
+ : Canvas2DLayerBridge(adoptPtr(new MockWebGraphicsContext3DProvider(context)), canvas, 0, NonOpaque)
+ , m_freeableBytes(0)
+ , m_freeMemoryIfPossibleCount(0)
+ , m_flushCount(0)
+ {
+ }
+
+ virtual size_t storageAllocatedForRecording() OVERRIDE
+ {
+ // Because the fake layer has no canvas to query, just
+ // return status quo. Allocation changes that would normally be
+ // initiated by the canvas can be faked by invoking
+ // storageAllocatedForRecordingChanged directly from the test code.
+ return m_bytesAllocated;
+ }
+
+ void fakeFreeableBytes(size_t size)
+ {
+ m_freeableBytes = size;
+ }
+
+ virtual size_t freeMemoryIfPossible(size_t size) OVERRIDE
+ {
+ m_freeMemoryIfPossibleCount++;
+ size_t bytesFreed = size < m_freeableBytes ? size : m_freeableBytes;
+ m_freeableBytes -= bytesFreed;
+ if (bytesFreed)
+ storageAllocatedForRecordingChanged(m_bytesAllocated - bytesFreed);
+ return bytesFreed;
+ }
+
+ virtual void flush() OVERRIDE
+ {
+ flushedDrawCommands();
+ m_freeableBytes = bytesAllocated();
+ m_flushCount++;
+ }
+
+public:
+ size_t m_freeableBytes;
+ int m_freeMemoryIfPossibleCount;
+ int m_flushCount;
+};
+
+class FakeCanvas2DLayerBridgePtr {
+public:
+ FakeCanvas2DLayerBridgePtr(PassRefPtr<FakeCanvas2DLayerBridge> layerBridge)
+ : m_layerBridge(layerBridge) { }
+
+ ~FakeCanvas2DLayerBridgePtr()
+ {
+ m_layerBridge->beginDestruction();
+ }
+
+ FakeCanvas2DLayerBridge* operator->() { return m_layerBridge.get(); }
+ FakeCanvas2DLayerBridge* get() { return m_layerBridge.get(); }
+
+private:
+ RefPtr<FakeCanvas2DLayerBridge> m_layerBridge;
+};
+
+static PassOwnPtr<SkDeferredCanvas> createCanvas()
+{
+ RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(1, 1));
+ return adoptPtr(SkDeferredCanvas::Create(surface.get()));
+}
+
+} // unnamed namespace
+
+class Canvas2DLayerManagerTest : public Test {
+protected:
+ void storageAllocationTrackingTest()
+ {
+ Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
+ manager.init(10, 10);
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ OwnPtr<SkDeferredCanvas> canvas1 = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer1(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas1.release())));
+ EXPECT_EQ((size_t)0, manager.m_bytesAllocated);
+ layer1->storageAllocatedForRecordingChanged(1);
+ EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
+ // Test allocation increase
+ layer1->storageAllocatedForRecordingChanged(2);
+ EXPECT_EQ((size_t)2, manager.m_bytesAllocated);
+ // Test allocation decrease
+ layer1->storageAllocatedForRecordingChanged(1);
+ EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
+ {
+ OwnPtr<SkDeferredCanvas> canvas2 = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer2(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas2.release())));
+ EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
+ // verify multi-layer allocation tracking
+ layer2->storageAllocatedForRecordingChanged(2);
+ EXPECT_EQ((size_t)3, manager.m_bytesAllocated);
+ }
+ // Verify tracking after destruction
+ EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
+ }
+ }
+
+ void evictionTest()
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
+ manager.init(10, 5);
+ OwnPtr<SkDeferredCanvas> canvas = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release())));
+ layer->fakeFreeableBytes(10);
+ layer->storageAllocatedForRecordingChanged(8); // under the max
+ EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount);
+ layer->storageAllocatedForRecordingChanged(12); // over the max
+ EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount);
+ EXPECT_EQ((size_t)3, layer->m_freeableBytes);
+ EXPECT_EQ(0, layer->m_flushCount); // eviction succeeded without triggering a flush
+ EXPECT_EQ((size_t)5, layer->bytesAllocated());
+ }
+
+ void hiddenCanvasTest()
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
+ manager.init(20, 5);
+ OwnPtr<SkDeferredCanvas> canvas = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release())));
+ layer->fakeFreeableBytes(5);
+ layer->storageAllocatedForRecordingChanged(10);
+ EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount);
+ EXPECT_EQ(0, layer->m_flushCount);
+ EXPECT_EQ((size_t)10, layer->bytesAllocated());
+ layer->setIsHidden(true);
+ EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount);
+ EXPECT_EQ((size_t)0, layer->m_freeableBytes);
+ EXPECT_EQ((size_t)0, layer->bytesAllocated());
+ EXPECT_EQ(1, layer->m_flushCount);
+ }
+
+ void addRemoveLayerTest()
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
+ manager.init(10, 5);
+ OwnPtr<SkDeferredCanvas> canvas = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release())));
+ EXPECT_FALSE(manager.isInList(layer.get()));
+ layer->storageAllocatedForRecordingChanged(5);
+ EXPECT_TRUE(manager.isInList(layer.get()));
+ layer->storageAllocatedForRecordingChanged(0);
+ EXPECT_FALSE(manager.isInList(layer.get()));
+ }
+
+ void flushEvictionTest()
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
+ manager.init(10, 5);
+ OwnPtr<SkDeferredCanvas> canvas = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release())));
+ layer->fakeFreeableBytes(1); // Not enough freeable bytes, will cause aggressive eviction by flushing
+ layer->storageAllocatedForRecordingChanged(8); // under the max
+ EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount);
+ layer->storageAllocatedForRecordingChanged(12); // over the max
+ EXPECT_EQ(2, layer->m_freeMemoryIfPossibleCount); // Two tries, one before flush, one after flush
+ EXPECT_EQ((size_t)5, layer->m_freeableBytes);
+ EXPECT_EQ(1, layer->m_flushCount); // flush was attempted
+ EXPECT_EQ((size_t)5, layer->bytesAllocated());
+ EXPECT_TRUE(manager.isInList(layer.get()));
+ }
+
+ void doDeferredFrameTestTask(FakeCanvas2DLayerBridge* layer, bool skipCommands)
+ {
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ layer->willUse();
+ layer->storageAllocatedForRecordingChanged(1);
+ EXPECT_TRUE(Canvas2DLayerManager::get().m_taskObserverActive);
+ if (skipCommands) {
+ layer->willUse();
+ layer->skippedPendingDrawCommands();
+ }
+ blink::Platform::current()->currentThread()->exitRunLoop();
+ }
+
+ class DeferredFrameTestTask : public blink::WebThread::Task {
+ public:
+ DeferredFrameTestTask(Canvas2DLayerManagerTest* test, FakeCanvas2DLayerBridge* layer, bool skipCommands)
+ {
+ m_test = test;
+ m_layer = layer;
+ m_skipCommands = skipCommands;
+ }
+
+ virtual void run() OVERRIDE
+ {
+ m_test->doDeferredFrameTestTask(m_layer, m_skipCommands);
+ }
+ private:
+ Canvas2DLayerManagerTest* m_test;
+ FakeCanvas2DLayerBridge* m_layer;
+ bool m_skipCommands;
+ };
+
+ void deferredFrameTest()
+ {
+ OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink::MockWebGraphicsContext3D);
+ Canvas2DLayerManager::get().init(10, 10);
+ OwnPtr<SkDeferredCanvas> canvas = createCanvas();
+ FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(webContext.get(), canvas.release())));
+ blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true));
+ blink::Platform::current()->currentThread()->enterRunLoop();
+ // Verify that didProcessTask was called upon completion
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ // Verify that no flush was performed because frame is fresh
+ EXPECT_EQ(0, layer->m_flushCount);
+
+ // Verify that no flushes are triggered as long as frame are fresh
+ blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true));
+ blink::Platform::current()->currentThread()->enterRunLoop();
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ EXPECT_EQ(0, layer->m_flushCount);
+
+ blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), true));
+ blink::Platform::current()->currentThread()->enterRunLoop();
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ EXPECT_EQ(0, layer->m_flushCount);
+
+ // Verify that a flush is triggered when queue is accumulating a multi-frame backlog.
+ blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), false));
+ blink::Platform::current()->currentThread()->enterRunLoop();
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ EXPECT_EQ(1, layer->m_flushCount);
+
+ blink::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, layer.get(), false));
+ blink::Platform::current()->currentThread()->enterRunLoop();
+ EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
+ EXPECT_EQ(2, layer->m_flushCount);
+ }
+};
+
+namespace {
+
+TEST_F(Canvas2DLayerManagerTest, testStorageAllocationTracking)
+{
+ storageAllocationTrackingTest();
+}
+
+TEST_F(Canvas2DLayerManagerTest, testEviction)
+{
+ evictionTest();
+}
+
+TEST_F(Canvas2DLayerManagerTest, testFlushEviction)
+{
+ flushEvictionTest();
+}
+
+TEST_F(Canvas2DLayerManagerTest, testDeferredFrame)
+{
+ deferredFrameTest();
+}
+
+TEST_F(Canvas2DLayerManagerTest, testHiddenCanvas)
+{
+ hiddenCanvasTest();
+}
+
+TEST_F(Canvas2DLayerManagerTest, testAddRemoveLayer)
+{
+ addRemoveLayerTest();
+}
+
+} // unnamed namespace
+