diff options
author | Derek Sollenberger <djsollen@google.com> | 2012-03-06 09:06:43 -0500 |
---|---|---|
committer | Derek Sollenberger <derek@android.com> | 2012-03-06 09:44:47 -0500 |
commit | 4f1dae40e24d57d647db01443b8bf2410514b8b5 (patch) | |
tree | 594df3f3fc6c1d90a76691a75763ae1beacfdf98 /tests | |
parent | 1cab2921ab279367f8206cdadc9259d12e603548 (diff) | |
download | external_skia-4f1dae40e24d57d647db01443b8bf2410514b8b5.zip external_skia-4f1dae40e24d57d647db01443b8bf2410514b8b5.tar.gz external_skia-4f1dae40e24d57d647db01443b8bf2410514b8b5.tar.bz2 |
Skia Merge (revision 3312)
This CL also includes changes made to Android's copy of
Skia in their J release branch.
Change-Id: Ib2baecf48004951a3ad4a1574cdc38790c814cbc
Diffstat (limited to 'tests')
-rw-r--r-- | tests/AAClipTest.cpp | 53 | ||||
-rw-r--r-- | tests/Android.mk | 4 | ||||
-rw-r--r-- | tests/BitmapCopyTest.cpp | 11 | ||||
-rw-r--r-- | tests/CanvasTest.cpp | 781 | ||||
-rw-r--r-- | tests/ClipCubicTest.cpp | 20 | ||||
-rw-r--r-- | tests/ColorTest.cpp | 42 | ||||
-rw-r--r-- | tests/DeferredCanvasTest.cpp | 187 | ||||
-rw-r--r-- | tests/DrawPathTest.cpp | 46 | ||||
-rw-r--r-- | tests/DrawTextTest.cpp | 115 | ||||
-rw-r--r-- | tests/FontHostTest.cpp | 95 | ||||
-rwxr-xr-x | tests/GLInterfaceValidation.cpp | 12 | ||||
-rw-r--r-- | tests/GLProgramsTest.cpp | 2 | ||||
-rw-r--r-- | tests/GeometryTest.cpp | 21 | ||||
-rw-r--r-- | tests/PathMeasureTest.cpp | 85 | ||||
-rw-r--r-- | tests/PathTest.cpp | 55 | ||||
-rw-r--r-- | tests/PremulAlphaRoundTripTest.cpp | 106 | ||||
-rw-r--r-- | tests/ReadPixelsTest.cpp | 2 | ||||
-rw-r--r-- | tests/Test.cpp | 2 | ||||
-rw-r--r-- | tests/Test.h | 11 | ||||
-rw-r--r-- | tests/WArrayTest.cpp | 6 | ||||
-rw-r--r-- | tests/WritePixelsTest.cpp | 9 |
21 files changed, 1600 insertions, 65 deletions
diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp index b3051fd..4f3f759 100644 --- a/tests/AAClipTest.cpp +++ b/tests/AAClipTest.cpp @@ -272,15 +272,68 @@ static void test_irect(skiatest::Reporter* reporter) { } REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW); REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds()); + + SkMask maskBW, maskAA; + copyToMask(rgn2, &maskBW); + clip2.copyToMask(&maskAA); + REPORTER_ASSERT(reporter, maskBW == maskAA); } } } +static void test_path_with_hole(skiatest::Reporter* reporter) { + static const uint8_t gExpectedImage[] = { + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + }; + SkMask expected; + expected.fBounds.set(0, 0, 4, 6); + expected.fRowBytes = 4; + expected.fFormat = SkMask::kA8_Format; + expected.fImage = (uint8_t*)gExpectedImage; + + SkPath path; + path.addRect(SkRect::MakeXYWH(0, 0, + SkIntToScalar(4), SkIntToScalar(2))); + path.addRect(SkRect::MakeXYWH(0, SkIntToScalar(4), + SkIntToScalar(4), SkIntToScalar(2))); + + for (int i = 0; i < 2; ++i) { + SkAAClip clip; + clip.setPath(path, NULL, 1 == i); + + SkMask mask; + clip.copyToMask(&mask); + + REPORTER_ASSERT(reporter, expected == mask); + } +} + +static void test_regressions(skiatest::Reporter* reporter) { + // these should not assert in the debug build + // bug was introduced in rev. 3209 + { + SkAAClip clip; + SkRect r; + r.fLeft = SkFloatToScalar(129.892181); + r.fTop = SkFloatToScalar(10.3999996); + r.fRight = SkFloatToScalar(130.892181); + r.fBottom = SkFloatToScalar(20.3999996); + clip.setRect(r, true); + } +} + static void TestAAClip(skiatest::Reporter* reporter) { test_empty(reporter); test_path_bounds(reporter); test_irect(reporter); test_rgn(reporter); + test_path_with_hole(reporter); + test_regressions(reporter); } #include "TestClassDef.h" diff --git a/tests/Android.mk b/tests/Android.mk index 14d23f8..8487699 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -16,11 +16,14 @@ LOCAL_SRC_FILES:= \ ColorFilterTest.cpp \ ColorTest.cpp \ DataRefTest.cpp \ + DeferredCanvasTest.cpp \ DequeTest.cpp \ DrawBitmapRectTest.cpp \ + DrawTextTest.cpp \ EmptyPathTest.cpp \ FillPathTest.cpp \ FlateTest.cpp \ + FontHostTest.cpp \ GeometryTest.cpp \ GLInterfaceValidation.cpp \ GLProgramsTest.cpp \ @@ -37,6 +40,7 @@ LOCAL_SRC_FILES:= \ PathMeasureTest.cpp \ PathTest.cpp \ PointTest.cpp \ + PremulAlphaRoundTripTest.cpp \ QuickRejectTest.cpp \ Reader32Test.cpp \ ReadPixelsTest.cpp \ diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp index b8d16bf..d5fd7df 100644 --- a/tests/BitmapCopyTest.cpp +++ b/tests/BitmapCopyTest.cpp @@ -308,12 +308,16 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { } // test extractSubset { + SkBitmap bitmap(src); SkBitmap subset; SkIRect r; r.set(1, 1, 2, 2); - if (src.extractSubset(&subset, r)) { + bitmap.setIsVolatile(true); + if (bitmap.extractSubset(&subset, r)) { REPORTER_ASSERT(reporter, subset.width() == 1); REPORTER_ASSERT(reporter, subset.height() == 1); + REPORTER_ASSERT(reporter, + subset.isVolatile() == true); SkBitmap copy; REPORTER_ASSERT(reporter, @@ -329,6 +333,11 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, (copy.getColorTable() != NULL) == hasCT); } + bitmap.setIsVolatile(false); + if (bitmap.extractSubset(&subset, r)) { + REPORTER_ASSERT(reporter, + subset.isVolatile() == false); + } } } else { // dst should be unchanged from its initial state diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index da1fafd..7cafda2 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -1,66 +1,759 @@ /* - * Copyright 2011 Google Inc. + * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#include "Test.h" + +/* Description: + * This test defines a series of elementatry test steps that perform + * a single or a small group of canvas API calls. Each test step is + * used in several test cases that verify that different types of SkCanvas + * flavors and derivatives pass it and yield consistent behavior. The + * test cases analyse results that are queryable through the API. They do + * not look at rendering results. + * + * Adding test stepss: + * The general pattern for creating a new test step is to write a test + * function of the form: + * + * static void MyTestStepFunction(SkCanvas* canvas, + * skiatest::Reporter* reporter, + * CanvasTestStep* testStep) + * { + * canvas->someCanvasAPImethod(); + * (...) + * REPORTER_ASSERT_MESSAGE(reporter, (...), \ + * testStep->assertMessage()); + * } + * + * The definition of the test step function should be followed by an + * invocation of the TEST_STEP macro, which generates a class and + * instance for the test step: + * + * TEST_STEP(MyTestStep, MyTestStepFunction) + * + * There are also short hand macros for defining simple test steps + * in a single line of code. A simple test step is a one that is made + * of a single canvas API call. + * + * SIMPLE_TEST_STEP(MytestStep, someCanvasAPIMethod()); + * + * There is another macro called SIMPLE_TEST_STEP_WITH_ASSERT that + * works the same way as SIMPLE_TEST_STEP, and additionally verifies + * that the invoked method returns a non-zero value. + */ #include "SkBitmap.h" #include "SkCanvas.h" +#include "SkDeferredCanvas.h" +#include "SkDevice.h" +#include "SkMatrix.h" +#include "SkNWayCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPicture.h" +#include "SkPictureRecord.h" +#include "SkProxyCanvas.h" +#include "SkRect.h" +#include "SkRegion.h" +#include "SkShader.h" +#include "SkStream.h" +#include "SkTDArray.h" +#include "Test.h" -static void test_isDrawingToLayer(skiatest::Reporter* reporter) { - SkBitmap bm; - bm.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); - bm.allocPixels(); - - SkCanvas canvas(bm); +static const int kWidth = 2; +static const int kHeight = 2; +// Maximum stream length for picture serialization +static const size_t kMaxPictureBufferSize = 1024; + +// Format strings that describe the test context. The %s token is where +// the name of the test step is inserted. The context is required for +// disambiguating the error in the case of failures that are reported in +// functions that are called multiple times in different contexts (test +// cases and test steps). +static const char* const kDefaultAssertMessageFormat = "%s"; +static const char* const kCanvasDrawAssertMessageFormat = + "Drawing test step %s with SkCanvas"; +static const char* const kPictureDrawAssertMessageFormat = + "Drawing test step %s with SkPicture"; +static const char* const kPictureSecondDrawAssertMessageFormat = + "Duplicate draw of test step %s with SkPicture"; +static const char* const kPictureReDrawAssertMessageFormat = + "Playing back test step %s from an SkPicture to another SkPicture"; +static const char* const kDeferredDrawAssertMessageFormat = + "Drawing test step %s with SkDeferredCanvas"; +static const char* const kProxyDrawAssertMessageFormat = + "Drawing test step %s with SkProxyCanvas"; +static const char* const kNWayDrawAssertMessageFormat = + "Drawing test step %s with SkNWayCanvas"; +static const char* const kRoundTripAssertMessageFormat = + "test step %s, SkPicture consistency after round trip"; +static const char* const kPictureRecoringAssertMessageFormat = + "test step %s, SkPicture state consistency after recording"; +static const char* const kPicturePlaybackAssertMessageFormat = + "test step %s, SkPicture state consistency in playback canvas"; +static const char* const kDeferredPreFlushAssertMessageFormat = + "test step %s, SkDeferredCanvas state consistency before flush"; +static const char* const kDeferredPostFlushAssertMessageFormat = + "test step %s, SkDeferredCanvas state consistency after flush"; +static const char* const kPictureResourceReuseMessageFormat = + "test step %s, SkPicture duplicate flattened object test"; +static const char* const kProxyStateAssertMessageFormat = + "test step %s, SkProxyCanvas state consistency"; +static const char* const kProxyIndirectStateAssertMessageFormat = + "test step %s, SkProxyCanvas indirect canvas state consistency"; +static const char* const kNWayStateAssertMessageFormat = + "test step %s, SkNWayCanvas state consistency"; +static const char* const kNWayIndirect1StateAssertMessageFormat = + "test step %s, SkNWayCanvas indirect canvas 1 state consistency"; +static const char* const kNWayIndirect2StateAssertMessageFormat = + "test step %s, SkNWayCanvas indirect canvas 2 state consistency"; + +static void createBitmap(SkBitmap* bm, SkBitmap::Config config, SkColor color) { + bm->setConfig(config, kWidth, kHeight); + bm->allocPixels(); + bm->eraseColor(color); +} + +class CanvasTestStep; +static SkTDArray<CanvasTestStep*>& testStepArray() { + static SkTDArray<CanvasTestStep*> theTests; + return theTests; +} + +class CanvasTestStep { +public: + CanvasTestStep() { + *testStepArray().append() = this; + fAssertMessageFormat = kDefaultAssertMessageFormat; + } + virtual ~CanvasTestStep() { } + + virtual void draw(SkCanvas*, skiatest::Reporter*) = 0; + virtual const char* name() const = 0; + + const char* assertMessage() { + fAssertMessage.printf(fAssertMessageFormat, name()); + return fAssertMessage.c_str(); + } + + void setAssertMessageFormat(const char* format) { + fAssertMessageFormat = format; + } + +private: + SkString fAssertMessage; + const char* fAssertMessageFormat; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Constants used by test steps + +const SkRect kTestRect = + SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(2), SkIntToScalar(1)); +static SkMatrix testMatrix() { + SkMatrix matrix; + matrix.reset(); + matrix.setScale(SkIntToScalar(2), SkIntToScalar(3)); + return matrix; +} +const SkMatrix kTestMatrix = testMatrix(); +static SkPath testPath() { + SkPath path; + path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(2), SkIntToScalar(1))); + return path; +} +const SkPath kTestPath = testPath(); +static SkRegion testRegion() { + SkRegion region; + SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1); + region.setRect(rect); + return region; +} +const SkIRect kTestIRect = SkIRect::MakeXYWH(0, 0, 2, 1); +const SkRegion kTestRegion = testRegion(); +const SkColor kTestColor = 0x01020304; +const SkPaint kTestPaint; +const SkPoint kTestPoints[3] = { + {SkIntToScalar(0), SkIntToScalar(0)}, + {SkIntToScalar(2), SkIntToScalar(1)}, + {SkIntToScalar(0), SkIntToScalar(2)} +}; +const size_t kTestPointCount = 3; +static SkBitmap testBitmap() { + SkBitmap bitmap; + createBitmap(&bitmap, SkBitmap::kARGB_8888_Config, 0x05060708); + return bitmap; +} +SkBitmap kTestBitmap; // cannot be created during static init +SkString kTestText("Hello World"); +SkPoint kTestPoint = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(1)); + +/////////////////////////////////////////////////////////////////////////////// +// Macros for defining test steps + +#define TEST_STEP(NAME, FUNCTION) \ +class NAME##_TestStep : public CanvasTestStep{ \ +public: \ + virtual void draw(SkCanvas* canvas, skiatest::Reporter* reporter) { \ + FUNCTION (canvas, reporter, this); \ + } \ + virtual const char* name() const {return #NAME ;} \ +}; \ +static NAME##_TestStep NAME##_TestStepInstance; + +#define SIMPLE_TEST_STEP(NAME, CALL) \ +static void NAME##TestStep(SkCanvas* canvas, skiatest::Reporter*, \ + CanvasTestStep*) { \ + canvas-> CALL ; \ +} \ +TEST_STEP(NAME, NAME##TestStep ) + +#define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL) \ +static void NAME##TestStep(SkCanvas* canvas, skiatest::Reporter* reporter, \ + CanvasTestStep* testStep) { \ + REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL , \ + testStep->assertMessage()); \ +} \ +TEST_STEP(NAME, NAME##TestStep ) + + +/////////////////////////////////////////////////////////////////////////////// +// Basic test steps for most virtual methods in SkCanvas that draw or affect +// the state of the canvas. + +SIMPLE_TEST_STEP(SaveMatrix, save(SkCanvas::kMatrix_SaveFlag)); +SIMPLE_TEST_STEP(SaveClip, save(SkCanvas::kClip_SaveFlag)); +SIMPLE_TEST_STEP(SaveMatrixClip, save(SkCanvas::kMatrixClip_SaveFlag)); +SIMPLE_TEST_STEP(SaveLayer, saveLayer(NULL, NULL)); +SIMPLE_TEST_STEP(BoundedSaveLayer, saveLayer(&kTestRect, NULL)); +SIMPLE_TEST_STEP(PaintSaveLayer, saveLayer(NULL, &kTestPaint)); +SIMPLE_TEST_STEP_WITH_ASSERT(Translate, + translate(SkIntToScalar(1), SkIntToScalar(2))); +SIMPLE_TEST_STEP_WITH_ASSERT(Scale, + scale(SkIntToScalar(1), SkIntToScalar(2))); +SIMPLE_TEST_STEP_WITH_ASSERT(Rotate, rotate(SkIntToScalar(1))); +SIMPLE_TEST_STEP_WITH_ASSERT(Skew, + skew(SkIntToScalar(1), SkIntToScalar(2))); +SIMPLE_TEST_STEP_WITH_ASSERT(Concat, concat(kTestMatrix)); +SIMPLE_TEST_STEP(SetMatrix, setMatrix(kTestMatrix)); +SIMPLE_TEST_STEP_WITH_ASSERT(ClipRect, clipRect(kTestRect)); +SIMPLE_TEST_STEP_WITH_ASSERT(ClipPath, clipPath(kTestPath)); +SIMPLE_TEST_STEP_WITH_ASSERT(ClipRegion, + clipRegion(kTestRegion, SkRegion::kReplace_Op)); +SIMPLE_TEST_STEP(Clear, clear(kTestColor)); +SIMPLE_TEST_STEP(DrawPaint, drawPaint(kTestPaint)); +SIMPLE_TEST_STEP(DrawPointsPoints, drawPoints(SkCanvas::kPoints_PointMode, + kTestPointCount, kTestPoints, kTestPaint)); +SIMPLE_TEST_STEP(DrawPointsLiness, drawPoints(SkCanvas::kLines_PointMode, + kTestPointCount, kTestPoints, kTestPaint)); +SIMPLE_TEST_STEP(DrawPointsPolygon, drawPoints(SkCanvas::kPolygon_PointMode, + kTestPointCount, kTestPoints, kTestPaint)); +SIMPLE_TEST_STEP(DrawRect, drawRect(kTestRect, kTestPaint)); +SIMPLE_TEST_STEP(DrawPath, drawPath(kTestPath, kTestPaint)); +SIMPLE_TEST_STEP(DrawBitmap, drawBitmap(kTestBitmap, 0, 0)); +SIMPLE_TEST_STEP(DrawBitmapPaint, drawBitmap(kTestBitmap, 0, 0, &kTestPaint)); +SIMPLE_TEST_STEP(DrawBitmapRect, drawBitmapRect(kTestBitmap, NULL, kTestRect, + NULL)); +SIMPLE_TEST_STEP(DrawBitmapRectSrcRect, drawBitmapRect(kTestBitmap, + &kTestIRect, kTestRect, NULL)); +SIMPLE_TEST_STEP(DrawBitmapRectPaint, drawBitmapRect(kTestBitmap, NULL, + kTestRect, &kTestPaint)); +SIMPLE_TEST_STEP(DrawBitmapMatrix, drawBitmapMatrix(kTestBitmap, kTestMatrix, + NULL)); +SIMPLE_TEST_STEP(DrawBitmapMatrixPaint, drawBitmapMatrix(kTestBitmap, + kTestMatrix, &kTestPaint)); +SIMPLE_TEST_STEP(DrawBitmapNine, drawBitmapNine(kTestBitmap, kTestIRect, + kTestRect, NULL)); +SIMPLE_TEST_STEP(DrawBitmapNinePaint, drawBitmapNine(kTestBitmap, kTestIRect, + kTestRect, &kTestPaint)); +SIMPLE_TEST_STEP(DrawSprite, drawSprite(kTestBitmap, 0, 0, NULL)); +SIMPLE_TEST_STEP(DrawSpritePaint, drawSprite(kTestBitmap, 0, 0, &kTestPaint)); +SIMPLE_TEST_STEP(DrawText, drawText(kTestText.c_str(), kTestText.size(), + 0, 1, kTestPaint)); +SIMPLE_TEST_STEP(DrawPosText, drawPosText(kTestText.c_str(), + kTestText.size(), &kTestPoint, kTestPaint)); +SIMPLE_TEST_STEP(DrawTextOnPath, drawTextOnPath(kTestText.c_str(), + kTestText.size(), kTestPath, NULL, kTestPaint)); +SIMPLE_TEST_STEP(DrawTextOnPathMatrix, drawTextOnPath(kTestText.c_str(), + kTestText.size(), kTestPath, &kTestMatrix, kTestPaint)); +SIMPLE_TEST_STEP(SetExternalMatrix, setExternalMatrix(&kTestMatrix)); +SIMPLE_TEST_STEP(DrawData, drawData(kTestText.c_str(), kTestText.size())); + +/////////////////////////////////////////////////////////////////////////////// +// Complex test steps + +static void DrawVerticesShaderTestStep(SkCanvas* canvas, + skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + SkPoint pts[4]; + pts[0].set(0, 0); + pts[1].set(SkIntToScalar(kWidth), 0); + pts[2].set(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); + pts[3].set(0, SkIntToScalar(kHeight)); + SkPaint paint; + SkShader* shader = SkShader::CreateBitmapShader(kTestBitmap, + SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); + paint.setShader(shader)->unref(); + canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, pts, pts, + NULL, NULL, NULL, 0, paint); +} +TEST_STEP(DrawVerticesShader, DrawVerticesShaderTestStep); + +static void DrawPictureTestStep(SkCanvas* canvas, + skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + SkPicture* testPicture = SkNEW_ARGS(SkPicture, ()); + SkAutoUnref aup(testPicture); + SkCanvas* testCanvas = testPicture->beginRecording(kWidth, kHeight); + testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1)); + testCanvas->clipRect(kTestRect); + testCanvas->drawRect(kTestRect, kTestPaint); + canvas->drawPicture(*testPicture); +} +TEST_STEP(DrawPicture, DrawPictureTestStep); + +static void SaveRestoreTestStep(SkCanvas* canvas, + skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(), + testStep->assertMessage()); + size_t n = canvas->save(); + REPORTER_ASSERT_MESSAGE(reporter, 1 == n, testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, 2 == canvas->getSaveCount(), + testStep->assertMessage()); + canvas->save(); + canvas->save(); + REPORTER_ASSERT_MESSAGE(reporter, 4 == canvas->getSaveCount(), + testStep->assertMessage()); + canvas->restoreToCount(2); + REPORTER_ASSERT_MESSAGE(reporter, 2 == canvas->getSaveCount(), + testStep->assertMessage()); + + // should this pin to 1, or be a no-op, or crash? + canvas->restoreToCount(0); + REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(), + testStep->assertMessage()); +} +TEST_STEP(SaveRestore, SaveRestoreTestStep); - REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer()); - canvas.save(); - REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer()); +static void DrawLayerTestStep(SkCanvas* canvas, + skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(), + testStep->assertMessage()); + canvas->save(); + REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(), + testStep->assertMessage()); const SkRect* bounds = NULL; // null means include entire bounds const SkPaint* paint = NULL; - canvas.saveLayer(bounds, paint); - REPORTER_ASSERT(reporter, canvas.isDrawingToLayer()); - canvas.restore(); - REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer()); - - canvas.saveLayer(bounds, paint); - canvas.saveLayer(bounds, paint); - REPORTER_ASSERT(reporter, canvas.isDrawingToLayer()); - canvas.restore(); - REPORTER_ASSERT(reporter, canvas.isDrawingToLayer()); - canvas.restore(); + canvas->saveLayer(bounds, paint); + REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(), + testStep->assertMessage()); + canvas->restore(); + REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(), + testStep->assertMessage()); + + canvas->saveLayer(bounds, paint); + canvas->saveLayer(bounds, paint); + REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(), + testStep->assertMessage()); + canvas->restore(); + REPORTER_ASSERT_MESSAGE(reporter, canvas->isDrawingToLayer(), + testStep->assertMessage()); + canvas->restore(); // now layer count should be 0 - REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer()); + REPORTER_ASSERT_MESSAGE(reporter, !canvas->isDrawingToLayer(), + testStep->assertMessage()); } +TEST_STEP(DrawLayer, DrawLayerTestStep); -static void TestCanvas(skiatest::Reporter* reporter) { - SkBitmap bm; - bm.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); - bm.allocPixels(); - - SkCanvas canvas(bm); - int n; - - REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount()); - n = canvas.save(); - REPORTER_ASSERT(reporter, 1 == n); - REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount()); - canvas.save(); - canvas.save(); - REPORTER_ASSERT(reporter, 4 == canvas.getSaveCount()); - canvas.restoreToCount(2); - REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount()); +static void AssertCanvasStatesEqual(skiatest::Reporter* reporter, + const SkCanvas* canvas1, + const SkCanvas* canvas2, + CanvasTestStep* testStep) { + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDeviceSize() == + canvas2->getDeviceSize(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getSaveCount() == + canvas2->getSaveCount(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->isDrawingToLayer() == + canvas2->isDrawingToLayer(), testStep->assertMessage()); + SkRect bounds1, bounds2; + REPORTER_ASSERT_MESSAGE(reporter, + canvas1->getClipBounds(&bounds1, SkCanvas::kAA_EdgeType) == + canvas2->getClipBounds(&bounds2, SkCanvas::kAA_EdgeType), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2, + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, + canvas1->getClipBounds(&bounds1, SkCanvas::kBW_EdgeType) == + canvas2->getClipBounds(&bounds2, SkCanvas::kBW_EdgeType), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2, + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDrawFilter() == + canvas2->getDrawFilter(), testStep->assertMessage()); + SkIRect deviceBounds1, deviceBounds2; + REPORTER_ASSERT_MESSAGE(reporter, + canvas1->getClipDeviceBounds(&deviceBounds1) == + canvas2->getClipDeviceBounds(&deviceBounds2), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, deviceBounds1 == deviceBounds2, + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getBounder() == + canvas2->getBounder(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalMatrix() == + canvas2->getTotalMatrix(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getClipType() == + canvas2->getClipType(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalClip() == + canvas2->getTotalClip(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalClipStack() == + canvas2->getTotalClipStack(), testStep->assertMessage()); - // should this pin to 1, or be a no-op, or crash? - canvas.restoreToCount(0); - REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount()); + // The following test code is commented out because the test fails when + // the canvas is an SkPictureRecord or SkDeferredCanvas + // Issue: http://code.google.com/p/skia/issues/detail?id=498 + // Also, creating a LayerIter on an SkProxyCanvas crashes + // Issue: http://code.google.com/p/skia/issues/detail?id=499 + /* + SkCanvas::LayerIter layerIter1(const_cast<SkCanvas*>(canvas1), false); + SkCanvas::LayerIter layerIter2(const_cast<SkCanvas*>(canvas2), false); + while (!layerIter1.done() && !layerIter2.done()) { + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.matrix() == + layerIter2.matrix(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.clip() == + layerIter2.clip(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.paint() == + layerIter2.paint(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.x() == + layerIter2.x(), testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.y() == + layerIter2.y(), testStep->assertMessage()); + layerIter1.next(); + layerIter2.next(); + } + REPORTER_ASSERT_MESSAGE(reporter, layerIter1.done(), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, layerIter2.done(), + testStep->assertMessage()); + */ +} + +// The following class groups static functions that need to access +// the privates members of SkPictureRecord +class SkPictureTester { +private: + static void AssertFlattenedObjectsEqual( + SkPictureRecord* referenceRecord, + SkPictureRecord* testRecord, + skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fBitmaps.count() == + testRecord->fBitmaps.count(), testStep->assertMessage()); + for (int i = 0; i < referenceRecord->fBitmaps.count(); ++i) { + REPORTER_ASSERT_MESSAGE(reporter, + SkFlatData::Compare(referenceRecord->fBitmaps[i], + testRecord->fBitmaps[i]) == 0, testStep->assertMessage()); + } + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fMatrices.count() == + testRecord->fMatrices.count(), testStep->assertMessage()); + for (int i = 0; i < referenceRecord->fMatrices.count(); ++i) { + REPORTER_ASSERT_MESSAGE(reporter, + SkFlatData::Compare(referenceRecord->fMatrices[i], + testRecord->fMatrices[i]) == 0, + testStep->assertMessage()); + } + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fPaints.count() == + testRecord->fPaints.count(), testStep->assertMessage()); + for (int i = 0; i < referenceRecord->fPaints.count(); ++i) { + REPORTER_ASSERT_MESSAGE(reporter, + SkFlatData::Compare(referenceRecord->fPaints[i], + testRecord->fPaints[i]) == 0, testStep->assertMessage()); + } + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fRegions.count() == + testRecord->fRegions.count(), testStep->assertMessage()); + for (int i = 0; i < referenceRecord->fRegions.count(); ++i) { + REPORTER_ASSERT_MESSAGE(reporter, + SkFlatData::Compare(referenceRecord->fRegions[i], + testRecord->fRegions[i]) == 0, testStep->assertMessage()); + } + REPORTER_ASSERT_MESSAGE(reporter, + !referenceRecord->fPathHeap == + !testRecord->fPathHeap, + testStep->assertMessage()); + // The following tests are commented out because they currently + // fail. Issue: http://code.google.com/p/skia/issues/detail?id=507 + /* + if (referenceRecord->fPathHeap) { + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fPathHeap->count() == + testRecord->fPathHeap->count(), + testStep->assertMessage()); + for (int i = 0; i < referenceRecord->fPathHeap->count(); ++i) { + REPORTER_ASSERT_MESSAGE(reporter, + (*referenceRecord->fPathHeap)[i] == + (*testRecord->fPathHeap)[i], testStep->assertMessage()); + } + } + */ + + } + +public: + + static void TestPictureSerializationRoundTrip(skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat); + SkPicture referencePicture; + testStep->draw(referencePicture.beginRecording(kWidth, kHeight), + reporter); + SkPicture initialPicture; + testStep->draw(initialPicture.beginRecording(kWidth, kHeight), + reporter); + testStep->setAssertMessageFormat(kPictureReDrawAssertMessageFormat); + SkPicture roundTripPicture; + initialPicture.draw(roundTripPicture.beginRecording(kWidth, kHeight)); + + SkPictureRecord* referenceRecord = static_cast<SkPictureRecord*>( + referencePicture.getRecordingCanvas()); + SkPictureRecord* roundTripRecord = static_cast<SkPictureRecord*>( + roundTripPicture.getRecordingCanvas()); + + testStep->setAssertMessageFormat(kPictureReDrawAssertMessageFormat); + + // Verify that deserialization-serialization round trip conserves all + // data by comparing referenceRecord to roundTripRecord + REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fBitmapIndex == + roundTripRecord->fBitmapIndex, testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fMatrixIndex == + roundTripRecord->fMatrixIndex, testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fPaintIndex == + roundTripRecord->fPaintIndex, testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fRegionIndex == + roundTripRecord->fRegionIndex, testStep->assertMessage()); + char referenceBuffer[kMaxPictureBufferSize]; + SkMemoryWStream referenceStream(referenceBuffer, + kMaxPictureBufferSize); + referenceRecord->fWriter.writeToStream(&referenceStream); + char roundTripBuffer[kMaxPictureBufferSize]; + SkMemoryWStream roundTripStream(roundTripBuffer, + kMaxPictureBufferSize); + roundTripRecord->fWriter.writeToStream(&roundTripStream); + REPORTER_ASSERT_MESSAGE(reporter, + roundTripStream.bytesWritten() == referenceStream.bytesWritten(), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, 0 == memcmp(referenceBuffer, + roundTripBuffer, roundTripStream.bytesWritten()), + testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fRecordFlags == + roundTripRecord->fRecordFlags, testStep->assertMessage()); + REPORTER_ASSERT_MESSAGE(reporter, + referenceRecord->fRestoreOffsetStack == + roundTripRecord->fRestoreOffsetStack, + testStep->assertMessage()); + AssertFlattenedObjectsEqual(referenceRecord, roundTripRecord, + reporter, testStep); + AssertCanvasStatesEqual(reporter, referenceRecord, roundTripRecord, + testStep); + } + + static void TestPictureFlattenedObjectReuse(skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + // Verify that when a test step is executed twice, no extra resources + // are flattened during the second execution + testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat); + SkPicture referencePicture; + SkCanvas* referenceCanvas = referencePicture.beginRecording(kWidth, + kHeight); + testStep->draw(referenceCanvas, reporter); + SkPicture testPicture; + SkCanvas* testCanvas = testPicture.beginRecording(kWidth, + kHeight); + testStep->draw(testCanvas, reporter); + testStep->setAssertMessageFormat(kPictureSecondDrawAssertMessageFormat); + testStep->draw(testCanvas, reporter); + + SkPictureRecord* referenceRecord = static_cast<SkPictureRecord*>( + referenceCanvas); + SkPictureRecord* testRecord = static_cast<SkPictureRecord*>( + testCanvas); + testStep->setAssertMessageFormat(kPictureResourceReuseMessageFormat); + AssertFlattenedObjectsEqual(referenceRecord, testRecord, + reporter, testStep); + } +}; + +static void TestPictureStateConsistency(skiatest::Reporter* reporter, + CanvasTestStep* testStep, + const SkCanvas& referenceCanvas) { + // Verify that the recording canvas's state is consistent + // with that of a regular canvas + SkPicture testPicture; + SkCanvas* pictureCanvas = testPicture.beginRecording(kWidth, kHeight); + testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat); + testStep->draw(pictureCanvas, reporter); + testStep->setAssertMessageFormat(kPictureRecoringAssertMessageFormat); + AssertCanvasStatesEqual(reporter, pictureCanvas, &referenceCanvas, + testStep); + + SkBitmap playbackStore; + createBitmap(&playbackStore, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice playbackDevice(playbackStore); + SkCanvas playbackCanvas(&playbackDevice); + testPicture.draw(&playbackCanvas); + testStep->setAssertMessageFormat(kPicturePlaybackAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &playbackCanvas, &referenceCanvas, + testStep); + + // The following test code is commented out because SkPicture is not + // currently expected to preserve state when restarting recording. + /* + SkCanvas* pictureCanvas = testPicture.beginRecording(kWidth, kHeight); + testStep->setAssertMessageFormat(kPictureResumeAssertMessageFormat); + AssertCanvasStatesEqual(reporter, pictureCanvas, &referenceCanvas, + testStep); + */ +} + +static void TestDeferredCanvasStateConsistency( + skiatest::Reporter* reporter, + CanvasTestStep* testStep, + const SkCanvas& referenceCanvas) { + + SkBitmap deferredStore; + createBitmap(&deferredStore, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice deferredDevice(deferredStore); + SkDeferredCanvas deferredCanvas(&deferredDevice); + testStep->setAssertMessageFormat(kDeferredDrawAssertMessageFormat); + testStep->draw(&deferredCanvas, reporter); + testStep->setAssertMessageFormat(kDeferredPreFlushAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &deferredCanvas, &referenceCanvas, + testStep); + + // Verified that deferred canvas state is not affected by flushing + // pending draw operations + + // The following test code is commented out because it currently fails. + // Issue: http://code.google.com/p/skia/issues/detail?id=496 + /* + deferredCanvas.flush(); + testStep->setAssertMessageFormat(kDeferredPostFlushAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &deferredCanvas, &referenceCanvas, + testStep); + */ +} + +static void TestProxyCanvasStateConsistency( + skiatest::Reporter* reporter, + CanvasTestStep* testStep, + const SkCanvas& referenceCanvas) { + + SkBitmap indirectStore; + createBitmap(&indirectStore, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice indirectDevice(indirectStore); + SkCanvas indirectCanvas(&indirectDevice); + SkProxyCanvas proxyCanvas(&indirectCanvas); + testStep->setAssertMessageFormat(kProxyDrawAssertMessageFormat); + testStep->draw(&proxyCanvas, reporter); + // Verify that the SkProxyCanvas reports consitent state + testStep->setAssertMessageFormat(kProxyStateAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &proxyCanvas, &referenceCanvas, + testStep); + // Verify that the indirect canvas reports consitent state + testStep->setAssertMessageFormat(kProxyIndirectStateAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &indirectCanvas, &referenceCanvas, + testStep); +} + +static void TestNWayCanvasStateConsistency( + skiatest::Reporter* reporter, + CanvasTestStep* testStep, + const SkCanvas& referenceCanvas) { + + SkBitmap indirectStore1; + createBitmap(&indirectStore1, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice indirectDevice1(indirectStore1); + SkCanvas indirectCanvas1(&indirectDevice1); + + SkBitmap indirectStore2; + createBitmap(&indirectStore2, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice indirectDevice2(indirectStore2); + SkCanvas indirectCanvas2(&indirectDevice2); + + SkNWayCanvas nWayCanvas; + nWayCanvas.addCanvas(&indirectCanvas1); + nWayCanvas.addCanvas(&indirectCanvas2); + + testStep->setAssertMessageFormat(kNWayDrawAssertMessageFormat); + testStep->draw(&nWayCanvas, reporter); + // Verify that the SkProxyCanvas reports consitent state + testStep->setAssertMessageFormat(kNWayStateAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &nWayCanvas, &referenceCanvas, + testStep); + // Verify that the indirect canvases report consitent state + testStep->setAssertMessageFormat(kNWayIndirect1StateAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &indirectCanvas1, &referenceCanvas, + testStep); + testStep->setAssertMessageFormat(kNWayIndirect2StateAssertMessageFormat); + AssertCanvasStatesEqual(reporter, &indirectCanvas2, &referenceCanvas, + testStep); +} + +/* + * This sub-test verifies that the test step passes when executed + * with SkCanvas and with classes derrived from SkCanvas. It also verifies + * that the all canvas derivatives report the same state as an SkCanvas + * after having executed the test step. + */ +static void TestOverrideStateConsistency(skiatest::Reporter* reporter, + CanvasTestStep* testStep) { + SkBitmap referenceStore; + createBitmap(&referenceStore, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice referenceDevice(referenceStore); + SkCanvas referenceCanvas(&referenceDevice); + testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat); + testStep->draw(&referenceCanvas, reporter); + + TestPictureStateConsistency(reporter, testStep, referenceCanvas); + TestDeferredCanvasStateConsistency(reporter, testStep, referenceCanvas); + + // The following test code is commented out because SkProxyCanvas is + // missing a lot of virtual overrides on get* methods, which are used + // to verify canvas state. + // Issue: http://code.google.com/p/skia/issues/detail?id=500 + + //TestProxyCanvasStateConsistency(reporter, testStep, referenceCanvas); + + // The following test code is commented out because SkNWayCanvas does not + // report correct clipping and device bounds information + // Issue: http://code.google.com/p/skia/issues/detail?id=501 + + //TestNWayCanvasStateConsistency(reporter, testStep, referenceCanvas); +} + +static void TestCanvas(skiatest::Reporter* reporter) { + // Init global here because bitmap pixels cannot be alocated during + // static initialization + kTestBitmap = testBitmap(); - test_isDrawingToLayer(reporter); + for (int testStep = 0; testStep < testStepArray().count(); testStep++) { + TestOverrideStateConsistency(reporter, testStepArray()[testStep]); + SkPictureTester::TestPictureSerializationRoundTrip(reporter, + testStepArray()[testStep]); + SkPictureTester::TestPictureFlattenedObjectReuse(reporter, + testStepArray()[testStep]); + } } #include "TestClassDef.h" diff --git a/tests/ClipCubicTest.cpp b/tests/ClipCubicTest.cpp index 931b61e..491d0e5 100644 --- a/tests/ClipCubicTest.cpp +++ b/tests/ClipCubicTest.cpp @@ -7,9 +7,27 @@ */ #include "Test.h" +#include "SkCanvas.h" +#include "SkPaint.h" #include "SkCubicClipper.h" #include "SkGeometry.h" +// Currently the supersampler blitter uses int16_t for its index into an array +// the width of the clip. Test that we don't crash/assert if we try to draw +// with a device/clip that is larger. +static void test_giantClip() { + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, 64919, 1); + bm.allocPixels(); + SkCanvas canvas(bm); + canvas.clear(0); + + SkPath path; + path.moveTo(0, 0); path.lineTo(1, 0); path.lineTo(33, 1); + SkPaint paint; + paint.setAntiAlias(true); + canvas.drawPath(path, paint); +} static void PrintCurve(const char *name, const SkPoint crv[4]) { printf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n", @@ -142,6 +160,8 @@ static void TestCubicClipping(skiatest::Reporter* reporter) { 1.297736168, 7.059780121, 2.505550385, 10, shouldbe), tol)); + + test_giantClip(); } diff --git a/tests/ColorTest.cpp b/tests/ColorTest.cpp index 0efb892..83e2e3f 100644 --- a/tests/ColorTest.cpp +++ b/tests/ColorTest.cpp @@ -7,7 +7,9 @@ */ #include "Test.h" #include "SkColor.h" +#include "SkColorPriv.h" #include "SkMath.h" +#include "SkRandom.h" #include "SkUnPreMultiply.h" static void test_premul(skiatest::Reporter* reporter) { @@ -31,9 +33,49 @@ static void test_premul(skiatest::Reporter* reporter) { } } +/** + This test fails: SkFourByteInterp does *not* preserve opaque destinations. + SkAlpha255To256 implemented as (alpha + 1) is faster than + (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out. +*/ +/* +static void test_interp(skiatest::Reporter* reporter) { + SkRandom r; + + U8CPU a0 = 0; + U8CPU a255 = 255; + for (int i = 0; i < 200; i++) { + SkColor colorSrc = r.nextU(); + SkColor colorDst = r.nextU(); + SkPMColor src = SkPreMultiplyColor(colorSrc); + SkPMColor dst = SkPreMultiplyColor(colorDst); + + REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst); + REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src); + } +} +*/ + +static void test_fast_interp(skiatest::Reporter* reporter) { + SkRandom r; + + U8CPU a0 = 0; + U8CPU a255 = 255; + for (int i = 0; i < 200; i++) { + SkColor colorSrc = r.nextU(); + SkColor colorDst = r.nextU(); + SkPMColor src = SkPreMultiplyColor(colorSrc); + SkPMColor dst = SkPreMultiplyColor(colorDst); + + REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst); + REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src); + } +} static void TestColor(skiatest::Reporter* reporter) { test_premul(reporter); + //test_interp(reporter); + test_fast_interp(reporter); } #include "TestClassDef.h" diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp new file mode 100644 index 0000000..17adb52 --- /dev/null +++ b/tests/DeferredCanvasTest.cpp @@ -0,0 +1,187 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Test.h" +#include "SkBitmap.h" +#include "SkDeferredCanvas.h" +#include "SkShader.h" + + +static const int gWidth = 2; +static const int gHeight = 2; + +static void create(SkBitmap* bm, SkBitmap::Config config, SkColor color) { + bm->setConfig(config, gWidth, gHeight); + bm->allocPixels(); + bm->eraseColor(color); +} + +static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) { + SkBitmap store; + + create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice device(store); + SkDeferredCanvas canvas(&device); + + canvas.clear(0x00000000); + + SkAutoLockPixels alp(store); + REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred + SkBitmap accessed = canvas.getDevice()->accessBitmap(false); + REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed + REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef()); +} + +static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) { + SkBitmap store; + + create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice device(store); + SkDeferredCanvas canvas(&device); + + canvas.clear(0x00000000); + + SkAutoLockPixels alp(store); + REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred + canvas.flush(); + REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed +} + +static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) { + SkBitmap store; + SkRect fullRect; + fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth), + SkIntToScalar(gHeight)); + SkRect partialRect; + partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(1), SkIntToScalar(1)); + create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + SkDevice device(store); + SkDeferredCanvas canvas(&device); + + // verify that frame is intially fresh + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + // no clearing op since last call to isFreshFrame -> not fresh + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + + // Verify that clear triggers a fresh frame + canvas.clear(0x00000000); + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + + // Verify that clear with saved state triggers a fresh frame + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.clear(0x00000000); + canvas.restore(); + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + + // Verify that clear within a layer does NOT trigger a fresh frame + canvas.saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas.clear(0x00000000); + canvas.restore(); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + + // Verify that a clear with clipping triggers a fresh frame + // (clear is not affected by clipping) + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false); + canvas.clear(0x00000000); + canvas.restore(); + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + + // Verify that full frame rects with different forms of opaque paint + // trigger frames to be marked as fresh + { + SkPaint paint; + paint.setStyle( SkPaint::kFill_Style ); + paint.setAlpha( 255 ); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + } + { + SkPaint paint; + paint.setStyle( SkPaint::kFill_Style ); + SkBitmap bmp; + create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + bmp.setIsOpaque(true); + SkShader* shader = SkShader::CreateBitmapShader(bmp, + SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); + paint.setShader(shader)->unref(); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); + } + + // Verify that full frame rects with different forms of non-opaque paint + // do not trigger frames to be marked as fresh + { + SkPaint paint; + paint.setStyle( SkPaint::kFill_Style ); + paint.setAlpha( 254 ); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } + { + SkPaint paint; + paint.setStyle( SkPaint::kFill_Style ); + SkBitmap bmp; + create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); + bmp.setIsOpaque(false); + SkShader* shader = SkShader::CreateBitmapShader(bmp, + SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); + paint.setShader(shader)->unref(); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } + + // Verify that incomplete coverage does not trigger a fresh frame + { + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setAlpha(255); + canvas.drawRect(partialRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } + + // Verify that incomplete coverage due to clipping does not trigger a fresh + // frame + { + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false); + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setAlpha(255); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } + + // Verify that stroked rect does not trigger a fresh frame + { + SkPaint paint; + paint.setStyle( SkPaint::kStroke_Style ); + paint.setAlpha( 255 ); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } + + // Verify kSrcMode triggers a fresh frame even with transparent color + { + SkPaint paint; + paint.setStyle( SkPaint::kFill_Style ); + paint.setAlpha( 100 ); + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + canvas.drawRect(fullRect, paint); + REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); + } +} + +static void TestDeferredCanvas(skiatest::Reporter* reporter) { + TestDeferredCanvasBitmapAccess(reporter); + TestDeferredCanvasFlush(reporter); + TestDeferredCanvasFreshFrame(reporter); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas) diff --git a/tests/DrawPathTest.cpp b/tests/DrawPathTest.cpp new file mode 100644 index 0000000..ae0068b --- /dev/null +++ b/tests/DrawPathTest.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Test.h" +#include "SkBitmap.h" +#include "SkCanvas.h" + +static SkCanvas* create(SkBitmap::Config config, int w, int h, int rb, + void* addr = NULL) { + SkBitmap bm; + bm.setConfig(config, w, h, rb); + if (addr) { + bm.setPixels(addr); + } else { + bm.allocPixels(); + } + return new SkCanvas(bm); +} + +// we used to assert if the bounds of the device (clip) was larger than 32K +// even when the path itself was smaller. We just draw and hope in the debug +// version to not assert. +static void test_giantaa(skiatest::Reporter* reporter) { + const int W = 400; + const int H = 400; + SkCanvas* canvas = create(SkBitmap::kARGB_8888_Config, 33000, 10, 0, NULL); + canvas->clear(0); + + SkPaint paint; + paint.setAntiAlias(true); + SkPath path; + path.addOval(SkRect::MakeXYWH(-10, -10, 20 + W, 20 + H)); + canvas->drawPath(path, paint); + canvas->unref(); +} + +static void TestDrawPath(skiatest::Reporter* reporter) { + test_giantaa(reporter); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("DrawPath", TestDrawPathClass, TestDrawPath) diff --git a/tests/DrawTextTest.cpp b/tests/DrawTextTest.cpp new file mode 100644 index 0000000..aefe2f9 --- /dev/null +++ b/tests/DrawTextTest.cpp @@ -0,0 +1,115 @@ +/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkTypes.h"
+
+#include "Test.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkPaint.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const SkColor bgColor = SK_ColorWHITE;
+
+static void create(SkBitmap* bm, SkIRect bound, SkBitmap::Config config) {
+ bm->setConfig(config, bound.width(), bound.height());
+ bm->allocPixels();
+}
+
+static void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(bgColor);
+}
+
+/** Assumes that the ref draw was completely inside ref canvas --
+ implies that everything outside is "bgColor".
+ Checks that all overlap is the same and that all non-overlap on the
+ ref is "bgColor".
+ */
+static bool compare(const SkBitmap& ref, const SkIRect& iref,
+ const SkBitmap& test, const SkIRect& itest)
+{
+ const int xOff = itest.fLeft - iref.fLeft;
+ const int yOff = itest.fTop - iref.fTop;
+
+ SkAutoLockPixels alpRef(ref);
+ SkAutoLockPixels alpTest(test);
+
+ for (int y = 0; y < test.height(); ++y) {
+ for (int x = 0; x < test.width(); ++x) {
+ SkColor testColor = test.getColor(x, y);
+ int refX = x + xOff;
+ int refY = y + yOff;
+ SkColor refColor;
+ if (refX >= 0 && refX < ref.width() &&
+ refY >= 0 && refY < ref.height())
+ {
+ refColor = ref.getColor(refX, refY);
+ } else {
+ refColor = bgColor;
+ }
+ if (refColor != testColor) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static void test_drawText(skiatest::Reporter* reporter) {
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setTextSize(SkIntToScalar(20));
+
+ SkIRect drawTextRect = SkIRect::MakeWH(64, 64);
+ SkBitmap drawTextBitmap;
+ create(&drawTextBitmap, drawTextRect, SkBitmap::kARGB_8888_Config);
+ SkCanvas drawTextCanvas(drawTextBitmap);
+
+ SkIRect drawPosTextRect = SkIRect::MakeWH(64, 64);
+ SkBitmap drawPosTextBitmap;
+ create(&drawPosTextBitmap, drawPosTextRect, SkBitmap::kARGB_8888_Config);
+ SkCanvas drawPosTextCanvas(drawPosTextBitmap);
+
+ for (float offsetY = 0.0f; offsetY < 1.0f; offsetY += (1.0f / 16.0f)) {
+ for (float offsetX = 0.0f; offsetX < 1.0f; offsetX += (1.0f / 16.0f)) {
+ SkPoint point = SkPoint::Make(SkFloatToScalar(25.0f + offsetX),
+ SkFloatToScalar(25.0f + offsetY));
+
+ for (int align = 0; align < SkPaint::kAlignCount; ++align) {
+ paint.setTextAlign(static_cast<SkPaint::Align>(align));
+
+ for (unsigned int flags = 0; flags < (1 << 3); ++flags) {
+ static const unsigned int antiAliasFlag = 1;
+ static const unsigned int subpixelFlag = 1 << 1;
+ static const unsigned int lcdFlag = 1 << 2;
+
+ paint.setAntiAlias(SkToBool(flags & antiAliasFlag));
+ paint.setSubpixelText(SkToBool(flags & subpixelFlag));
+ paint.setLCDRenderText(SkToBool(flags & lcdFlag));
+
+ // Test: drawText and drawPosText draw the same.
+ drawBG(&drawTextCanvas);
+ drawTextCanvas.drawText("A", 1, point.fX, point.fY, paint);
+
+ drawBG(&drawPosTextCanvas);
+ drawPosTextCanvas.drawPosText("A", 1, &point, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(drawTextBitmap, drawTextRect,
+ drawPosTextBitmap, drawPosTextRect));
+ }
+ }
+ }
+ }
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("DrawText_DrawPosText", DrawTextTestClass, test_drawText)
diff --git a/tests/FontHostTest.cpp b/tests/FontHostTest.cpp new file mode 100644 index 0000000..8ab7ad3 --- /dev/null +++ b/tests/FontHostTest.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Test.h" +#include "SkTypeface.h" +#include "SkFontHost.h" + +//#define DUMP_TABLES + +#define kFontTableTag_head SkSetFourByteTag('h', 'e', 'a', 'd') +#define kFontTableTag_hhea SkSetFourByteTag('h', 'h', 'e', 'a') +#define kFontTableTag_maxp SkSetFourByteTag('m', 'a', 'x', 'p') + +static const struct TagSize { + SkFontTableTag fTag; + size_t fSize; +} gKnownTableSizes[] = { + { kFontTableTag_head, 54 }, + { kFontTableTag_hhea, 36 }, + { kFontTableTag_maxp, 32 }, +}; + +static void test_tables(skiatest::Reporter* reporter, SkTypeface* face) { + SkFontID fontID = face->uniqueID(); + + int count = SkFontHost::CountTables(fontID); + + SkAutoTMalloc<SkFontTableTag> storage(count); + SkFontTableTag* tags = storage.get(); + + int count2 = SkFontHost::GetTableTags(fontID, tags); + REPORTER_ASSERT(reporter, count2 == count); + + for (int i = 0; i < count; ++i) { + size_t size = SkFontHost::GetTableSize(fontID, tags[i]); + REPORTER_ASSERT(reporter, size > 0); + +#ifdef DUMP_TABLES + char name[5]; + name[0] = (tags[i] >> 24) & 0xFF; + name[1] = (tags[i] >> 16) & 0xFF; + name[2] = (tags[i] >> 8) & 0xFF; + name[3] = (tags[i] >> 0) & 0xFF; + name[4] = 0; + SkDebugf("%s %d\n", name, size); +#endif + + for (size_t j = 0; j < SK_ARRAY_COUNT(gKnownTableSizes); ++j) { + if (gKnownTableSizes[j].fTag == tags[i]) { + REPORTER_ASSERT(reporter, gKnownTableSizes[j].fSize == size); + } + } + + // do we get the same size from GetTableData and GetTableSize + { + SkAutoMalloc data(size); + size_t size2 = SkFontHost::GetTableData(fontID, tags[i], 0, size, + data.get()); + REPORTER_ASSERT(reporter, size2 == size); + } + } +} + +static void test_tables(skiatest::Reporter* reporter) { + static const char* const gNames[] = { + NULL, // default font + "Arial", "Times", "Times New Roman", "Helvetica", "Courier", + "Courier New", + }; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) { + SkTypeface* face = SkTypeface::CreateFromName(gNames[i], + SkTypeface::kNormal); + if (face) { +#ifdef DUMP_TABLES + SkDebugf("%s\n", gNames[i]); +#endif + test_tables(reporter, face); + face->unref(); + } + } +} + +static void TestFontHost(skiatest::Reporter* reporter) { + test_tables(reporter); +} + +// need tests for SkStrSearch + +#include "TestClassDef.h" +DEFINE_TESTCLASS("FontHost", FontHostTestClass, TestFontHost) diff --git a/tests/GLInterfaceValidation.cpp b/tests/GLInterfaceValidation.cpp index 2be13f0..5cee0e4 100755 --- a/tests/GLInterfaceValidation.cpp +++ b/tests/GLInterfaceValidation.cpp @@ -7,8 +7,8 @@ */ #include "Test.h" -#include "SkNativeGLContext.h" -#include "SkMesaGLContext.h" +#include "gl/SkNativeGLContext.h" +#include "gl/SkMesaGLContext.h" static void GLInterfaceValidationTest(skiatest::Reporter* reporter) { typedef const GrGLInterface* (*interfaceFactory)(); @@ -51,7 +51,13 @@ static void GLInterfaceValidationTest(skiatest::Reporter* reporter) { iface.reset(interfaceFactories[i].fFactory()); REPORTER_ASSERT(reporter, NULL != iface.get()); if (iface.get()) { - REPORTER_ASSERT(reporter, iface.get()->validate()); + for (GrGLBinding binding = kFirstGrGLBinding; + binding <= kLastGrGLBinding; + binding = static_cast<GrGLBinding>(binding << 1)) { + if (iface.get()->fBindingsExported & binding) { + REPORTER_ASSERT(reporter, iface.get()->validate(binding)); + } + } } } } diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index 5cacade..583b802 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -8,7 +8,7 @@ #include "Test.h" #include "GrContext.h" -#include "GrGpuGLShaders.h" +#include "gl/GrGpuGLShaders.h" static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) { GrGpuGLShaders* shadersGpu = (GrGpuGLShaders*) context->getGpu(); diff --git a/tests/GeometryTest.cpp b/tests/GeometryTest.cpp index 6158a20..9a0f78f 100644 --- a/tests/GeometryTest.cpp +++ b/tests/GeometryTest.cpp @@ -12,6 +12,25 @@ static bool nearly_equal(const SkPoint& a, const SkPoint& b) { return SkScalarNearlyEqual(a.fX, b.fX) && SkScalarNearlyEqual(a.fY, b.fY); } +static void testChopCubic(skiatest::Reporter* reporter) { + /* + Inspired by this test, which used to assert that the tValues had dups + + <path stroke="#202020" d="M0,0 C0,0 1,1 2190,5130 C2190,5070 2220,5010 2205,4980" /> + */ + const SkPoint src[] = { + { SkIntToScalar(2190), SkIntToScalar(5130) }, + { SkIntToScalar(2190), SkIntToScalar(5070) }, + { SkIntToScalar(2220), SkIntToScalar(5010) }, + { SkIntToScalar(2205), SkIntToScalar(4980) }, + }; + SkPoint dst[13]; + SkScalar tValues[3]; + // make sure we don't assert internally + int count = SkChopCubicAtMaxCurvature(src, dst, tValues); +} + + static void TestGeometry(skiatest::Reporter* reporter) { SkPoint pts[3], dst[5]; @@ -35,6 +54,8 @@ static void TestGeometry(skiatest::Reporter* reporter) { for (int i = 0; i < 4; ++i) { REPORTER_ASSERT(reporter, nearly_equal(cubic[i], dst[i])); } + + testChopCubic(reporter); } #include "TestClassDef.h" diff --git a/tests/PathMeasureTest.cpp b/tests/PathMeasureTest.cpp index d454e37..2ff9f3a 100644 --- a/tests/PathMeasureTest.cpp +++ b/tests/PathMeasureTest.cpp @@ -43,6 +43,91 @@ static void TestPathMeasure(skiatest::Reporter* reporter) { d, p.fX, p.fY, v.fX, v.fY); #endif } + + // Test the behavior following a close not followed by a move. + path.reset(); + path.lineTo(SK_Scalar1, 0); + path.lineTo(SK_Scalar1, SK_Scalar1); + path.lineTo(0, SK_Scalar1); + path.close(); + path.lineTo(-SK_Scalar1, 0); + meas.setPath(&path, false); + length = meas.getLength(); + REPORTER_ASSERT(reporter, length == SK_Scalar1 * 4); + meas.nextContour(); + length = meas.getLength(); + REPORTER_ASSERT(reporter, length == SK_Scalar1); + SkPoint position; + SkVector tangent; + REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, -SK_ScalarHalf, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, position.fY == 0); + REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1); + REPORTER_ASSERT(reporter, tangent.fY == 0); + + // Test degenerate paths + path.reset(); + path.moveTo(0, 0); + path.lineTo(0, 0); + path.lineTo(SK_Scalar1, 0); + path.quadTo(SK_Scalar1, 0, SK_Scalar1, 0); + path.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1 * 2); + path.cubicTo(SK_Scalar1, SK_Scalar1 * 2, + SK_Scalar1, SK_Scalar1 * 2, + SK_Scalar1, SK_Scalar1 * 2); + path.cubicTo(SK_Scalar1*2, SK_Scalar1 * 2, + SK_Scalar1*3, SK_Scalar1 * 2, + SK_Scalar1*4, SK_Scalar1 * 2); + meas.setPath(&path, false); + length = meas.getLength(); + REPORTER_ASSERT(reporter, length == SK_Scalar1 * 6); + REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, SK_ScalarHalf, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, position.fY == 0); + REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); + REPORTER_ASSERT(reporter, tangent.fY == 0); + REPORTER_ASSERT(reporter, meas.getPosTan(SK_Scalar1 * 2.5f, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, SK_Scalar1, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fY, SK_Scalar1 * 1.5f)); + REPORTER_ASSERT(reporter, tangent.fX == 0); + REPORTER_ASSERT(reporter, tangent.fY == SK_Scalar1); + REPORTER_ASSERT(reporter, meas.getPosTan(SK_Scalar1 * 4.5f, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, SK_Scalar1 * 2.5f, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fY, SK_Scalar1 * 2.0f, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); + REPORTER_ASSERT(reporter, tangent.fY == 0); + + path.reset(); + path.moveTo(0, 0); + path.lineTo(SK_Scalar1, 0); + path.moveTo(SK_Scalar1, SK_Scalar1); + path.moveTo(SK_Scalar1 * 2, SK_Scalar1 * 2); + path.lineTo(SK_Scalar1, SK_Scalar1 * 2); + meas.setPath(&path, false); + length = meas.getLength(); + REPORTER_ASSERT(reporter, length == SK_Scalar1); + REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, SK_ScalarHalf, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, position.fY == 0); + REPORTER_ASSERT(reporter, tangent.fX == SK_Scalar1); + REPORTER_ASSERT(reporter, tangent.fY == 0); + meas.nextContour(); + length = meas.getLength(); + REPORTER_ASSERT(reporter, length == SK_Scalar1); + REPORTER_ASSERT(reporter, meas.getPosTan(SK_ScalarHalf, &position, &tangent)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fX, SK_Scalar1 * 1.5f, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, + SkScalarNearlyEqual(position.fY, SK_Scalar1 * 2.0f, SK_Scalar1 * 0.0001)); + REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1); + REPORTER_ASSERT(reporter, tangent.fY == 0); } #include "TestClassDef.h" diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index fadb0d9..868ce31 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -15,6 +15,21 @@ #include "SkSize.h" #include "SkWriter32.h" +/** + * cheapIsDirection can take a shortcut when a path is marked convex. + * This function ensures that we always test cheapIsDirection when the path + * is flagged with unknown convexity status. + */ +static void check_direction(SkPath* path, + SkPath::Direction expectedDir, + skiatest::Reporter* reporter) { + if (SkPath::kConvex_Convexity == path->getConvexity()) { + REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir)); + path->setConvexity(SkPath::kUnknown_Convexity); + } + REPORTER_ASSERT(reporter, path->cheapIsDirection(expectedDir)); +} + static void test_direction(skiatest::Reporter* reporter) { size_t i; SkPath path; @@ -40,24 +55,48 @@ static void test_direction(skiatest::Reporter* reporter) { static const char* gCW[] = { "M 10 10 L 10 10 Q 20 10 20 20", "M 10 10 C 20 10 20 20 20 20", + "M 20 10 Q 20 20 30 20 L 10 20", // test double-back at y-max }; for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) { path.reset(); bool valid = SkParsePath::FromSVGString(gCW[i], &path); REPORTER_ASSERT(reporter, valid); - REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction)); + check_direction(&path, SkPath::kCW_Direction, reporter); } static const char* gCCW[] = { "M 10 10 L 10 10 Q 20 10 20 -20", "M 10 10 C 20 10 20 -20 20 -20", + "M 20 10 Q 20 20 10 20 L 30 20", // test double-back at y-max }; for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) { path.reset(); bool valid = SkParsePath::FromSVGString(gCCW[i], &path); REPORTER_ASSERT(reporter, valid); - REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction)); + check_direction(&path, SkPath::kCCW_Direction, reporter); } + + // Test two donuts, each wound a different direction. Only the outer contour + // determines the cheap direction + path.reset(); + path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCW_Direction); + path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCCW_Direction); + check_direction(&path, SkPath::kCW_Direction, reporter); + + path.reset(); + path.addCircle(0, 0, SkIntToScalar(1), SkPath::kCW_Direction); + path.addCircle(0, 0, SkIntToScalar(2), SkPath::kCCW_Direction); + check_direction(&path, SkPath::kCCW_Direction, reporter); + +#ifdef SK_SCALAR_IS_FLOAT + // triangle with one point really far from the origin. + path.reset(); + // the first point is roughly 1.05e10, 1.05e10 + path.moveTo(SkFloatToScalar(SkBits2Float(0x501c7652)), SkFloatToScalar(SkBits2Float(0x501c7652))); + path.lineTo(110 * SK_Scalar1, -10 * SK_Scalar1); + path.lineTo(-10 * SK_Scalar1, 60 * SK_Scalar1); + check_direction(&path, SkPath::kCCW_Direction, reporter); +#endif } static void add_rect(SkPath* path, const SkRect& r) { @@ -889,12 +928,14 @@ static void test_raw_iter(skiatest::Reporter* reporter) { // Max of 10 segments, max 3 points per segment SkRandom rand(9876543); SkPoint expectedPts[31]; // May have leading moveTo - SkPath::Verb expectedVerbs[11]; // May have leading moveTo + SkPath::Verb expectedVerbs[22]; // May have leading moveTo SkPath::Verb nextVerb; + for (int i = 0; i < 500; ++i) { p.reset(); bool lastWasClose = true; bool haveMoveTo = false; + SkPoint lastMoveToPt = { 0, 0 }; int numPoints = 0; int numVerbs = (rand.nextU() >> 16) % 10; int numIterVerbs = 0; @@ -907,13 +948,14 @@ static void test_raw_iter(skiatest::Reporter* reporter) { case SkPath::kMove_Verb: expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25]; p.moveTo(expectedPts[numPoints]); + lastMoveToPt = expectedPts[numPoints]; numPoints += 1; lastWasClose = false; haveMoveTo = true; break; case SkPath::kLine_Verb: if (!haveMoveTo) { - expectedPts[numPoints++].set(0, 0); + expectedPts[numPoints++] = lastMoveToPt; expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; haveMoveTo = true; } @@ -924,7 +966,7 @@ static void test_raw_iter(skiatest::Reporter* reporter) { break; case SkPath::kQuad_Verb: if (!haveMoveTo) { - expectedPts[numPoints++].set(0, 0); + expectedPts[numPoints++] = lastMoveToPt; expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; haveMoveTo = true; } @@ -936,7 +978,7 @@ static void test_raw_iter(skiatest::Reporter* reporter) { break; case SkPath::kCubic_Verb: if (!haveMoveTo) { - expectedPts[numPoints++].set(0, 0); + expectedPts[numPoints++] = lastMoveToPt; expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb; haveMoveTo = true; } @@ -950,6 +992,7 @@ static void test_raw_iter(skiatest::Reporter* reporter) { break; case SkPath::kClose_Verb: p.close(); + haveMoveTo = false; lastWasClose = true; break; default:; diff --git a/tests/PremulAlphaRoundTripTest.cpp b/tests/PremulAlphaRoundTripTest.cpp new file mode 100644 index 0000000..c4ec6ab --- /dev/null +++ b/tests/PremulAlphaRoundTripTest.cpp @@ -0,0 +1,106 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Test.h" +#include "SkCanvas.h" +#include "SkConfig8888.h" +#include "SkGpuDevice.h" + + +namespace { + +void fillCanvas(SkCanvas* canvas, SkCanvas::Config8888 unpremulConfig) { + SkBitmap bmp; + bmp.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); + bmp.allocPixels(); + SkAutoLockPixels alp(bmp); + uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels()); + + for (int a = 0; a < 256; ++a) { + for (int r = 0; r < 256; ++r) { + pixels[a * 256 + r] = SkPackConfig8888(unpremulConfig, a, r, 0, 0); + } + } + canvas->writePixels(bmp, 0, 0, unpremulConfig); +} + +static const SkCanvas::Config8888 gUnpremulConfigs[] = { + SkCanvas::kNative_Unpremul_Config8888, +/** + * There is a bug in Ganesh (http://code.google.com/p/skia/issues/detail?id=438) + * that causes the readback of pixels from BGRA canvas to an RGBA bitmap to + * fail. This should be removed as soon as the issue above is resolved. + */ +#if !defined(SK_BUILD_FOR_ANDROID) + SkCanvas::kBGRA_Unpremul_Config8888, +#endif + SkCanvas::kRGBA_Unpremul_Config8888, +}; + +void PremulAlphaRoundTripTest(skiatest::Reporter* reporter, + GrContext* context) { + SkCanvas canvas; + for (int dtype = 0; dtype < 2; ++dtype) { + if (0 == dtype) { + canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config, + 256, + 256, + false))->unref(); + } else { +#if SK_SCALAR_IS_FIXED + // GPU device known not to work in the fixed pt build. + continue; +#endif + canvas.setDevice(new SkGpuDevice(context, + SkBitmap::kARGB_8888_Config, + 256, + 256))->unref(); + } + + SkBitmap readBmp1; + readBmp1.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); + readBmp1.allocPixels(); + SkBitmap readBmp2; + readBmp2.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); + readBmp2.allocPixels(); + + for (size_t upmaIdx = 0; + upmaIdx < SK_ARRAY_COUNT(gUnpremulConfigs); + ++upmaIdx) { + fillCanvas(&canvas, gUnpremulConfigs[upmaIdx]); + { + SkAutoLockPixels alp1(readBmp1); + SkAutoLockPixels alp2(readBmp2); + sk_bzero(readBmp1.getPixels(), readBmp1.getSafeSize()); + sk_bzero(readBmp2.getPixels(), readBmp2.getSafeSize()); + } + + canvas.readPixels(&readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]); + canvas.writePixels(readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]); + canvas.readPixels(&readBmp2, 0, 0, gUnpremulConfigs[upmaIdx]); + + SkAutoLockPixels alp1(readBmp1); + SkAutoLockPixels alp2(readBmp2); + uint32_t* pixels1 = + reinterpret_cast<uint32_t*>(readBmp1.getPixels()); + uint32_t* pixels2 = + reinterpret_cast<uint32_t*>(readBmp2.getPixels()); + for (int y = 0; y < 256; ++y) { + for (int x = 0; x < 256; ++x) { + int i = y * 256 + x; + REPORTER_ASSERT(reporter, pixels1[i] == pixels2[i]); + } + } + } + } +} +} + +#include "TestClassDef.h" +DEFINE_GPUTESTCLASS("PremulAlphaRoundTripTest", PremulAlphaRoundTripTestClass, PremulAlphaRoundTripTest) + diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp index b531e92..4e0fcc6 100644 --- a/tests/ReadPixelsTest.cpp +++ b/tests/ReadPixelsTest.cpp @@ -297,7 +297,7 @@ void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) { SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), }; - for (int dtype = 1; dtype < 2; ++dtype) { + for (int dtype = 0; dtype < 2; ++dtype) { if (0 == dtype) { canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config, diff --git a/tests/Test.cpp b/tests/Test.cpp index 1c3b691..62df731 100644 --- a/tests/Test.cpp +++ b/tests/Test.cpp @@ -8,7 +8,7 @@ #include "Test.h" #include "GrContext.h" -#include "SkNativeGLContext.h" +#include "gl/SkNativeGLContext.h" #include "SkTLazy.h" using namespace skiatest; diff --git a/tests/Test.h b/tests/Test.h index 8728040..4ca1971 100644 --- a/tests/Test.h +++ b/tests/Test.h @@ -115,10 +115,19 @@ namespace skiatest { do { \ if (!(cond)) { \ SkString desc; \ - desc.printf("%s:%d: %s", __FILE__, __LINE__, #cond); \ + desc.printf("%s:%d: %s", __FILE__, __LINE__, #cond); \ r->reportFailed(desc); \ } \ } while(0) +#define REPORTER_ASSERT_MESSAGE(r, cond, message) \ + do { \ + if (!(cond)) { \ + SkString desc; \ + desc.printf("%s %s:%d: %s", message, __FILE__, __LINE__, #cond); \ + r->reportFailed(desc); \ + } \ + } while(0) + #endif diff --git a/tests/WArrayTest.cpp b/tests/WArrayTest.cpp index 428ca5f..daab543 100644 --- a/tests/WArrayTest.cpp +++ b/tests/WArrayTest.cpp @@ -108,7 +108,7 @@ static SkString stringify_advance_data( bool leadingSpace = false; while (data != NULL) { if (leadingSpace) { - result.appendf(" "); + result.append(" "); } else { leadingSpace = true; } @@ -121,11 +121,11 @@ static SkString stringify_advance_data( result.appendf("%d[", data->fStartId); for (int i = 0; i < data->fAdvance.count(); ++i) { if (i > 0) { - result.appendf(" "); + result.append(" "); } result.appendf("%d", data->fAdvance[i]); } - result.appendf("]"); + result.append("]"); break; case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kDefault: result.appendf("<Default=%d>", data->fAdvance[0]); diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp index 0c5b7b9..403ab84 100644 --- a/tests/WritePixelsTest.cpp +++ b/tests/WritePixelsTest.cpp @@ -233,6 +233,7 @@ bool checkWrite(skiatest::Reporter* reporter, intptr_t canvasPixels = reinterpret_cast<intptr_t>(devBmp.getPixels()); size_t canvasRowBytes = devBmp.rowBytes(); SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height()); + bool success = true; for (int cy = 0; cy < DEV_H; ++cy) { const SkPMColor* canvasRow = reinterpret_cast<const SkPMColor*>(canvasPixels); for (int cx = 0; cx < DEV_W; ++cx) { @@ -246,14 +247,14 @@ bool checkWrite(skiatest::Reporter* reporter, bool check; REPORTER_ASSERT(reporter, check = checkPixel(bmpPMColor, canvasPixel, mul)); if (!check) { - return false; + success = false; } } else { bool check; SkPMColor testColor = getCanvasColor(cx, cy); REPORTER_ASSERT(reporter, check = (canvasPixel == testColor)); if (!check) { - return false; + success = false; } } } @@ -263,14 +264,14 @@ bool checkWrite(skiatest::Reporter* reporter, bool check; REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD))); if (!check) { - return false; + success = false; } } } canvasPixels += canvasRowBytes; } - return true; + return success; } enum DevType { |