Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(950)

Unified Diff: Source/core/html/canvas/CanvasRenderingContext2DTest.cpp

Issue 907453003: Move overdraw tracking code from GraphicsContext to CanvasRenderingContext2D (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix test copypasta Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/html/canvas/CanvasRenderingContext2D.cpp ('k') | Source/platform/blink_platform.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/html/canvas/CanvasRenderingContext2DTest.cpp
diff --git a/Source/core/html/canvas/CanvasRenderingContext2DTest.cpp b/Source/core/html/canvas/CanvasRenderingContext2DTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8bc582383fafb77ec52fcb2bf4ff3c4200cff95a
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext2DTest.cpp
@@ -0,0 +1,308 @@
+// 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 "config.h"
+
+#include "core/html/canvas/CanvasRenderingContext2D.h"
+
+#include "core/frame/FrameView.h"
+#include "core/html/HTMLDocument.h"
+#include "core/html/ImageData.h"
+#include "core/html/canvas/CanvasGradient.h"
+#include "core/html/canvas/CanvasPattern.h"
+#include "core/html/canvas/WebGLRenderingContext.h"
+#include "core/loader/EmptyClients.h"
+#include "core/testing/DummyPageHolder.h"
+#include "platform/graphics/StaticBitmapImage.h"
+#include "platform/graphics/UnacceleratedImageBufferSurface.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace blink;
+using ::testing::Mock;
+
+namespace {
+
+enum BitmapOpacity {
+ OpaqueBitmap,
+ TransparentBitmap
+};
+
+class FakeImageSource : public CanvasImageSource {
+public:
+ FakeImageSource(IntSize, BitmapOpacity);
+
+ PassRefPtr<Image> getSourceImageForCanvas(SourceImageMode, SourceImageStatus*) const override;
+
+ bool wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const override { return false; }
+ FloatSize sourceSize() const override { return FloatSize(m_size); }
+ bool isOpaque() const override { return m_isOpaque; }
+
+ virtual ~FakeImageSource() { }
+
+private:
+ IntSize m_size;
+ RefPtr<Image> m_image;
+ bool m_isOpaque;
+};
+
+FakeImageSource::FakeImageSource(IntSize size, BitmapOpacity opacity)
+ : m_size(size)
+ , m_isOpaque(opacity == OpaqueBitmap)
+{
+ SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(m_size.width(), m_size.height()));
+ surface->getCanvas()->clear(opacity == OpaqueBitmap ? SK_ColorWHITE : SK_ColorTRANSPARENT);
+ RefPtr<SkImage> image = adoptRef(surface->newImageSnapshot());
+ m_image = StaticBitmapImage::create(image);
+}
+
+PassRefPtr<Image> FakeImageSource::getSourceImageForCanvas(SourceImageMode, SourceImageStatus* status) const
+{
+ if (status)
+ *status = NormalSourceImageStatus;
+ return m_image;
+}
+
+//============================================================================
+
+class CanvasRenderingContext2DTest : public ::testing::Test {
+protected:
+ CanvasRenderingContext2DTest();
+ virtual void SetUp() override;
+
+ DummyPageHolder& page() const { return *m_dummyPageHolder; }
+ HTMLDocument& document() const { return *m_document; }
+ HTMLCanvasElement& canvasElement() const { return *m_canvasElement; }
+ CanvasRenderingContext2D* context2d() const { return static_cast<CanvasRenderingContext2D*>(canvasElement().renderingContext()); }
+
+ void createContext(OpacityMode);
+
+private:
+ OwnPtr<DummyPageHolder> m_dummyPageHolder;
+ RefPtrWillBePersistent<HTMLDocument> m_document;
+ RefPtrWillBePersistent<HTMLCanvasElement> m_canvasElement;
+
+protected:
+ // Pre-canned objects for testing
+ RefPtrWillBePersistent<ImageData> m_fullImageData;
+ RefPtrWillBePersistent<ImageData> m_partialImageData;
+ FakeImageSource m_opaqueBitmap;
+ FakeImageSource m_alphaBitmap;
+ StringOrCanvasGradientOrCanvasPattern m_opaqueGradient;
+ StringOrCanvasGradientOrCanvasPattern m_alphaGradient;
+};
+
+CanvasRenderingContext2DTest::CanvasRenderingContext2DTest()
+ : m_opaqueBitmap(IntSize(10, 10), OpaqueBitmap)
+ , m_alphaBitmap(IntSize(10, 10), TransparentBitmap)
+{ }
+
+void CanvasRenderingContext2DTest::createContext(OpacityMode opacityMode)
+{
+ String canvasType("2d");
+ CanvasContextCreationAttributes attributes;
+ attributes.setAlpha(opacityMode == NonOpaque);
+ CanvasRenderingContext2DOrWebGLRenderingContext result;
+ m_canvasElement->getContext(canvasType, attributes, result);
+}
+
+void CanvasRenderingContext2DTest::SetUp()
+{
+ Page::PageClients pageClients;
+ fillWithEmptyClients(pageClients);
+ m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600), &pageClients);
+ m_document = toHTMLDocument(&m_dummyPageHolder->document());
+ m_document->documentElement()->setInnerHTML("<body><canvas id='c'></canvas></body>", ASSERT_NO_EXCEPTION);
+ m_document->view()->updateLayoutAndStyleIfNeededRecursive();
+ m_canvasElement = toHTMLCanvasElement(m_document->getElementById("c"));
+
+ m_fullImageData = ImageData::create(IntSize(10, 10));
+ m_partialImageData = ImageData::create(IntSize(2, 2));
+
+ NonThrowableExceptionState exceptionState;
+ RefPtrWillBeRawPtr<CanvasGradient> opaqueGradient = CanvasGradient::create(FloatPoint(0, 0), FloatPoint(10, 0));
+ opaqueGradient->addColorStop(0, String("green"), exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ opaqueGradient->addColorStop(1, String("blue"), exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ m_opaqueGradient.setCanvasGradient(opaqueGradient);
+
+ RefPtrWillBeRawPtr<CanvasGradient> alphaGradient = CanvasGradient::create(FloatPoint(0, 0), FloatPoint(10, 0));
+ alphaGradient->addColorStop(0, String("green"), exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ alphaGradient->addColorStop(1, String("rgba(0, 0, 255, 0.5)"), exceptionState);
+ EXPECT_FALSE(exceptionState.hadException());
+ StringOrCanvasGradientOrCanvasPattern wrappedAlphaGradient;
+ m_alphaGradient.setCanvasGradient(alphaGradient);
+}
+
+//============================================================================
+
+class MockImageBufferSurfaceForOverwriteTesting : public UnacceleratedImageBufferSurface {
+public:
+ MockImageBufferSurfaceForOverwriteTesting(const IntSize& size, OpacityMode mode) : UnacceleratedImageBufferSurface(size, mode) { }
+ virtual ~MockImageBufferSurfaceForOverwriteTesting() { }
+ bool isRecording() const override { return true; } // otherwise overwrites are not tracked
+
+ MOCK_METHOD0(willOverwriteCanvas, void());
+};
+
+//============================================================================
+
+#define TEST_OVERDRAW_SETUP(EXPECTED_OVERDRAWS) \
+ OwnPtr<MockImageBufferSurfaceForOverwriteTesting> mockSurface = adoptPtr(new MockImageBufferSurfaceForOverwriteTesting(IntSize(10, 10), NonOpaque)); \
+ MockImageBufferSurfaceForOverwriteTesting* surfacePtr = mockSurface.get(); \
+ canvasElement().createImageBufferUsingSurface(mockSurface.release()); \
+ EXPECT_CALL(*surfacePtr, willOverwriteCanvas()).Times(EXPECTED_OVERDRAWS); \
+ context2d()->save();
+
+#define TEST_OVERDRAW_FINALIZE \
+ context2d()->restore(); \
+ Mock::VerifyAndClearExpectations(surfacePtr);
+
+#define TEST_OVERDRAW_1(EXPECTED_OVERDRAWS, CALL1) \
+ do { \
+ TEST_OVERDRAW_SETUP(EXPECTED_OVERDRAWS) \
+ context2d()->CALL1; \
+ TEST_OVERDRAW_FINALIZE \
+ } while (0)
+
+#define TEST_OVERDRAW_2(EXPECTED_OVERDRAWS, CALL1, CALL2) \
+ do { \
+ TEST_OVERDRAW_SETUP(EXPECTED_OVERDRAWS) \
+ context2d()->CALL1; \
+ context2d()->CALL2; \
+ TEST_OVERDRAW_FINALIZE \
+ } while (0)
+
+#define TEST_OVERDRAW_3(EXPECTED_OVERDRAWS, CALL1, CALL2, CALL3) \
+ do { \
+ TEST_OVERDRAW_SETUP(EXPECTED_OVERDRAWS) \
+ context2d()->CALL1; \
+ context2d()->CALL2; \
+ context2d()->CALL3; \
+ TEST_OVERDRAW_FINALIZE \
+ } while (0)
+
+#define TEST_OVERDRAW_4(EXPECTED_OVERDRAWS, CALL1, CALL2, CALL3, CALL4) \
+ do { \
+ TEST_OVERDRAW_SETUP(EXPECTED_OVERDRAWS) \
+ context2d()->CALL1; \
+ context2d()->CALL2; \
+ context2d()->CALL3; \
+ context2d()->CALL4; \
+ TEST_OVERDRAW_FINALIZE \
+ } while (0)
+
+//============================================================================
+
+TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithFillRect)
+{
+ createContext(NonOpaque);
+
+ TEST_OVERDRAW_1(1, fillRect(-1, -1, 12, 12));
+ TEST_OVERDRAW_1(1, fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_1(0, strokeRect(0, 0, 10, 10)); // stroking instead of filling does not overwrite
+ TEST_OVERDRAW_2(0, setGlobalAlpha(0.5f), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_1(0, fillRect(0, 0, 9, 9));
+ TEST_OVERDRAW_2(0, translate(1, 1), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, translate(1, 1), fillRect(-1, -1, 10, 10));
+ TEST_OVERDRAW_2(1, setFillStyle(m_opaqueGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(0, setFillStyle(m_alphaGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_3(0, setGlobalAlpha(0.5), setFillStyle(m_opaqueGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 9, 9));
+ TEST_OVERDRAW_3(0, rect(0, 0, 5, 5), clip(), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_4(0, rect(0, 0, 5, 5), clip(), setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+}
+
+TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithClearRect)
+{
+ createContext(NonOpaque);
+
+ TEST_OVERDRAW_1(1, clearRect(0, 0, 10, 10));
+ TEST_OVERDRAW_1(0, clearRect(0, 0, 9, 9));
+ TEST_OVERDRAW_2(1, setGlobalAlpha(0.5f), clearRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, setFillStyle(m_alphaGradient), clearRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(0, translate(1, 1), clearRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, translate(1, 1), clearRect(-1, -1, 10, 10));
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("destination-in")), clearRect(0, 0, 10, 10)); // composite op ignored
+ TEST_OVERDRAW_3(0, rect(0, 0, 5, 5), clip(), clearRect(0, 0, 10, 10));
+}
+
+TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithDrawImage)
+{
+ createContext(NonOpaque);
+ NonThrowableExceptionState exceptionState;
+
+ TEST_OVERDRAW_1(1, drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_1(1, drawImage(&m_opaqueBitmap, 0, 0, 1, 1, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(0, setGlobalAlpha(0.5f), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_1(0, drawImage(&m_alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(0, setGlobalAlpha(0.5f), drawImage(&m_alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_1(0, drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_1(0, drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 9, 9, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_1(1, drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 11, 11, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(1, translate(-1, 0), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(0, translate(-1, 0), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(0, setFillStyle(m_opaqueGradient), drawImage(&m_alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState)); // fillStyle ignored by drawImage
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(1, setFillStyle(m_alphaGradient), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState)); // fillStyle ignored by drawImage
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("copy")), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERDRAW_3(0, rect(0, 0, 5, 5), clip(), drawImage(&m_opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+}
+
+TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithPutImageData)
+{
+ createContext(NonOpaque);
+
+ // Test putImageData
+ TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0));
+ TEST_OVERDRAW_1(1, putImageData(m_fullImageData.get(), 0, 0, 0, 0, 10, 10));
+ TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 0, 0, 1, 1, 8, 8));
+ TEST_OVERDRAW_2(1, setGlobalAlpha(0.5f), putImageData(m_fullImageData.get(), 0, 0)); // alpha has no effect
+ TEST_OVERDRAW_1(0, putImageData(m_partialImageData.get(), 0, 0));
+ TEST_OVERDRAW_2(1, translate(1, 1), putImageData(m_fullImageData.get(), 0, 0)); // ignores tranforms
+ TEST_OVERDRAW_1(0, putImageData(m_fullImageData.get(), 1, 0));
+ TEST_OVERDRAW_3(1, rect(0, 0, 5, 5), clip(), putImageData(m_fullImageData.get(), 0, 0)); // ignores clip
+}
+
+TEST_F(CanvasRenderingContext2DTest, detectOverdrawWithCompositeOperations)
+{
+ createContext(NonOpaque);
+
+ // Test composite operators with an opaque rect that covers the entire canvas
+ // Note: all the untested composite operations take the same code path as source-in,
+ // which assumes that the destination may not be overwritten
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_2(0, setGlobalCompositeOperation(String("source-in")), fillRect(0, 0, 10, 10));
+ // Test composite operators with a transparent rect that covers the entire canvas
+ TEST_OVERDRAW_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_3(0, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 10, 10));
+ TEST_OVERDRAW_3(0, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("source-in")), fillRect(0, 0, 10, 10));
+ // Test composite operators with an opaque rect that does not cover the entire canvas
+ TEST_OVERDRAW_2(0, setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 5, 5));
+ TEST_OVERDRAW_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 5, 5));
+ TEST_OVERDRAW_2(0, setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 5, 5));
+ TEST_OVERDRAW_2(0, setGlobalCompositeOperation(String("source-in")), fillRect(0, 0, 5, 5));
+}
+
+} // unnamed namespace
« no previous file with comments | « Source/core/html/canvas/CanvasRenderingContext2D.cpp ('k') | Source/platform/blink_platform.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698