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

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: adding missing test file 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
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..0c351fc463749a75954b0b5c2f25a2fe2d58afcc
--- /dev/null
+++ b/Source/core/html/canvas/CanvasRenderingContext2DTest.cpp
@@ -0,0 +1,262 @@
+// 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 {
+
+class CanvasRenderingContext2DTest : public ::testing::Test {
+protected:
+ 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;
+};
+
+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"));
+}
+
+//============================================================================
+
+class PLATFORM_EXPORT 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_OVERWRITE_SETUP(EXPECTED_OVERWRITES) \
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 Throughout this test file, would it make sense to
Justin Novosad 2015/02/11 18:59:54 Done.
+ OwnPtr<MockImageBufferSurfaceForOverwriteTesting> mockSurface = adoptPtr(new MockImageBufferSurfaceForOverwriteTesting(IntSize(10, 10), NonOpaque)); \
+ MockImageBufferSurfaceForOverwriteTesting* surfacePtr = mockSurface.get(); \
+ canvasElement().createImageBufferUsingSurface(mockSurface.release()); \
+ EXPECT_CALL(*surfacePtr, willOverwriteCanvas()).Times(EXPECTED_OVERWRITES); \
+ context2d()->save();
+
+#define TEST_OVERWRITE_FINALIZE \
+ context2d()->restore(); \
+ Mock::VerifyAndClearExpectations(surfacePtr);
+
+#define TEST_OVERWRITE_1(EXPECTED_OVERWRITES, CALL1) \
+ do { \
+ TEST_OVERWRITE_SETUP(EXPECTED_OVERWRITES) \
+ context2d()->CALL1; \
+ TEST_OVERWRITE_FINALIZE \
+ } while (0)
+
+#define TEST_OVERWRITE_2(EXPECTED_OVERWRITES, CALL1, CALL2) \
+ do { \
+ TEST_OVERWRITE_SETUP(EXPECTED_OVERWRITES) \
+ context2d()->CALL1; \
+ context2d()->CALL2; \
+ TEST_OVERWRITE_FINALIZE \
+ } while (0)
+
+#define TEST_OVERWRITE_3(EXPECTED_OVERWRITES, CALL1, CALL2, CALL3) \
+ do { \
+ TEST_OVERWRITE_SETUP(EXPECTED_OVERWRITES) \
+ context2d()->CALL1; \
+ context2d()->CALL2; \
+ context2d()->CALL3; \
+ TEST_OVERWRITE_FINALIZE \
+ } while (0)
+
+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;
+}
+
+//============================================================================
+
+TEST_F(CanvasRenderingContext2DTest, detectOverwrite)
dshwang 2015/02/11 08:37:52 nice test!
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 Consider splitting up this test into a few so it's
Justin Novosad 2015/02/11 18:59:54 Done.
+{
+ RefPtrWillBeRawPtr<ImageData> fullImageData = ImageData::create(IntSize(10, 10));
+ RefPtrWillBeRawPtr<ImageData> partialImageData = ImageData::create(IntSize(2, 2));
+ FakeImageSource opaqueBitmap(IntSize(10, 10), OpaqueBitmap);
+ FakeImageSource alphaBitmap(IntSize(10, 10), TransparentBitmap);
+ 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());
+ StringOrCanvasGradientOrCanvasPattern wrappedOpaqueGradient;
+ wrappedOpaqueGradient.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;
+ wrappedAlphaGradient.setCanvasGradient(alphaGradient);
+
+ createContext(NonOpaque);
+
+ // Test fillRect
+ TEST_OVERWRITE_1(1, fillRect(-1, -1, 12, 12));
+ TEST_OVERWRITE_1(1, fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_1(0, strokeRect(0, 0, 10, 10)); // stroking instead of filling does not overwrite
+ TEST_OVERWRITE_2(0, setGlobalAlpha(0.5f), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_1(0, fillRect(0, 0, 9, 9));
+ TEST_OVERWRITE_2(0, translate(1, 1), fillRect(0, 0, 10, 10));
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 Also test transformed rects that would still overd
Justin Novosad 2015/02/11 18:59:54 Done.
+ TEST_OVERWRITE_2(1, setFillStyle(wrappedOpaqueGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(0, setFillStyle(wrappedAlphaGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_3(0, setGlobalAlpha(0.5), setFillStyle(wrappedOpaqueGradient), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 9, 9));
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 I don't understand why setting the globalComposite
Justin Novosad 2015/02/11 18:59:54 Close. The way the spec defines the behavior: prim
+ TEST_OVERWRITE_3(0, rect(0, 0, 5, 5), clip(), fillRect(0, 0, 10, 10));
+
+ // Test clearRect
+ TEST_OVERWRITE_1(1, clearRect(0, 0, 10, 10));
+ TEST_OVERWRITE_1(0, clearRect(0, 0, 9, 9));
+ TEST_OVERWRITE_2(1, setGlobalAlpha(0.5f), clearRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(1, setFillStyle(wrappedAlphaGradient), clearRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("destination-in")), clearRect(0, 0, 10, 10));
+ TEST_OVERWRITE_3(0, rect(0, 0, 5, 5), clip(), clearRect(0, 0, 10, 10));
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 What about transforms in conjunction with clearRec
Justin Novosad 2015/02/11 18:59:54 Done.
+
+ // Test drawImage
+ TEST_OVERWRITE_1(1, drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_1(1, drawImage(&opaqueBitmap, 0, 0, 1, 1, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(0, setGlobalAlpha(0.5f), drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_1(0, drawImage(&alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(0, setGlobalAlpha(0.5f), drawImage(&alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_1(0, drawImage(&opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_1(0, drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 9, 9, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_1(1, drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 11, 11, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(1, translate(-1, 0), drawImage(&opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
Ken Russell (switch to Gerrit) 2015/02/11 10:11:44 Should also test the case where a transform makes
Justin Novosad 2015/02/11 18:59:54 Done.
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(0, setFillStyle(wrappedOpaqueGradient), drawImage(&alphaBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState)); // fillStyle ignored by drawImage
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(1, setFillStyle(wrappedAlphaGradient), drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState)); // fillStyle ignored by drawImage
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("copy")), drawImage(&opaqueBitmap, 0, 0, 10, 10, 1, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+ TEST_OVERWRITE_3(0, rect(0, 0, 5, 5), clip(), drawImage(&opaqueBitmap, 0, 0, 10, 10, 0, 0, 10, 10, exceptionState));
+ EXPECT_FALSE(exceptionState.hadException());
+
+ // Test putImageData
+ TEST_OVERWRITE_1(1, putImageData(fullImageData.get(), 0, 0));
+ TEST_OVERWRITE_1(1, putImageData(fullImageData.get(), 0, 0, 0, 0, 10, 10));
+ TEST_OVERWRITE_1(0, putImageData(fullImageData.get(), 0, 0, 1, 1, 8, 8));
+ TEST_OVERWRITE_2(1, setGlobalAlpha(0.5f), putImageData(fullImageData.get(), 0, 0)); // alpha has no effect
+ TEST_OVERWRITE_1(0, putImageData(partialImageData.get(), 0, 0));
+ TEST_OVERWRITE_2(1, translate(1, 1), putImageData(fullImageData.get(), 0, 0)); // ignores tranforms
+ TEST_OVERWRITE_1(0, putImageData(fullImageData.get(), 1, 0));
+ TEST_OVERWRITE_3(1, rect(0, 0, 5, 5), clip(), putImageData(fullImageData.get(), 0, 0)); // ignores clip
+
+ // 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_OVERWRITE_2(1, setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_2(0, setGlobalCompositeOperation(String("source-in")), fillRect(0, 0, 10, 10));
+ // Test composite operators with a transparent rect that covers the entire canvas
+ TEST_OVERWRITE_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_3(1, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_3(0, setGlobalAlpha(0.5f), setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 10, 10));
+ TEST_OVERWRITE_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_OVERWRITE_2(0, setGlobalCompositeOperation(String("clear")), fillRect(0, 0, 5, 5));
+ TEST_OVERWRITE_2(1, setGlobalCompositeOperation(String("copy")), fillRect(0, 0, 5, 5));
+ TEST_OVERWRITE_2(0, setGlobalCompositeOperation(String("source-over")), fillRect(0, 0, 5, 5));
+ TEST_OVERWRITE_2(0, setGlobalCompositeOperation(String("source-in")), fillRect(0, 0, 5, 5));
+}
+
+} // unnamed namespace

Powered by Google App Engine
This is Rietveld 408576698