aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2012-01-18 08:56:56 -0500
committerDerek Sollenberger <derek@android.com>2012-02-06 14:14:40 -0500
commit1cab2921ab279367f8206cdadc9259d12e603548 (patch)
tree2852f9dc2481f639122e18fc7831ae6ca43d6d5a /tests
parentd7176fd5571bc9878d3cdac8696eaa35ec170d9d (diff)
downloadexternal_skia-1cab2921ab279367f8206cdadc9259d12e603548.zip
external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.gz
external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.bz2
Skia merge (revision 3022)
This CL has companion changes to account for API updates in... (1) frameworks/base (2) external/webkit Change-Id: Ibb989e76e8bd24313849f9631dbef42cdef9eb7d
Diffstat (limited to 'tests')
-rw-r--r--tests/AAClipTest.cpp287
-rw-r--r--tests/Android.mk49
-rw-r--r--tests/BitSetTest.cpp79
-rw-r--r--tests/BitmapCopyTest.cpp9
-rw-r--r--tests/BitmapGetColorTest.cpp7
-rw-r--r--tests/BlitRowTest.cpp7
-rw-r--r--tests/BlurTest.cpp162
-rw-r--r--tests/CanvasTest.cpp67
-rw-r--r--tests/ClampRangeTest.cpp7
-rw-r--r--tests/ClipCubicTest.cpp7
-rw-r--r--tests/ClipStackTest.cpp28
-rw-r--r--tests/ClipperTest.cpp26
-rw-r--r--tests/ColorFilterTest.cpp7
-rw-r--r--tests/ColorTest.cpp8
-rw-r--r--tests/DataRefTest.cpp61
-rw-r--r--tests/DequeTest.cpp7
-rw-r--r--tests/DrawBitmapRectTest.cpp7
-rw-r--r--tests/EmptyPathTest.cpp156
-rw-r--r--tests/FillPathTest.cpp19
-rw-r--r--tests/FlateTest.cpp31
-rwxr-xr-xtests/GLInterfaceValidation.cpp64
-rw-r--r--tests/GLProgramsTest.cpp21
-rw-r--r--tests/GeometryTest.cpp25
-rw-r--r--tests/InfRectTest.cpp13
-rw-r--r--tests/MathTest.cpp107
-rw-r--r--tests/Matrix44Test.cpp83
-rw-r--r--tests/MatrixTest.cpp121
-rw-r--r--tests/MemsetTest.cpp91
-rw-r--r--tests/MetaDataTest.cpp7
-rw-r--r--tests/PDFPrimitivesTest.cpp248
-rw-r--r--tests/PackBitsTest.cpp7
-rw-r--r--tests/PaintTest.cpp62
-rw-r--r--tests/ParsePathTest.cpp7
-rw-r--r--tests/PathCoverageTest.cpp83
-rw-r--r--tests/PathMeasureTest.cpp7
-rw-r--r--tests/PathTest.cpp957
-rw-r--r--tests/PointTest.cpp46
-rw-r--r--tests/QuickRejectTest.cpp80
-rw-r--r--tests/ReadPixelsTest.cpp391
-rw-r--r--tests/Reader32Test.cpp19
-rw-r--r--tests/RefDictTest.cpp7
-rw-r--r--tests/RegionTest.cpp7
-rw-r--r--tests/ScalarTest.cpp137
-rw-r--r--tests/ShaderOpacityTest.cpp119
-rw-r--r--tests/Sk64Test.cpp7
-rw-r--r--tests/SortTest.cpp7
-rw-r--r--tests/SrcOverTest.cpp7
-rw-r--r--tests/StreamTest.cpp48
-rw-r--r--tests/StringTest.cpp51
-rw-r--r--tests/Test.cpp32
-rw-r--r--tests/Test.h21
-rw-r--r--tests/TestClassDef.h22
-rw-r--r--tests/TestSize.cpp7
-rw-r--r--tests/ToUnicode.cpp133
-rw-r--r--tests/TriangulationTest.cpp7
-rw-r--r--tests/UnicodeTest.cpp45
-rw-r--r--tests/UtilsTest.cpp7
-rw-r--r--tests/WArrayTest.cpp219
-rw-r--r--tests/WritePixelsTest.cpp419
-rw-r--r--tests/Writer32Test.cpp19
-rw-r--r--tests/XfermodeTest.cpp31
-rw-r--r--tests/skia_test.cpp59
-rw-r--r--tests/tests_files.mk39
63 files changed, 4618 insertions, 302 deletions
diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp
new file mode 100644
index 0000000..b3051fd
--- /dev/null
+++ b/tests/AAClipTest.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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 "SkAAClip.h"
+#include "SkCanvas.h"
+#include "SkMask.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+
+static bool operator==(const SkMask& a, const SkMask& b) {
+ if (a.fFormat != b.fFormat || a.fBounds != b.fBounds) {
+ return false;
+ }
+ if (!a.fImage && !b.fImage) {
+ return true;
+ }
+ if (!a.fImage || !b.fImage) {
+ return false;
+ }
+
+ size_t wbytes = a.fBounds.width();
+ switch (a.fFormat) {
+ case SkMask::kBW_Format:
+ wbytes = (wbytes + 7) >> 3;
+ break;
+ case SkMask::kA8_Format:
+ case SkMask::k3D_Format:
+ break;
+ case SkMask::kLCD16_Format:
+ wbytes <<= 1;
+ break;
+ case SkMask::kLCD32_Format:
+ case SkMask::kARGB32_Format:
+ wbytes <<= 2;
+ break;
+ default:
+ SkASSERT(!"unknown mask format");
+ return false;
+ }
+
+ const int h = a.fBounds.height();
+ const char* aptr = (const char*)a.fImage;
+ const char* bptr = (const char*)b.fImage;
+ for (int y = 0; y < h; ++y) {
+ if (memcmp(aptr, bptr, wbytes)) {
+ return false;
+ }
+ aptr += wbytes;
+ bptr += wbytes;
+ }
+ return true;
+}
+
+static void copyToMask(const SkRegion& rgn, SkMask* mask) {
+ mask->fFormat = SkMask::kA8_Format;
+
+ if (rgn.isEmpty()) {
+ mask->fBounds.setEmpty();
+ mask->fRowBytes = 0;
+ mask->fImage = NULL;
+ return;
+ }
+
+ mask->fBounds = rgn.getBounds();
+ mask->fRowBytes = mask->fBounds.width();
+ mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+ sk_bzero(mask->fImage, mask->computeImageSize());
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kA8_Config, mask->fBounds.width(),
+ mask->fBounds.height(), mask->fRowBytes);
+ bitmap.setPixels(mask->fImage);
+
+ // canvas expects its coordinate system to always be 0,0 in the top/left
+ // so we translate the rgn to match that before drawing into the mask.
+ //
+ SkRegion tmpRgn(rgn);
+ tmpRgn.translate(-rgn.getBounds().fLeft, -rgn.getBounds().fTop);
+
+ SkCanvas canvas(bitmap);
+ canvas.clipRegion(tmpRgn);
+ canvas.drawColor(SK_ColorBLACK);
+}
+
+static SkIRect rand_rect(SkRandom& rand, int n) {
+ int x = rand.nextS() % n;
+ int y = rand.nextS() % n;
+ int w = rand.nextU() % n;
+ int h = rand.nextU() % n;
+ return SkIRect::MakeXYWH(x, y, w, h);
+}
+
+static void make_rand_rgn(SkRegion* rgn, SkRandom& rand) {
+ int count = rand.nextU() % 20;
+ for (int i = 0; i < count; ++i) {
+ rgn->op(rand_rect(rand, 100), SkRegion::kXOR_Op);
+ }
+}
+
+static bool operator==(const SkRegion& rgn, const SkAAClip& aaclip) {
+ SkMask mask0, mask1;
+
+ copyToMask(rgn, &mask0);
+ aaclip.copyToMask(&mask1);
+ bool eq = (mask0 == mask1);
+
+ SkMask::FreeImage(mask0.fImage);
+ SkMask::FreeImage(mask1.fImage);
+ return eq;
+}
+
+static bool equalsAAClip(const SkRegion& rgn) {
+ SkAAClip aaclip;
+ aaclip.setRegion(rgn);
+ return rgn == aaclip;
+}
+
+static void setRgnToPath(SkRegion* rgn, const SkPath& path) {
+ SkIRect ir;
+ path.getBounds().round(&ir);
+ rgn->setPath(path, SkRegion(ir));
+}
+
+// aaclip.setRegion should create idential masks to the region
+static void test_rgn(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ for (int i = 0; i < 1000; i++) {
+ SkRegion rgn;
+ make_rand_rgn(&rgn, rand);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+
+ {
+ SkRegion rgn;
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(30));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(SkIntToScalar(100 - 20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+}
+
+static const SkRegion::Op gRgnOps[] = {
+ SkRegion::kDifference_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op,
+ SkRegion::kReplace_Op
+};
+
+static const char* gRgnOpNames[] = {
+ "DIFF", "INTERSECT", "UNION", "XOR", "REVERSE_DIFF", "REPLACE"
+};
+
+static void imoveTo(SkPath& path, int x, int y) {
+ path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
+}
+
+static void icubicTo(SkPath& path, int x0, int y0, int x1, int y1, int x2, int y2) {
+ path.cubicTo(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ SkIntToScalar(x2), SkIntToScalar(y2));
+}
+
+static void test_path_bounds(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkAAClip clip;
+ const int height = 40;
+ const SkScalar sheight = SkIntToScalar(height);
+
+ path.addOval(SkRect::MakeWH(sheight, sheight));
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, height == clip.getBounds().height());
+
+ // this is the trimmed height of this cubic (with aa). The critical thing
+ // for this test is that it is less than height, which represents just
+ // the bounds of the path's control-points.
+ //
+ // This used to fail until we tracked the MinY in the BuilderBlitter.
+ //
+ const int teardrop_height = 12;
+ path.reset();
+ imoveTo(path, 0, 20);
+ icubicTo(path, 40, 40, 40, 0, 0, 20);
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
+}
+
+static void test_empty(skiatest::Reporter* reporter) {
+ SkAAClip clip0, clip1;
+
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ clip0.translate(10, 10); // should have no effect on empty
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkIRect r = { 10, 10, 40, 50 };
+ clip0.setRect(r);
+ REPORTER_ASSERT(reporter, !clip0.isEmpty());
+ REPORTER_ASSERT(reporter, !clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip0 != clip1);
+ REPORTER_ASSERT(reporter, clip0.getBounds() == r);
+
+ clip0.setEmpty();
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkMask mask;
+ mask.fImage = NULL;
+ clip0.copyToMask(&mask);
+ REPORTER_ASSERT(reporter, NULL == mask.fImage);
+ REPORTER_ASSERT(reporter, mask.fBounds.isEmpty());
+}
+
+static void rand_irect(SkIRect* r, int N, SkRandom& rand) {
+ r->setXYWH(0, 0, rand.nextU() % N, rand.nextU() % N);
+ int dx = rand.nextU() % (2*N);
+ int dy = rand.nextU() % (2*N);
+ // use int dx,dy to make the subtract be signed
+ r->offset(N - dx, N - dy);
+}
+
+static void test_irect(skiatest::Reporter* reporter) {
+ SkRandom rand;
+
+ for (int i = 0; i < 10000; i++) {
+ SkAAClip clip0, clip1;
+ SkRegion rgn0, rgn1;
+ SkIRect r0, r1;
+
+ rand_irect(&r0, 10, rand);
+ rand_irect(&r1, 10, rand);
+ clip0.setRect(r0);
+ clip1.setRect(r1);
+ rgn0.setRect(r0);
+ rgn1.setRect(r1);
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gRgnOps); ++j) {
+ SkRegion::Op op = gRgnOps[j];
+ SkAAClip clip2;
+ SkRegion rgn2;
+ bool nonEmptyAA = clip2.op(clip0, clip1, op);
+ bool nonEmptyBW = rgn2.op(rgn0, rgn1, op);
+ if (nonEmptyAA != nonEmptyBW || clip2.getBounds() != rgn2.getBounds()) {
+ SkDebugf("[%d %d %d %d] %s [%d %d %d %d] = BW:[%d %d %d %d] AA:[%d %d %d %d]\n",
+ r0.fLeft, r0.fTop, r0.right(), r0.bottom(),
+ gRgnOpNames[j],
+ r1.fLeft, r1.fTop, r1.right(), r1.bottom(),
+ rgn2.getBounds().fLeft, rgn2.getBounds().fTop,
+ rgn2.getBounds().right(), rgn2.getBounds().bottom(),
+ clip2.getBounds().fLeft, clip2.getBounds().fTop,
+ clip2.getBounds().right(), clip2.getBounds().bottom());
+ }
+ REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW);
+ REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds());
+ }
+ }
+}
+
+static void TestAAClip(skiatest::Reporter* reporter) {
+ test_empty(reporter);
+ test_path_bounds(reporter);
+ test_irect(reporter);
+ test_rgn(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)
diff --git a/tests/Android.mk b/tests/Android.mk
index 4db6c75..14d23f8 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -3,23 +3,32 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AAClipTest.cpp \
BitmapCopyTest.cpp \
BitmapGetColorTest.cpp \
BlitRowTest.cpp \
+ BlurTest.cpp \
+ CanvasTest.cpp \
ClampRangeTest.cpp \
ClipCubicTest.cpp \
ClipStackTest.cpp \
ClipperTest.cpp \
ColorFilterTest.cpp \
ColorTest.cpp \
+ DataRefTest.cpp \
DequeTest.cpp \
DrawBitmapRectTest.cpp \
+ EmptyPathTest.cpp \
FillPathTest.cpp \
FlateTest.cpp \
GeometryTest.cpp \
+ GLInterfaceValidation.cpp \
+ GLProgramsTest.cpp \
InfRectTest.cpp \
MathTest.cpp \
MatrixTest.cpp \
+ Matrix44Test.cpp \
+ MemsetTest.cpp \
MetaDataTest.cpp \
PackBitsTest.cpp \
PaintTest.cpp \
@@ -27,37 +36,53 @@ LOCAL_SRC_FILES:= \
PathCoverageTest.cpp \
PathMeasureTest.cpp \
PathTest.cpp \
+ PointTest.cpp \
+ QuickRejectTest.cpp \
Reader32Test.cpp \
+ ReadPixelsTest.cpp \
RefDictTest.cpp \
RegionTest.cpp \
+ ScalarTest.cpp \
+ ShaderOpacityTest.cpp \
Sk64Test.cpp \
+ skia_test.cpp \
SortTest.cpp \
SrcOverTest.cpp \
StreamTest.cpp \
StringTest.cpp \
Test.cpp \
+ Test.h \
TestSize.cpp \
+ UnicodeTest.cpp \
UtilsTest.cpp \
+ WArrayTest.cpp \
+ WritePixelsTest.cpp \
Writer32Test.cpp \
XfermodeTest.cpp
-# The name of the file with a main function must
-# match native test's naming rule: xxx_test.cpp.
-LOCAL_SRC_FILES += \
- skia_test.cpp
+# TODO: tests that currently are causing build problems
+#LOCAL_SRC_FILES += \
+# BitSetTest.cpp \
+# PDFPrimitivesTest.cpp \
+# ToUnicode.cpp
LOCAL_MODULE:= skia_test
LOCAL_C_INCLUDES := \
- external/skia/include/core \
- external/skia/include/effects \
- external/skia/include/images \
- external/skia/include/ports \
- external/skia/include/utils \
- external/skia/src/core
+ external/freetype/include \
+ external/skia/include/core \
+ external/skia/include/config \
+ external/skia/include/effects \
+ external/skia/include/gpu \
+ external/skia/include/images \
+ external/skia/include/pdf \
+ external/skia/include/ports \
+ external/skia/include/utils \
+ external/skia/src/core \
+ external/skia/src/gpu
-LOCAL_SHARED_LIBRARIES := \
- libskia libcutils
+LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2 libEGL
+LOCAL_STATIC_LIBRARIES := libskiagpu
LOCAL_MODULE_TAGS := eng tests
diff --git a/tests/BitSetTest.cpp b/tests/BitSetTest.cpp
new file mode 100644
index 0000000..7139495
--- /dev/null
+++ b/tests/BitSetTest.cpp
@@ -0,0 +1,79 @@
+
+/*
+ * 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 "SkBitSet.h"
+
+static void TestBitSet(skiatest::Reporter* reporter) {
+ SkBitSet set0(65536);
+ REPORTER_ASSERT(reporter, set0.isBitSet(0) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(32767) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(65535) == false);
+
+ SkBitSet set1(65536);
+ REPORTER_ASSERT(reporter, set0 == set1);
+
+ set0.setBit(22, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == true);
+ set0.setBit(24, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ set0.setBit(35, true); // on a different DWORD
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ set0.setBit(22, false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+
+ SkTDArray<unsigned int> data;
+ set0.exportTo(&data);
+ REPORTER_ASSERT(reporter, data.count() == 2);
+ REPORTER_ASSERT(reporter, data[0] == 24);
+ REPORTER_ASSERT(reporter, data[1] == 35);
+
+ set1.setBit(12345, true);
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == true);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ REPORTER_ASSERT(reporter, set1 != set0);
+
+ set1.clearAll();
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(35) == false);
+
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set1 == set0);
+
+ SkBitSet set2(1);
+ SkBitSet set3(1);
+ SkBitSet set4(4);
+ SkBitSet set5(33);
+
+ REPORTER_ASSERT(reporter, set2 == set3);
+ REPORTER_ASSERT(reporter, set2 != set4);
+ REPORTER_ASSERT(reporter, set2 != set5);
+
+ set2.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ set5.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ REPORTER_ASSERT(reporter, set2 != set3);
+ set3.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 == set3);
+ set3.clearAll();
+ set3 = set2;
+ set2 = set2;
+ REPORTER_ASSERT(reporter, set2 == set3);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("BitSet", BitSetTest, TestBitSet)
diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp
index 6ddb548..b8d16bf 100644
--- a/tests/BitmapCopyTest.cpp
+++ b/tests/BitmapCopyTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkBitmap.h"
#include "SkRect.h"
@@ -543,6 +550,7 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) {
reportCopyVerification(subset, bufBm, coords,
"copyPixelsTo(buf, bufSize, rowBytes()-1)", reporter);
+#if 0 // copyPixelsFrom is gone
// Test #5 ////////////////////////////////////////////
// Tests the case where the source stride is too small
// for the source configuration.
@@ -577,6 +585,7 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) {
false);
delete [] buf;
+#endif
}
}
} // for (size_t copyCase ...
diff --git a/tests/BitmapGetColorTest.cpp b/tests/BitmapGetColorTest.cpp
index 81cf412..4204ddf 100644
--- a/tests/BitmapGetColorTest.cpp
+++ b/tests/BitmapGetColorTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkBitmap.h"
diff --git a/tests/BlitRowTest.cpp b/tests/BlitRowTest.cpp
index d18cb8a..b37b47e 100644
--- a/tests/BlitRowTest.cpp
+++ b/tests/BlitRowTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkBitmap.h"
#include "SkCanvas.h"
diff --git a/tests/BlurTest.cpp b/tests/BlurTest.cpp
new file mode 100644
index 0000000..c0d16f8
--- /dev/null
+++ b/tests/BlurTest.cpp
@@ -0,0 +1,162 @@
+
+/*
+ * 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 "SkBlurMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkMath.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
+
+static const int outset = 100;
+static const SkColor bgColor = SK_ColorWHITE;
+static const int strokeWidth = 4;
+
+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);
+}
+
+
+struct BlurTest {
+ void (*addPath)(SkPath*);
+ int viewLen;
+ SkIRect views[9];
+};
+
+//Path Draw Procs
+//Beware that paths themselves my draw differently depending on the clip.
+static void draw50x50Rect(SkPath* path) {
+ path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
+}
+
+//Tests
+static BlurTest tests[] = {
+ { draw50x50Rect, 3, {
+ //inner half of blur
+ { 0, 0, 50, 50 },
+ //blur, but no path.
+ { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
+ //just an edge
+ { 40, strokeWidth, 60, 50 - strokeWidth },
+ }},
+};
+
+/** 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_blur(skiatest::Reporter* reporter) {
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(strokeWidth));
+
+ SkScalar radius = SkIntToScalar(5);
+ for (int style = 0; style < SkBlurMaskFilter::kBlurStyleCount; ++style) {
+ SkBlurMaskFilter::BlurStyle blurStyle =
+ static_cast<SkBlurMaskFilter::BlurStyle>(style);
+
+ const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
+ for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
+ SkMaskFilter* filter;
+ filter = SkBlurMaskFilter::Create(radius, blurStyle, flags);
+
+ SkMaskFilter::BlurInfo info;
+ sk_bzero(&info, sizeof(info));
+ SkMaskFilter::BlurType type = filter->asABlur(&info);
+
+ REPORTER_ASSERT(reporter, type ==
+ static_cast<SkMaskFilter::BlurType>(style + 1));
+ REPORTER_ASSERT(reporter, info.fRadius == radius);
+ REPORTER_ASSERT(reporter, info.fIgnoreTransform ==
+ SkToBool(flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag));
+ REPORTER_ASSERT(reporter, info.fHighQuality ==
+ SkToBool(flags & SkBlurMaskFilter::kHighQuality_BlurFlag));
+
+ paint.setMaskFilter(filter);
+ filter->unref();
+
+ for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
+ SkPath path;
+ tests[test].addPath(&path);
+ SkPath strokedPath;
+ paint.getFillPath(path, &strokedPath);
+ SkRect refBound = strokedPath.getBounds();
+ SkIRect iref;
+ refBound.roundOut(&iref);
+ iref.inset(-outset, -outset);
+ SkBitmap refBitmap;
+ create(&refBitmap, iref, SkBitmap::kARGB_8888_Config);
+
+ SkCanvas refCanvas(refBitmap);
+ refCanvas.translate(SkIntToScalar(-iref.fLeft),
+ SkIntToScalar(-iref.fTop));
+ drawBG(&refCanvas);
+ refCanvas.drawPath(path, paint);
+
+ for (int view = 0; view < tests[test].viewLen; ++view) {
+ SkIRect itest = tests[test].views[view];
+ SkBitmap testBitmap;
+ create(&testBitmap, itest, SkBitmap::kARGB_8888_Config);
+
+ SkCanvas testCanvas(testBitmap);
+ testCanvas.translate(SkIntToScalar(-itest.fLeft),
+ SkIntToScalar(-itest.fTop));
+ drawBG(&testCanvas);
+ testCanvas.drawPath(path, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(refBitmap, iref, testBitmap, itest));
+ }
+ }
+ }
+ }
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("BlurMaskFilter", BlurTestClass, test_blur)
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
new file mode 100644
index 0000000..da1fafd
--- /dev/null
+++ b/tests/CanvasTest.cpp
@@ -0,0 +1,67 @@
+
+/*
+ * 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 "SkBitmap.h"
+#include "SkCanvas.h"
+
+static void test_isDrawingToLayer(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
+ bm.allocPixels();
+
+ SkCanvas canvas(bm);
+
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+ canvas.save();
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+
+ 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();
+ // now layer count should be 0
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+}
+
+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());
+
+ // should this pin to 1, or be a no-op, or crash?
+ canvas.restoreToCount(0);
+ REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
+
+ test_isDrawingToLayer(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Canvas", TestCanvasClass, TestCanvas)
diff --git a/tests/ClampRangeTest.cpp b/tests/ClampRangeTest.cpp
index be9c6ec..226d030 100644
--- a/tests/ClampRangeTest.cpp
+++ b/tests/ClampRangeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkClampRange.h"
#include "SkRandom.h"
diff --git a/tests/ClipCubicTest.cpp b/tests/ClipCubicTest.cpp
index e38a22f..931b61e 100644
--- a/tests/ClipCubicTest.cpp
+++ b/tests/ClipCubicTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkCubicClipper.h"
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index eafdd69..40738df 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkClipStack.h"
#include "SkPath.h"
@@ -5,6 +12,7 @@
static void test_assign_and_comparison(skiatest::Reporter* reporter) {
SkClipStack s;
+ bool doAA = false;
// Build up a clip stack with a path, an empty clip, and a rect.
s.save();
@@ -13,17 +21,17 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
p.lineTo(7, 8);
p.lineTo(5, 9);
p.close();
- s.clipDevPath(p);
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
s.save();
SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
r = SkRect::MakeLTRB(10, 11, 12, 13);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
// Test that assignment works.
SkClipStack copy = s;
@@ -36,14 +44,14 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
// Test that an equal, but not copied version is equal.
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s == copy);
// Test that a different op on one level triggers not equal.
s.restore();
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Test that different state (clip type) triggers not equal.
@@ -51,14 +59,14 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
s.save();
SkPath rp;
rp.addRect(r);
- s.clipDevPath(rp, SkRegion::kUnion_Op);
+ s.clipDevPath(rp, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Test that different rects triggers not equal.
s.restore();
s.save();
r = SkRect::MakeLTRB(24, 25, 26, 27);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Sanity check
@@ -73,7 +81,7 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
s.restore();
s.save();
p.addRect(r);
- s.clipDevPath(p);
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
}
@@ -101,7 +109,7 @@ static void TestClipStack(skiatest::Reporter* reporter) {
{ 0, 0, 75, 75 }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
- stack.clipDevRect(gRects[i]);
+ stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op);
}
// all of the above rects should have been intersected, leaving only 1 rect
diff --git a/tests/ClipperTest.cpp b/tests/ClipperTest.cpp
index 66301fc..7bb2254 100644
--- a/tests/ClipperTest.cpp
+++ b/tests/ClipperTest.cpp
@@ -1,8 +1,33 @@
+
+/*
+ * 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 "SkPath.h"
#include "SkLineClipper.h"
#include "SkEdgeClipper.h"
+static void test_edgeclipper(skiatest::Reporter* reporter) {
+ SkEdgeClipper clipper;
+
+ const SkPoint pts[] = {
+ { SkFloatToScalar(3.0995476e+010), SkFloatToScalar(42.929779) },
+ { SkFloatToScalar(-3.0995163e+010), SkFloatToScalar(51.050385) },
+ { SkFloatToScalar(-3.0995157e+010), SkFloatToScalar(51.050392) },
+ { SkFloatToScalar(-3.0995134e+010), SkFloatToScalar(51.050400) },
+ };
+
+ const SkRect clip = { 0, 0, SkIntToScalar(300), SkIntToScalar(200) };
+
+ // this should not assert, even though our choppers do a poor numerical
+ // job when computing their t values.
+ // http://code.google.com/p/skia/issues/detail?id=444
+ clipper.clipCubic(pts, clip);
+}
+
static void test_intersectline(skiatest::Reporter* reporter) {
static const SkScalar L = 0;
static const SkScalar T = 0;
@@ -83,6 +108,7 @@ static void test_intersectline(skiatest::Reporter* reporter) {
void TestClipper(skiatest::Reporter* reporter) {
test_intersectline(reporter);
+ test_edgeclipper(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp
index 77575eb..f98deb0 100644
--- a/tests/ColorFilterTest.cpp
+++ b/tests/ColorFilterTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkColor.h"
#include "SkColorFilter.h"
diff --git a/tests/ColorTest.cpp b/tests/ColorTest.cpp
index ef4b0b6..0efb892 100644
--- a/tests/ColorTest.cpp
+++ b/tests/ColorTest.cpp
@@ -1,5 +1,13 @@
+
+/*
+ * 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 "SkColor.h"
+#include "SkMath.h"
#include "SkUnPreMultiply.h"
static void test_premul(skiatest::Reporter* reporter) {
diff --git a/tests/DataRefTest.cpp b/tests/DataRefTest.cpp
new file mode 100644
index 0000000..6a42485
--- /dev/null
+++ b/tests/DataRefTest.cpp
@@ -0,0 +1,61 @@
+
+/*
+ * 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 "SkData.h"
+
+static void* gGlobal;
+
+static void delete_int_proc(const void* ptr, size_t len, void* context) {
+ int* data = (int*)ptr;
+ SkASSERT(context == gGlobal);
+ delete[] data;
+}
+
+static void assert_len(skiatest::Reporter* reporter, SkData* ref, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+}
+
+static void assert_data(skiatest::Reporter* reporter, SkData* ref,
+ const void* data, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+ REPORTER_ASSERT(reporter, !memcmp(ref->data(), data, len));
+}
+
+void TestDataRef(skiatest::Reporter* reporter) {
+ const char* str = "We the people, in order to form a more perfect union.";
+ const int N = 10;
+
+ SkData* r0 = SkData::NewEmpty();
+ SkData* r1 = SkData::NewWithCopy(str, strlen(str));
+ SkData* r2 = SkData::NewWithProc(new int[N], N*sizeof(int),
+ delete_int_proc, gGlobal);
+ SkData* r3 = SkData::NewSubset(r1, 7, 6);
+
+ SkAutoUnref aur0(r0);
+ SkAutoUnref aur1(r1);
+ SkAutoUnref aur2(r2);
+ SkAutoUnref aur3(r3);
+
+ assert_len(reporter, r0, 0);
+ assert_len(reporter, r1, strlen(str));
+ assert_len(reporter, r2, N * sizeof(int));
+ assert_len(reporter, r3, 6);
+
+ assert_data(reporter, r1, str, strlen(str));
+ assert_data(reporter, r3, "people", 6);
+
+ SkData* tmp = SkData::NewSubset(r1, strlen(str), 10);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+ tmp = SkData::NewSubset(r1, 0, 0);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("DataRef", DataRefTestClass, TestDataRef)
diff --git a/tests/DequeTest.cpp b/tests/DequeTest.cpp
index e74fd28..4e1c1b7 100644
--- a/tests/DequeTest.cpp
+++ b/tests/DequeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkDeque.h"
diff --git a/tests/DrawBitmapRectTest.cpp b/tests/DrawBitmapRectTest.cpp
index fc382ce..843feb5 100644
--- a/tests/DrawBitmapRectTest.cpp
+++ b/tests/DrawBitmapRectTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkBitmap.h"
#include "SkCanvas.h"
diff --git a/tests/EmptyPathTest.cpp b/tests/EmptyPathTest.cpp
new file mode 100644
index 0000000..b126076
--- /dev/null
+++ b/tests/EmptyPathTest.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "SkPath.h"
+#include "SkCanvas.h"
+
+static void appendStr(SkString* str, const SkPaint& paint) {
+ str->appendf(" style[%d] cap[%d] join[%d] antialias[%d]",
+ paint.getStyle(), paint.getStrokeCap(),
+ paint.getStrokeJoin(), paint.isAntiAlias());
+}
+
+static void appendStr(SkString* str, const SkPath& path) {
+ str->appendf(" filltype[%d] ptcount[%d]",
+ path.getFillType(), path.countPoints());
+}
+
+#define DIMENSION 32
+
+static void drawAndTest(skiatest::Reporter* reporter, const SkPath& path,
+ const SkPaint& paint, bool shouldDraw) {
+ SkBitmap bm;
+ // explicitly specify a trim rowbytes, so we have no padding on each row
+ bm.setConfig(SkBitmap::kARGB_8888_Config, DIMENSION, DIMENSION, DIMENSION*4);
+ bm.allocPixels();
+ bm.eraseColor(0);
+
+ SkCanvas canvas(bm);
+ SkPaint p(paint);
+ p.setColor(SK_ColorWHITE);
+
+ canvas.drawPath(path, p);
+
+ size_t count = DIMENSION * DIMENSION;
+ const SkPMColor* ptr = bm.getAddr32(0, 0);
+
+ SkPMColor andValue = ~0;
+ SkPMColor orValue = 0;
+ for (size_t i = 0; i < count; ++i) {
+ SkPMColor c = ptr[i];
+ andValue &= c;
+ orValue |= c;
+ }
+
+ // success means we drew everywhere or nowhere (depending on shouldDraw)
+ bool success = shouldDraw ? (~0U == andValue) : (0 == orValue);
+
+ if (!success) {
+ SkString str;
+ if (shouldDraw) {
+ str.set("Path expected to draw everywhere, but didn't. ");
+ } else {
+ str.set("Path expected to draw nowhere, but did. ");
+ }
+ appendStr(&str, paint);
+ appendStr(&str, path);
+ reporter->report(str.c_str(), skiatest::Reporter::kFailed);
+
+// uncomment this if you want to step in to see the failure
+// canvas.drawPath(path, p);
+ }
+}
+
+static void iter_paint(skiatest::Reporter* reporter, const SkPath& path, bool shouldDraw) {
+ static const SkPaint::Cap gCaps[] = {
+ SkPaint::kButt_Cap,
+ SkPaint::kRound_Cap,
+ SkPaint::kSquare_Cap
+ };
+ static const SkPaint::Join gJoins[] = {
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join,
+ SkPaint::kBevel_Join
+ };
+ static const SkPaint::Style gStyles[] = {
+ SkPaint::kFill_Style,
+ SkPaint::kStroke_Style,
+ SkPaint::kStrokeAndFill_Style
+ };
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ for (size_t join = 0; join < SK_ARRAY_COUNT(gJoins); ++join) {
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ SkPaint paint;
+ paint.setStrokeWidth(SkIntToScalar(10));
+
+ paint.setStrokeCap(gCaps[cap]);
+ paint.setStrokeJoin(gJoins[join]);
+ paint.setStyle(gStyles[style]);
+
+ paint.setAntiAlias(false);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ paint.setAntiAlias(true);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ }
+ }
+ }
+}
+
+#define CX (SkIntToScalar(DIMENSION) / 2)
+#define CY (SkIntToScalar(DIMENSION) / 2)
+
+static void make_empty(SkPath* path) {}
+static void make_M(SkPath* path) { path->moveTo(CX, CY); }
+static void make_MM(SkPath* path) { path->moveTo(CX, CY); path->moveTo(CX, CY); }
+static void make_MZM(SkPath* path) { path->moveTo(CX, CY); path->close(); path->moveTo(CX, CY); }
+static void make_L(SkPath* path) { path->moveTo(CX, CY); path->lineTo(CX, CY); }
+static void make_Q(SkPath* path) { path->moveTo(CX, CY); path->quadTo(CX, CY, CX, CY); }
+static void make_C(SkPath* path) { path->moveTo(CX, CY); path->cubicTo(CX, CY, CX, CY, CX, CY); }
+
+/* Two invariants are tested: How does an empty/degenerate path draw?
+ * - if the path is drawn inverse, it should draw everywhere
+ * - if the path is drawn non-inverse, it should draw nowhere
+ *
+ * Things to iterate on:
+ * - path (empty, degenerate line/quad/cubic w/ and w/o close
+ * - paint style
+ * - path filltype
+ * - path stroke variants (e.g. caps, joins, width)
+ */
+static void test_emptydrawing(skiatest::Reporter* reporter) {
+ static void (*gMakeProc[])(SkPath*) = {
+ make_empty, make_M, make_MM, make_MZM, make_L, make_Q, make_C
+ };
+ static SkPath::FillType gFills[] = {
+ SkPath::kWinding_FillType,
+ SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType,
+ SkPath::kInverseEvenOdd_FillType
+ };
+ for (int doClose = 0; doClose < 2; ++doClose) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProc); ++i) {
+ SkPath path;
+ gMakeProc[i](&path);
+ if (doClose) {
+ path.close();
+ }
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ path.setFillType(gFills[fill]);
+ bool shouldDraw = path.isInverseFillType();
+ iter_paint(reporter, path, shouldDraw);
+ }
+ }
+ }
+}
+
+static void TestEmptyPath(skiatest::Reporter* reporter) {
+ test_emptydrawing(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("EmptyPath", TestEmptyPathClass, TestEmptyPath)
diff --git a/tests/FillPathTest.cpp b/tests/FillPathTest.cpp
index ffc9f8e..8271851 100644
--- a/tests/FillPathTest.cpp
+++ b/tests/FillPathTest.cpp
@@ -1,17 +1,8 @@
/*
- * Copyright (C) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010 Google Inc.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
#include "Test.h"
@@ -41,12 +32,12 @@ struct FakeBlitter : public SkBlitter {
// but skipped after tessellation, should be cleared by the blitter.
static void TestFillPathInverse(skiatest::Reporter* reporter) {
FakeBlitter blitter;
- SkRegion clip;
+ SkIRect clip;
SkPath path;
int height = 100;
int width = 200;
int expected_lines = 5;
- clip.setRect(0, height - expected_lines, width, height);
+ clip.set(0, height - expected_lines, width, height);
path.moveTo(0.0, 0.0);
path.quadTo(width/2, height, width, 0.0);
path.close();
diff --git a/tests/FlateTest.cpp b/tests/FlateTest.cpp
index fe2bb4a..8697df9 100644
--- a/tests/FlateTest.cpp
+++ b/tests/FlateTest.cpp
@@ -1,23 +1,17 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <stdlib.h>
#include <string.h>
#include "Test.h"
+#include "SkData.h"
#include "SkFlate.h"
#include "SkStream.h"
@@ -67,7 +61,9 @@ static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
else
REPORTER_ASSERT(reporter, compressed.getOffset() > 1024);
- testStream->setMemory(compressed.getStream(), compressed.getOffset(), true);
+ SkAutoDataUnref data1(compressed.copyToData());
+
+ testStream->setData(data1.get())->unref();
SkDynamicMemoryWStream uncompressed;
status = SkFlate::Inflate(testStream, &uncompressed);
REPORTER_ASSERT(reporter, status);
@@ -76,15 +72,14 @@ static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
inputSize = testStream->getLength();
if (inputSize == 0)
inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
- REPORTER_ASSERT(reporter, compressed.getOffset() == inputSize);
+ REPORTER_ASSERT(reporter, data1.size() == inputSize);
REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(),
- compressed.getStream(),
- compressed.getOffset()) == 0);
+ data1.data(), data1.size()) == 0);
// Check that the uncompressed data matches the source data.
+ SkAutoDataUnref data2(uncompressed.copyToData());
REPORTER_ASSERT(reporter, testData.getLength() == uncompressed.getOffset());
- REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(),
- uncompressed.getStream(),
+ REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(), data2.data(),
testData.getLength()) == 0);
}
diff --git a/tests/GLInterfaceValidation.cpp b/tests/GLInterfaceValidation.cpp
new file mode 100755
index 0000000..2be13f0
--- /dev/null
+++ b/tests/GLInterfaceValidation.cpp
@@ -0,0 +1,64 @@
+
+/*
+ * 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 "SkNativeGLContext.h"
+#include "SkMesaGLContext.h"
+
+static void GLInterfaceValidationTest(skiatest::Reporter* reporter) {
+ typedef const GrGLInterface* (*interfaceFactory)();
+ struct {
+ interfaceFactory fFactory;
+ const char* fName;
+ } interfaceFactories[] = {
+ {GrGLCreateNativeInterface, "Native"},
+#if SK_MESA
+ {GrGLCreateMesaInterface, "Mesa"},
+#endif
+ {GrGLCreateNullInterface, "Null"},
+ };
+
+ // On some platforms GrGLCreateNativeInterface will fail unless an OpenGL
+ // context has been created. Also, preserve the current context that may
+ // be in use by outer test harness.
+ SkNativeGLContext::AutoContextRestore nglacr;
+ SkNativeGLContext nglctx;
+ static const int gBOGUS_SIZE = 16;
+ bool nativeContextInit = nglctx.init(gBOGUS_SIZE, gBOGUS_SIZE);
+ REPORTER_ASSERT(reporter, nativeContextInit);
+ if (!nativeContextInit) {
+ return;
+ }
+#if SK_MESA
+ // We must have a current OSMesa context to initialize an OSMesa
+ // GrGLInterface
+ SkMesaGLContext::AutoContextRestore mglacr;
+ SkMesaGLContext mglctx;
+ bool mesaContextInit = mglctx.init(gBOGUS_SIZE, gBOGUS_SIZE);
+ REPORTER_ASSERT(reporter, mesaContextInit);
+ if(!mesaContextInit) {
+ return;
+ }
+#endif
+
+ SkAutoTUnref<const GrGLInterface> iface;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(interfaceFactories); ++i) {
+ iface.reset(interfaceFactories[i].fFactory());
+ REPORTER_ASSERT(reporter, NULL != iface.get());
+ if (iface.get()) {
+ REPORTER_ASSERT(reporter, iface.get()->validate());
+ }
+ }
+}
+
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("GLInterfaceValidation",
+ GLInterfaceValidationTestClass,
+ GLInterfaceValidationTest)
+
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
new file mode 100644
index 0000000..5cacade
--- /dev/null
+++ b/tests/GLProgramsTest.cpp
@@ -0,0 +1,21 @@
+
+/*
+ * 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 "GrContext.h"
+#include "GrGpuGLShaders.h"
+
+static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
+ GrGpuGLShaders* shadersGpu = (GrGpuGLShaders*) context->getGpu();
+ REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
+}
+
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
+
diff --git a/tests/GeometryTest.cpp b/tests/GeometryTest.cpp
index 5b05952..6158a20 100644
--- a/tests/GeometryTest.cpp
+++ b/tests/GeometryTest.cpp
@@ -1,6 +1,17 @@
+
+/*
+ * 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 "SkGeometry.h"
+static bool nearly_equal(const SkPoint& a, const SkPoint& b) {
+ return SkScalarNearlyEqual(a.fX, b.fX) && SkScalarNearlyEqual(a.fY, b.fY);
+}
+
static void TestGeometry(skiatest::Reporter* reporter) {
SkPoint pts[3], dst[5];
@@ -10,6 +21,20 @@ static void TestGeometry(skiatest::Reporter* reporter) {
int count = SkChopQuadAtMaxCurvature(pts, dst);
REPORTER_ASSERT(reporter, count == 1 || count == 2);
+
+ pts[0].set(0, 0);
+ pts[1].set(SkIntToScalar(3), 0);
+ pts[2].set(SkIntToScalar(3), SkIntToScalar(3));
+ SkConvertQuadToCubic(pts, dst);
+ const SkPoint cubic[] = {
+ { 0, 0, },
+ { SkIntToScalar(2), 0, },
+ { SkIntToScalar(3), SkIntToScalar(1), },
+ { SkIntToScalar(3), SkIntToScalar(3) },
+ };
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, nearly_equal(cubic[i], dst[i]));
+ }
}
#include "TestClassDef.h"
diff --git a/tests/InfRectTest.cpp b/tests/InfRectTest.cpp
index 1e15023..12356d9 100644
--- a/tests/InfRectTest.cpp
+++ b/tests/InfRectTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRect.h"
@@ -11,10 +18,10 @@ static void check_invalid(skiatest::Reporter* reporter,
SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
SkRect rect;
rect.set(l, t, r, b);
- REPORTER_ASSERT(reporter, !rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, !rect.isFinite());
}
-// Tests that hasValidCoordinates() will reject any rect with +/-inf values
+// Tests that isFinite() will reject any rect with +/-inf values
// as one of its coordinates.
static void TestInfRect(skiatest::Reporter* reporter) {
#ifdef SK_SCALAR_IS_FLOAT
@@ -26,7 +33,7 @@ static void TestInfRect(skiatest::Reporter* reporter) {
SkScalar big = SkIntToScalar(100);
SkRect rect = SkRect::MakeXYWH(small, small, big, big);
- REPORTER_ASSERT(reporter, rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, rect.isFinite());
check_invalid(reporter, small, small, big, invalid);
check_invalid(reporter, small, small, invalid, big);
diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp
index efdad3a..fef93cd 100644
--- a/tests/MathTest.cpp
+++ b/tests/MathTest.cpp
@@ -1,41 +1,97 @@
+
+/*
+ * 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 "SkFloatingPoint.h"
+#include "SkMath.h"
#include "SkPoint.h"
#include "SkRandom.h"
+#include "SkColorPriv.h"
-#if 0
-static U8CPU premul_fast(U8CPU a, U8CPU x) {
- return a * x * 32897 >> 23;
+static float float_blend(int src, int dst, float unit) {
+ return dst + (src - dst) * unit;
}
-static U8CPU premul_trunc(U8CPU a, U8CPU x) {
- double result = a * x;
- result /= 255.0;
- return (unsigned)floor(result + 0.0);
+static int blend31(int src, int dst, int a31) {
+ return dst + ((src - dst) * a31 * 2114 >> 16);
+ // return dst + ((src - dst) * a31 * 33 >> 10);
}
-static U8CPU premul_round(U8CPU a, U8CPU x) {
- double result = a * x;
- result /= 255.0;
- return (unsigned)floor(result + 0.5);
+static int blend31_slow(int src, int dst, int a31) {
+ int prod = src * a31 + (31 - a31) * dst + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return prod;
}
-static void test_premul(skiatest::Reporter* reporter) {
- for (int a = 0; a <= 255; a++) {
- for (int x = 0; x <= 255; x++) {
- unsigned curr_trunc = SkMulDiv255Trunc(a, x);
- unsigned curr_round = SkMulDiv255Round(a, x);
- unsigned fast = premul_fast(a, x);
- unsigned slow_round = premul_round(a, x);
- unsigned slow_trunc = premul_trunc(a, x);
- if (fast != slow || curr != fast) {
- SkDebugf("---- premul(%d %d) curr=%d fast=%d slow=%d\n", a, x,
- curr, fast, slow);
+static int blend31_round(int src, int dst, int a31) {
+ int prod = (src - dst) * a31 + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return dst + prod;
+}
+
+static int blend31_old(int src, int dst, int a31) {
+ a31 += a31 >> 4;
+ return dst + ((src - dst) * a31 >> 5);
+}
+
+static void test_blend31() {
+ int failed = 0;
+ int death = 0;
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 31; a++) {
+// int r0 = blend31(src, dst, a);
+// int r0 = blend31_round(src, dst, a);
+// int r0 = blend31_old(src, dst, a);
+ int r0 = blend31_slow(src, dst, a);
+
+ float f = float_blend(src, dst, a / 31.f);
+ int r1 = (int)f;
+ int r2 = SkScalarRoundToInt(SkFloatToScalar(f));
+
+ if (r0 != r1 && r0 != r2) {
+ printf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ failed += 1;
+ }
+ if (r0 > 255) {
+ death += 1;
+ printf("death src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ }
}
}
}
+ SkDebugf("---- failed %d death %d\n", failed, death);
}
+
+static void test_blend(skiatest::Reporter* reporter) {
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 255; a++) {
+ int r0 = SkAlphaBlend255(src, dst, a);
+ float f1 = float_blend(src, dst, a / 255.f);
+ int r1 = SkScalarRoundToInt(SkFloatToScalar(f1));
+
+ if (r0 != r1) {
+ float diff = sk_float_abs(f1 - r1);
+ diff = sk_float_abs(diff - 0.5f);
+ if (diff > (1 / 255.f)) {
+#ifdef SK_DEBUG
+ SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f1);
#endif
+ REPORTER_ASSERT(reporter, false);
+ }
+ }
+ }
+ }
+ }
+}
#if defined(SkLONGLONG)
static int symmetric_fixmul(int a, int b) {
@@ -493,7 +549,12 @@ static void TestMath(skiatest::Reporter* reporter) {
SkDebugf("SinCos: maximum error = %d\n", maxDiff);
#endif
-// test_premul(reporter);
+#ifdef SK_SCALAR_IS_FLOAT
+ test_blend(reporter);
+#endif
+
+ // disable for now
+// test_blend31();
}
#include "TestClassDef.h"
diff --git a/tests/Matrix44Test.cpp b/tests/Matrix44Test.cpp
index 8755bd3..485b38b 100644
--- a/tests/Matrix44Test.cpp
+++ b/tests/Matrix44Test.cpp
@@ -1,7 +1,14 @@
+
+/*
+ * 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 "SkMatrix44.h"
-static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
+static bool nearly_equal_scalar(SkMScalar a, SkMScalar b) {
// Note that we get more compounded error for multiple operations when
// SK_SCALAR_IS_FIXED.
#ifdef SK_SCALAR_IS_FLOAT
@@ -13,11 +20,37 @@ static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
return SkScalarAbs(a - b) <= tolerance;
}
+template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
+ T m0, T m1, T m2, T m3,
+ T m4, T m5, T m6, T m7,
+ T m8, T m9, T m10, T m11,
+ T m12, T m13, T m14, T m15) {
+ REPORTER_ASSERT(reporter, data[0] == m0);
+ REPORTER_ASSERT(reporter, data[1] == m1);
+ REPORTER_ASSERT(reporter, data[2] == m2);
+ REPORTER_ASSERT(reporter, data[3] == m3);
+
+ REPORTER_ASSERT(reporter, data[4] == m4);
+ REPORTER_ASSERT(reporter, data[5] == m5);
+ REPORTER_ASSERT(reporter, data[6] == m6);
+ REPORTER_ASSERT(reporter, data[7] == m7);
+
+ REPORTER_ASSERT(reporter, data[8] == m8);
+ REPORTER_ASSERT(reporter, data[9] == m9);
+ REPORTER_ASSERT(reporter, data[10] == m10);
+ REPORTER_ASSERT(reporter, data[11] == m11);
+
+ REPORTER_ASSERT(reporter, data[12] == m12);
+ REPORTER_ASSERT(reporter, data[13] == m13);
+ REPORTER_ASSERT(reporter, data[14] == m14);
+ REPORTER_ASSERT(reporter, data[15] == m15);
+}
+
static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if (!nearly_equal_scalar(a.get(i, j), b.get(i, j))) {
- printf("not equal %g %g\n", (float)a.get(i, j), (float)b.get(i, j));
+ printf("not equal %g %g\n", a.get(i, j), b.get(i, j));
return false;
}
}
@@ -31,8 +64,20 @@ static bool is_identity(const SkMatrix44& m) {
return nearly_equal(m, identity);
}
+static void test_common_angles(skiatest::Reporter* reporter) {
+ SkMatrix44 rot;
+ // Test precision of rotation in common cases
+ int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
+ for (int i = 0; i < 9; ++i) {
+ rot.setRotateDegreesAbout(0, 0, -1, common_angles[i]);
+
+ SkMatrix rot3x3 = rot;
+ REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
+ }
+}
void TestMatrix44(skiatest::Reporter* reporter) {
+#ifdef SK_SCALAR_IS_FLOAT
SkMatrix44 mat, inverse, iden1, iden2, rot;
mat.reset();
@@ -64,6 +109,40 @@ void TestMatrix44(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, is_identity(iden1));
iden2.setConcat(inverse, mat);
REPORTER_ASSERT(reporter, is_identity(iden2));
+
+ // test rol/col Major getters
+ {
+ mat.setTranslate(2, 3, 4);
+ float dataf[16];
+ double datad[16];
+
+ mat.asColMajorf(dataf);
+ assert16<float>(reporter, dataf,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asColMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asRowMajorf(dataf);
+ assert16<float>(reporter, dataf, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ mat.asRowMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ }
+
+#if 0 // working on making this pass
+ test_common_angles(reporter);
+#endif
+#endif
}
#include "TestClassDef.h"
diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp
index 4125f9f..c9a696c 100644
--- a/tests/MatrixTest.cpp
+++ b/tests/MatrixTest.cpp
@@ -1,5 +1,14 @@
+
+/*
+ * 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 "SkMath.h"
#include "SkMatrix.h"
+#include "SkRandom.h"
static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
// Note that we get more compounded error for multiple operations when
@@ -48,6 +57,94 @@ static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
}
+void test_matrix_max_stretch(skiatest::Reporter* reporter) {
+ SkMatrix identity;
+ identity.reset();
+ REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
+
+ SkMatrix scale;
+ scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
+ REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
+
+ SkMatrix rot90Scale;
+ rot90Scale.setRotate(90 * SK_Scalar1);
+ rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
+ REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
+
+ SkMatrix rotate;
+ rotate.setRotate(128 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SkScalarAbs(SK_Scalar1 - rotate.getMaxStretch()) <= SK_ScalarNearlyZero);
+
+ SkMatrix translate;
+ translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
+
+ SkMatrix perspX;
+ perspX.reset();
+ perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
+
+ SkMatrix perspY;
+ perspY.reset();
+ perspY.setPerspX(SkScalarToPersp(-SK_Scalar1 / 500));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
+
+ SkMatrix baseMats[] = {scale, rot90Scale, rotate,
+ translate, perspX, perspY};
+ SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
+ mats[i] = baseMats[i];
+ bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
+ REPORTER_ASSERT(reporter, invertable);
+ }
+ SkRandom rand;
+ for (int m = 0; m < 1000; ++m) {
+ SkMatrix mat;
+ mat.reset();
+ for (int i = 0; i < 4; ++i) {
+ int x = rand.nextU() % SK_ARRAY_COUNT(mats);
+ mat.postConcat(mats[x]);
+ }
+ SkScalar stretch = mat.getMaxStretch();
+
+ if ((stretch < 0) != mat.hasPerspective()) {
+ stretch = mat.getMaxStretch();
+ }
+
+ REPORTER_ASSERT(reporter, (stretch < 0) == mat.hasPerspective());
+
+ if (mat.hasPerspective()) {
+ m -= 1; // try another non-persp matrix
+ continue;
+ }
+
+ // test a bunch of vectors. None should be scaled by more than stretch
+ // (modulo some error) and we should find a vector that is scaled by
+ // almost stretch.
+ static const SkScalar gStretchTol = (105 * SK_Scalar1) / 100;
+ static const SkScalar gMaxStretchTol = (97 * SK_Scalar1) / 100;
+ SkScalar max = 0;
+ SkVector vectors[1000];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ vectors[i].fX = rand.nextSScalar1();
+ vectors[i].fY = rand.nextSScalar1();
+ if (!vectors[i].normalize()) {
+ i -= 1;
+ continue;
+ }
+ }
+ mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ SkScalar d = vectors[i].length();
+ REPORTER_ASSERT(reporter, SkScalarDiv(d, stretch) < gStretchTol);
+ if (max < d) {
+ max = d;
+ }
+ }
+ REPORTER_ASSERT(reporter, SkScalarDiv(max, stretch) >= gMaxStretchTol);
+ }
+}
+
void TestMatrix(skiatest::Reporter* reporter) {
SkMatrix mat, inverse, iden1, iden2;
@@ -117,6 +214,30 @@ void TestMatrix(skiatest::Reporter* reporter) {
m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
}
}
+
+ mat.reset();
+ mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
+ mat.set(SkMatrix::kMSkewX, SkIntToScalar(2));
+ mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
+ mat.set(SkMatrix::kMSkewY, SkIntToScalar(4));
+ mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
+ mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
+ SkScalar affine[6];
+ REPORTER_ASSERT(reporter, mat.asAffine(affine));
+
+ #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
+ REPORTER_ASSERT(reporter, affineEqual(ScaleX));
+ REPORTER_ASSERT(reporter, affineEqual(SkewY));
+ REPORTER_ASSERT(reporter, affineEqual(SkewX));
+ REPORTER_ASSERT(reporter, affineEqual(ScaleY));
+ REPORTER_ASSERT(reporter, affineEqual(TransX));
+ REPORTER_ASSERT(reporter, affineEqual(TransY));
+ #undef affineEqual
+
+ mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
+ REPORTER_ASSERT(reporter, !mat.asAffine(affine));
+
+ test_matrix_max_stretch(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/MemsetTest.cpp b/tests/MemsetTest.cpp
new file mode 100644
index 0000000..9c1fc92
--- /dev/null
+++ b/tests/MemsetTest.cpp
@@ -0,0 +1,91 @@
+
+/*
+ * 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 "SkUtils.h"
+
+static void set_zero(void* dst, size_t bytes) {
+ char* ptr = (char*)dst;
+ for (size_t i = 0; i < bytes; ++i) {
+ ptr[i] = 0;
+ }
+}
+
+#define MAX_ALIGNMENT 64
+#define MAX_COUNT ((MAX_ALIGNMENT) * 32)
+#define PAD 32
+#define TOTAL (PAD + MAX_ALIGNMENT + MAX_COUNT + PAD)
+
+#define VALUE16 0x1234
+#define VALUE32 0x12345678
+
+static bool compare16(const uint16_t base[], uint16_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool compare32(const uint32_t base[], uint32_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void test_16(skiatest::Reporter* reporter) {
+ uint16_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint16_t* base = &buffer[PAD + alignment];
+ sk_memset16(base, VALUE16, count);
+
+ compare16(buffer, 0, PAD + alignment);
+ compare16(base, VALUE16, count);
+ compare16(base + count, 0, TOTAL - count - PAD - alignment);
+ }
+ }
+}
+
+static void test_32(skiatest::Reporter* reporter) {
+ uint32_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint32_t* base = &buffer[PAD + alignment];
+ sk_memset32(base, VALUE32, count);
+
+ compare32(buffer, 0, PAD + alignment);
+ compare32(base, VALUE32, count);
+ compare32(base + count, 0, TOTAL - count - PAD - alignment);
+ }
+ }
+}
+
+/**
+ * Test sk_memset16 and sk_memset32.
+ * For performance considerations, implementations may take different paths
+ * depending on the alignment of the dst, and/or the size of the count.
+ */
+static void TestMemset(skiatest::Reporter* reporter) {
+ test_16(reporter);
+ test_32(reporter);
+};
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Memset", TestMemsetClass, TestMemset)
diff --git a/tests/MetaDataTest.cpp b/tests/MetaDataTest.cpp
index 70829d4..1cc3cca 100644
--- a/tests/MetaDataTest.cpp
+++ b/tests/MetaDataTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkMetaData.h"
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 9a58fa6..82686ef 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -1,39 +1,67 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <string>
#include "Test.h"
+#include "SkData.h"
+#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkScalar.h"
#include "SkStream.h"
+#include "SkTypes.h"
+
+class SkPDFTestDict : public SkPDFDict {
+public:
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ resourceList->setReserve(resourceList->count() + fResources.count());
+ for (int i = 0; i < fResources.count(); i++) {
+ resourceList->push(fResources[i]);
+ fResources[i]->ref();
+ }
+ }
+
+ void addResource(SkPDFObject* object) {
+ fResources.append(1, &object);
+ }
+
+private:
+ SkTDArray<SkPDFObject*> fResources;
+};
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const void* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data.size()) {
+ return false;
+ }
+ return memcmp(data.bytes() + offset, buffer, len) == 0;
+}
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
- const std::string& representation,
- bool indirect) {
- size_t directSize = obj->getOutputSize(NULL, false);
- REPORTER_ASSERT(reporter, directSize == representation.size());
+ const char* expectedData, size_t expectedSize,
+ bool indirect, bool compression) {
+ SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0;
+ if (!compression) {
+ docFlags = SkTBitOr(docFlags, SkPDFDocument::kNoCompression_Flag);
+ }
+ SkPDFCatalog catalog(docFlags);
+ size_t directSize = obj->getOutputSize(&catalog, false);
+ REPORTER_ASSERT(reporter, directSize == expectedSize);
SkDynamicMemoryWStream buffer;
- obj->emitObject(&buffer, NULL, false);
+ obj->emit(&buffer, &catalog, false);
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), representation.c_str(),
- directSize) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
+ directSize));
if (indirect) {
// Indirect output.
@@ -42,7 +70,6 @@ static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
static char footer[] = "\nendobj\n";
static size_t footerLen = strlen(footer);
- SkPDFCatalog catalog;
catalog.addObject(obj, false);
size_t indirectSize = obj->getOutputSize(&catalog, true);
@@ -50,21 +77,77 @@ static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
indirectSize == directSize + headerLen + footerLen);
buffer.reset();
- obj->emitObject(&buffer, &catalog, true);
+ obj->emit(&buffer, &catalog, true);
REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), header,
- headerLen) == 0);
- REPORTER_ASSERT(reporter,
- memcmp(buffer.getStream() + headerLen,
- representation.c_str(), directSize) == 0);
- REPORTER_ASSERT(reporter,
- memcmp(buffer.getStream() + headerLen + directSize,
- footer, footerLen) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData,
+ directSize));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize,
+ footer, footerLen));
+ }
+}
+
+static void SimpleCheckObjectOutput(skiatest::Reporter* reporter,
+ SkPDFObject* obj,
+ const std::string& expectedResult) {
+ CheckObjectOutput(reporter, obj, expectedResult.c_str(),
+ expectedResult.length(), true, false);
+}
+
+static void TestPDFStream(skiatest::Reporter* reporter) {
+ char streamBytes[] = "Test\nFoo\tBar";
+ SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
+ streamBytes, strlen(streamBytes), true);
+ streamData->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
+ stream->unref(); // SkRefPtr and new both took a reference.
+ SimpleCheckObjectOutput(
+ reporter, stream.get(),
+ "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream");
+ stream->insert("Attribute", new SkPDFInt(42))->unref();
+ SimpleCheckObjectOutput(reporter, stream.get(),
+ "<</Length 12\n/Attribute 42\n>> stream\n"
+ "Test\nFoo\tBar\nendstream");
+
+ if (SkFlate::HaveFlate()) {
+ char streamBytes2[] = "This is a longer string, so that compression "
+ "can do something with it. With shorter strings, "
+ "the short circuit logic cuts in and we end up "
+ "with an uncompressed string.";
+ SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2,
+ strlen(streamBytes2)));
+ SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData2.get());
+ stream->unref(); // SkRefPtr and new both took a reference.
+
+ SkDynamicMemoryWStream compressedByteStream;
+ SkFlate::Deflate(streamData2.get(), &compressedByteStream);
+ SkAutoDataUnref compressedData(compressedByteStream.copyToData());
+
+ // Check first without compression.
+ SkDynamicMemoryWStream expectedResult1;
+ expectedResult1.writeText("<</Length 167\n>> stream\n");
+ expectedResult1.writeText(streamBytes2);
+ expectedResult1.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData1(expectedResult1.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData1.data(),
+ expectedResultData1.size(), true, false);
+
+ // Then again with compression.
+ SkDynamicMemoryWStream expectedResult2;
+ expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n"
+ ">> stream\n");
+ expectedResult2.write(compressedData.data(), compressedData.size());
+ expectedResult2.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData2(expectedResult2.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData2.data(),
+ expectedResultData2.size(), true, true);
}
}
static void TestCatalog(skiatest::Reporter* reporter) {
- SkPDFCatalog catalog;
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
int1->unref(); // SkRefPtr and new both took a reference.
SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
@@ -87,8 +170,8 @@ static void TestCatalog(skiatest::Reporter* reporter) {
catalog.emitObjectNumber(&buffer, int3.get());
catalog.emitObjectNumber(&buffer, int1Again.get());
char expectedResult[] = "1 02 03 01 0";
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), expectedResult,
- strlen(expectedResult)) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ strlen(expectedResult)));
}
static void TestObjectRef(skiatest::Reporter* reporter) {
@@ -99,7 +182,7 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
SkRefPtr<SkPDFObjRef> int2ref = new SkPDFObjRef(int2.get());
int2ref->unref(); // SkRefPtr and new both took a reference.
- SkPDFCatalog catalog;
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
catalog.addObject(int1.get(), false);
catalog.addObject(int2.get(), false);
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
@@ -109,101 +192,128 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
SkDynamicMemoryWStream buffer;
int2ref->emitObject(&buffer, &catalog, false);
REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), expectedResult,
- buffer.getOffset()) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+}
+
+static void TestSubstitute(skiatest::Reporter* reporter) {
+ SkRefPtr<SkPDFTestDict> proxy = new SkPDFTestDict();
+ proxy->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFTestDict> stub = new SkPDFTestDict();
+ stub->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFInt> int33 = new SkPDFInt(33);
+ int33->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFDict> stubResource = new SkPDFDict();
+ stubResource->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFInt> int44 = new SkPDFInt(44);
+ int44->unref(); // SkRefPtr and new both took a reference.
+
+ stub->insert("Value", int33.get());
+ stubResource->insert("InnerValue", int44.get());
+ stub->addResource(stubResource.get());
+
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
+ catalog.addObject(proxy.get(), false);
+ catalog.setSubstitute(proxy.get(), stub.get());
+
+ SkDynamicMemoryWStream buffer;
+ proxy->emit(&buffer, &catalog, false);
+ catalog.emitSubstituteResources(&buffer, false);
+
+ char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n";
+ REPORTER_ASSERT(
+ reporter,
+ catalog.setFileOffset(proxy.get(), 0) == strlen(objectResult));
+
+ char expectedResult[] =
+ "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
+ REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
}
static void TestPDFPrimitives(skiatest::Reporter* reporter) {
SkRefPtr<SkPDFInt> int42 = new SkPDFInt(42);
int42->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, int42.get(), "42", true);
+ SimpleCheckObjectOutput(reporter, int42.get(), "42");
SkRefPtr<SkPDFScalar> realHalf = new SkPDFScalar(SK_ScalarHalf);
realHalf->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, realHalf.get(), "0.5", true);
+ SimpleCheckObjectOutput(reporter, realHalf.get(), "0.5");
#if defined(SK_SCALAR_IS_FLOAT)
SkRefPtr<SkPDFScalar> bigScalar = new SkPDFScalar(110999.75);
bigScalar->unref(); // SkRefPtr and new both took a reference.
#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
- CheckObjectOutput(reporter, bigScalar.get(), "111000", true);
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "111000");
#else
- CheckObjectOutput(reporter, bigScalar.get(), "110999.75", true);
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "110999.75");
SkRefPtr<SkPDFScalar> biggerScalar = new SkPDFScalar(50000000.1);
biggerScalar->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, biggerScalar.get(), "50000000", true);
+ SimpleCheckObjectOutput(reporter, biggerScalar.get(), "50000000");
SkRefPtr<SkPDFScalar> smallestScalar = new SkPDFScalar(1.0/65536);
smallestScalar->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, smallestScalar.get(), "0.00001526", true);
+ SimpleCheckObjectOutput(reporter, smallestScalar.get(), "0.00001526");
#endif
#endif
SkRefPtr<SkPDFString> stringSimple = new SkPDFString("test ) string ( foo");
stringSimple->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stringSimple.get(), "(test \\) string \\( foo)",
- true);
+ SimpleCheckObjectOutput(reporter, stringSimple.get(),
+ "(test \\) string \\( foo)");
SkRefPtr<SkPDFString> stringComplex =
new SkPDFString("\ttest ) string ( foo");
stringComplex->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stringComplex.get(),
- "<0974657374202920737472696E67202820666F6F>", true);
+ SimpleCheckObjectOutput(reporter, stringComplex.get(),
+ "<0974657374202920737472696E67202820666F6F>");
SkRefPtr<SkPDFName> name = new SkPDFName("Test name\twith#tab");
name->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, name.get(), "/Test#20name#09with#23tab", false);
+ const char expectedResult[] = "/Test#20name#09with#23tab";
+ CheckObjectOutput(reporter, name.get(), expectedResult,
+ strlen(expectedResult), false, false);
SkRefPtr<SkPDFArray> array = new SkPDFArray;
array->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, array.get(), "[]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[]");
array->append(int42.get());
- CheckObjectOutput(reporter, array.get(), "[42]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42]");
array->append(realHalf.get());
- CheckObjectOutput(reporter, array.get(), "[42 0.5]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5]");
SkRefPtr<SkPDFInt> int0 = new SkPDFInt(0);
int0->unref(); // SkRefPtr and new both took a reference.
array->append(int0.get());
- CheckObjectOutput(reporter, array.get(), "[42 0.5 0]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5 0]");
SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
int1->unref(); // SkRefPtr and new both took a reference.
array->setAt(0, int1.get());
- CheckObjectOutput(reporter, array.get(), "[1 0.5 0]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[1 0.5 0]");
SkRefPtr<SkPDFDict> dict = new SkPDFDict;
dict->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, dict.get(), "<<>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
SkRefPtr<SkPDFName> n1 = new SkPDFName("n1");
n1->unref(); // SkRefPtr and new both took a reference.
dict->insert(n1.get(), int42.get());
- CheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>");
SkRefPtr<SkPDFName> n2 = new SkPDFName("n2");
n2->unref(); // SkRefPtr and new both took a reference.
SkRefPtr<SkPDFName> n3 = new SkPDFName("n3");
n3->unref(); // SkRefPtr and new both took a reference.
dict->insert(n2.get(), realHalf.get());
dict->insert(n3.get(), array.get());
- CheckObjectOutput(reporter, dict.get(),
- "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(),
+ "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>");
- char streamBytes[] = "Test\nFoo\tBar";
- SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
- streamBytes, strlen(streamBytes), true);
- streamData->unref(); // SkRefPtr and new both took a reference.
- SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
- stream->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stream.get(),
- "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream",
- true);
- stream->insert(n1.get(), int42.get());
- CheckObjectOutput(reporter, stream.get(),
- "<</Length 12\n/n1 42\n>> stream\nTest\nFoo\tBar"
- "\nendstream",
- true);
+ TestPDFStream(reporter);
TestCatalog(reporter);
TestObjectRef(reporter);
+
+ TestSubstitute(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/PackBitsTest.cpp b/tests/PackBitsTest.cpp
index a22590c..f7d4b8e 100644
--- a/tests/PackBitsTest.cpp
+++ b/tests/PackBitsTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkPackBits.h"
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 5b19090..6350eb5 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -1,6 +1,67 @@
+
+/*
+ * 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 "SkPath.h"
#include "SkPaint.h"
+#include "SkLayerDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+
+static void test_copy(skiatest::Reporter* reporter) {
+ SkPaint paint;
+ // set a few member variables
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setTextAlign(SkPaint::kLeft_Align);
+ paint.setStrokeWidth(SkIntToScalar(2));
+ // set a few pointers
+ SkLayerDrawLooper* looper = new SkLayerDrawLooper();
+ paint.setLooper(looper)->unref();
+ SkMaskFilter* mask = SkBlurMaskFilter::Create(1, SkBlurMaskFilter::kNormal_BlurStyle);
+ paint.setMaskFilter(mask)->unref();
+
+ // copy the paint using the copy constructor and check they are the same
+ SkPaint copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the copy constructor should preserve the Generation ID
+ int32_t paintGenID = paint.getGenerationID();
+ int32_t copiedPaintGenID = copiedPaint.getGenerationID();
+ REPORTER_ASSERT(reporter, paintGenID == copiedPaintGenID);
+ REPORTER_ASSERT(reporter, !memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+ // copy the paint using the equal operator and check they are the same
+ copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the equals operator should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() == paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ copiedPaintGenID = copiedPaint.getGenerationID(); // reset to the new value
+ REPORTER_ASSERT(reporter, memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+ // clean the paint and check they are back to their initial states
+ SkPaint cleanPaint;
+ paint.reset();
+ copiedPaint.reset();
+ REPORTER_ASSERT(reporter, cleanPaint == paint);
+ REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the reset function should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() != paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &paint, sizeof(cleanPaint)));
+ REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &copiedPaint, sizeof(cleanPaint)));
+#endif
+}
// found and fixed for webkit: mishandling when we hit recursion limit on
// mostly degenerate cubic flatness test
@@ -38,6 +99,7 @@ static void regression_cubic(skiatest::Reporter* reporter) {
static void TestPaint(skiatest::Reporter* reporter) {
// TODO add general paint tests
+ test_copy(reporter);
// regression tests
regression_cubic(reporter);
diff --git a/tests/ParsePathTest.cpp b/tests/ParsePathTest.cpp
index 917b0cb..831cd8e 100644
--- a/tests/ParsePathTest.cpp
+++ b/tests/ParsePathTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkParsePath.h"
diff --git a/tests/PathCoverageTest.cpp b/tests/PathCoverageTest.cpp
index 8676029..91de178 100644
--- a/tests/PathCoverageTest.cpp
+++ b/tests/PathCoverageTest.cpp
@@ -1,15 +1,30 @@
+
+/*
+ * 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 "SkMath.h"
#include "SkPoint.h"
#include "SkScalar.h"
#include "Test.h"
/*
Duplicates lots of code from gpu/src/GrPathUtils.cpp
- It'd be nice not to do so, but that code's set up currently to only have a single implementation.
+ It'd be nice not to do so, but that code's set up currently to only have
+ a single implementation.
*/
+// Sk uses 6, Gr (implicitly) used 10, both apparently arbitrarily.
#define MAX_COEFF_SHIFT 6
static const uint32_t MAX_POINTS_PER_CURVE = 1 << MAX_COEFF_SHIFT;
+// max + 0.5 min has error [0.0, 0.12]
+// max + 0.375 min has error [-.03, 0.07]
+// 0.96043387 max + 0.397824735 min has error [-.06, +.05]
+// For determining the maximum possible number of points to use in
+// drawing a quadratic, we want to err on the high side.
static inline int cheap_distance(SkScalar dx, SkScalar dy) {
int idx = SkAbs32(SkScalarRound(dx));
int idy = SkAbs32(SkScalarRound(dy));
@@ -21,30 +36,27 @@ static inline int cheap_distance(SkScalar dx, SkScalar dy) {
return idx;
}
-static inline int diff_to_shift(SkScalar dx, SkScalar dy) {
- int dist = cheap_distance(dx, dy);
- return (32 - SkCLZ(dist));
+static inline int estimate_distance(const SkPoint points[]) {
+ return cheap_distance(points[1].fX * 2 - points[2].fX - points[0].fX,
+ points[1].fY * 2 - points[2].fY - points[0].fY);
}
-uint32_t estimatedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
- int shift = diff_to_shift(points[1].fX * 2 - points[2].fX - points[0].fX,
- points[1].fY * 2 - points[2].fY - points[0].fY);
- SkASSERT(shift >= 0);
- //SkDebugf("Quad shift %d;", shift);
- // bias to more closely approximate exact value, then clamp to zero
- shift -= 2;
- shift &= ~(shift>>31);
+static inline SkScalar compute_distance(const SkPoint points[]) {
+ return points[1].distanceToLineSegmentBetween(points[0], points[2]);
+}
+static inline uint32_t estimate_pointCount(int distance) {
+ // Includes -2 bias because this estimator runs 4x high?
+ int shift = 30 - SkCLZ(distance);
+ // Clamp to zero if above subtraction went negative.
+ shift &= ~(shift>>31);
if (shift > MAX_COEFF_SHIFT) {
shift = MAX_COEFF_SHIFT;
}
- uint32_t count = 1 << shift;
- //SkDebugf(" biased shift %d, scale %u\n", shift, count);
- return count;
+ return 1 << shift;
}
-uint32_t computedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
- SkScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
+static inline uint32_t compute_pointCount(SkScalar d, SkScalar tol) {
if (d < tol) {
return 1;
} else {
@@ -54,6 +66,26 @@ uint32_t computedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
}
}
+uint32_t quadraticPointCount_EE(const SkPoint points[], SkScalar tol) {
+ int distance = estimate_distance(points);
+ return estimate_pointCount(distance);
+}
+
+uint32_t quadraticPointCount_EC(const SkPoint points[], SkScalar tol) {
+ int distance = estimate_distance(points);
+ return compute_pointCount(SkIntToScalar(distance), tol);
+}
+
+uint32_t quadraticPointCount_CE(const SkPoint points[], SkScalar tol) {
+ SkScalar distance = compute_distance(points);
+ return estimate_pointCount(SkScalarRound(distance));
+}
+
+uint32_t quadraticPointCount_CC(const SkPoint points[], SkScalar tol) {
+ SkScalar distance = compute_distance(points);
+ return compute_pointCount(distance, tol);
+}
+
// Curve from samplecode/SampleSlides.cpp
static const int gXY[] = {
4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
@@ -82,18 +114,21 @@ static bool one_d_pe(const int* array, const unsigned int count,
path[1] = SkPoint::Make(SkIntToScalar(array[0]), SkIntToScalar(array[1]));
path[2] = SkPoint::Make(SkIntToScalar(array[2]), SkIntToScalar(array[3]));
int numErrors = 0;
- for (unsigned i = 4; i < (count); i += 2) {
+ for (unsigned i = 4; i < count; i += 2) {
path[0] = path[1];
path[1] = path[2];
path[2] = SkPoint::Make(SkIntToScalar(array[i]),
SkIntToScalar(array[i+1]));
uint32_t computedCount =
- computedQuadraticPointCount(path, SkIntToScalar(1));
+ quadraticPointCount_CC(path, SkIntToScalar(1));
uint32_t estimatedCount =
- estimatedQuadraticPointCount(path, SkIntToScalar(1));
- // Allow estimated to be off by a factor of two, but no more.
- if ((estimatedCount > 2 * computedCount) ||
- (computedCount > estimatedCount * 2)) {
+ quadraticPointCount_EE(path, SkIntToScalar(1));
+ // Allow estimated to be high by a factor of two, but no less than
+ // the computed value.
+ bool isAccurate = (estimatedCount >= computedCount) &&
+ (estimatedCount <= 2 * computedCount);
+
+ if (!isAccurate) {
SkString errorDescription;
errorDescription.printf(
"Curve from %.2f %.2f through %.2f %.2f to %.2f %.2f "
@@ -105,8 +140,6 @@ static bool one_d_pe(const int* array, const unsigned int count,
}
}
- if (numErrors > 0)
- printf("%d curve segments differ\n", numErrors);
return (numErrors == 0);
}
diff --git a/tests/PathMeasureTest.cpp b/tests/PathMeasureTest.cpp
index de18764..d454e37 100644
--- a/tests/PathMeasureTest.cpp
+++ b/tests/PathMeasureTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkPathMeasure.h"
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 7e4e6bc..fadb0d9 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -1,7 +1,221 @@
+
+/*
+ * 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 "SkPaint.h"
#include "SkPath.h"
#include "SkParse.h"
+#include "SkParsePath.h"
+#include "SkRandom.h"
+#include "SkReader32.h"
#include "SkSize.h"
+#include "SkWriter32.h"
+
+static void test_direction(skiatest::Reporter* reporter) {
+ size_t i;
+ SkPath path;
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
+
+ static const char* gDegen[] = {
+ "M 10 10",
+ "M 10 10 M 20 20",
+ "M 10 10 L 20 20",
+ "M 10 10 L 10 10 L 10 10",
+ "M 10 10 Q 10 10 10 10",
+ "M 10 10 C 10 10 10 10 10 10",
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ }
+
+ 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",
+ };
+ 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));
+ }
+
+ 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",
+ };
+ 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));
+ }
+}
+
+static void add_rect(SkPath* path, const SkRect& r) {
+ path->moveTo(r.fLeft, r.fTop);
+ path->lineTo(r.fRight, r.fTop);
+ path->lineTo(r.fRight, r.fBottom);
+ path->lineTo(r.fLeft, r.fBottom);
+ path->close();
+}
+
+static void test_bounds(skiatest::Reporter* reporter) {
+ static const SkRect rects[] = {
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
+ { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
+ };
+
+ SkPath path0, path1;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
+ path0.addRect(rects[i]);
+ add_rect(&path1, rects[i]);
+ }
+
+ REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
+}
+
+static void stroke_cubic(const SkPoint pts[4]) {
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SK_Scalar1 * 2);
+
+ SkPath fill;
+ paint.getFillPath(path, &fill);
+}
+
+// just ensure this can run w/o any SkASSERTS firing in the debug build
+// we used to assert due to differences in how we determine a degenerate vector
+// but that was fixed with the introduction of SkPoint::CanNormalize
+static void stroke_tiny_cubic() {
+ SkPoint p0[] = {
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ };
+
+ stroke_cubic(p0);
+
+ SkPoint p1[] = {
+ { 372.0f, 92.0f },
+ { 372.0007f, 92.000755f },
+ { 371.99927f, 92.003922f },
+ { 371.99826f, 92.003899f },
+ };
+
+ stroke_cubic(p1);
+}
+
+static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
+ for (int i = 0; i < 2; ++i) {
+ SkPath::Iter iter(path, (bool)i);
+ SkPoint mv;
+ SkPoint pts[4];
+ SkPath::Verb v;
+ int nMT = 0;
+ int nCL = 0;
+ mv.set(0, 0);
+ while (SkPath::kDone_Verb != (v = iter.next(pts))) {
+ switch (v) {
+ case SkPath::kMove_Verb:
+ mv = pts[0];
+ ++nMT;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, mv == pts[0]);
+ ++nCL;
+ break;
+ default:
+ break;
+ }
+ }
+ // if we force a close on the interator we should have a close
+ // for every moveTo
+ REPORTER_ASSERT(reporter, !i || nMT == nCL);
+ }
+}
+
+static void test_close(skiatest::Reporter* reporter) {
+ SkPath closePt;
+ closePt.moveTo(0, 0);
+ closePt.close();
+ check_close(reporter, closePt);
+
+ SkPath openPt;
+ openPt.moveTo(0, 0);
+ check_close(reporter, openPt);
+
+ SkPath empty;
+ check_close(reporter, empty);
+ empty.close();
+ check_close(reporter, empty);
+
+ SkPath rect;
+ rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect);
+ rect.close();
+ check_close(reporter, rect);
+
+ SkPath quad;
+ quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, quad);
+ quad.close();
+ check_close(reporter, quad);
+
+ SkPath cubic;
+ quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
+ 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
+ check_close(reporter, cubic);
+ cubic.close();
+ check_close(reporter, cubic);
+
+ SkPath line;
+ line.moveTo(SK_Scalar1, SK_Scalar1);
+ line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, line);
+ line.close();
+ check_close(reporter, line);
+
+ SkPath rect2;
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ rect2.close();
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect2);
+ rect2.close();
+ check_close(reporter, rect2);
+
+ SkPath oval3;
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
+ oval3.close();
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
+ check_close(reporter, oval3);
+ oval3.close();
+ check_close(reporter, oval3);
+
+ SkPath moves;
+ moves.moveTo(SK_Scalar1, SK_Scalar1);
+ moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
+ moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
+ moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
+ check_close(reporter, moves);
+
+ stroke_tiny_cubic();
+}
static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
SkPath::Convexity expected) {
@@ -16,30 +230,30 @@ static void test_convexity2(skiatest::Reporter* reporter) {
check_convexity(reporter, pt, SkPath::kConvex_Convexity);
SkPath line;
- line.moveTo(12, 20);
- line.lineTo(-12, -20);
+ line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
+ line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
line.close();
check_convexity(reporter, pt, SkPath::kConvex_Convexity);
SkPath triLeft;
triLeft.moveTo(0, 0);
- triLeft.lineTo(1, 0);
- triLeft.lineTo(1, 1);
+ triLeft.lineTo(SK_Scalar1, 0);
+ triLeft.lineTo(SK_Scalar1, SK_Scalar1);
triLeft.close();
check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
SkPath triRight;
triRight.moveTo(0, 0);
- triRight.lineTo(-1, 0);
- triRight.lineTo(1, 1);
+ triRight.lineTo(-SK_Scalar1, 0);
+ triRight.lineTo(SK_Scalar1, SK_Scalar1);
triRight.close();
check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
SkPath square;
square.moveTo(0, 0);
- square.lineTo(1, 0);
- square.lineTo(1, 1);
- square.lineTo(0, 1);
+ square.lineTo(SK_Scalar1, 0);
+ square.lineTo(SK_Scalar1, SK_Scalar1);
+ square.lineTo(0, SK_Scalar1);
square.close();
check_convexity(reporter, square, SkPath::kConvex_Convexity);
@@ -47,15 +261,15 @@ static void test_convexity2(skiatest::Reporter* reporter) {
redundantSquare.moveTo(0, 0);
redundantSquare.lineTo(0, 0);
redundantSquare.lineTo(0, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(0, 1);
- redundantSquare.lineTo(0, 1);
- redundantSquare.lineTo(0, 1);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
redundantSquare.close();
check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
@@ -63,35 +277,35 @@ static void test_convexity2(skiatest::Reporter* reporter) {
bowTie.moveTo(0, 0);
bowTie.lineTo(0, 0);
bowTie.lineTo(0, 0);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(0, 1);
- bowTie.lineTo(0, 1);
- bowTie.lineTo(0, 1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
bowTie.close();
check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
SkPath spiral;
spiral.moveTo(0, 0);
- spiral.lineTo(100, 0);
- spiral.lineTo(100, 100);
- spiral.lineTo(0, 100);
- spiral.lineTo(0, 50);
- spiral.lineTo(50, 50);
- spiral.lineTo(50, 75);
+ spiral.lineTo(100*SK_Scalar1, 0);
+ spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ spiral.lineTo(0, 100*SK_Scalar1);
+ spiral.lineTo(0, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
spiral.close();
check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
SkPath dent;
- dent.moveTo(SkIntToScalar(0), SkIntToScalar(0));
- dent.lineTo(SkIntToScalar(100), SkIntToScalar(100));
- dent.lineTo(SkIntToScalar(0), SkIntToScalar(100));
- dent.lineTo(SkIntToScalar(-50), SkIntToScalar(200));
- dent.lineTo(SkIntToScalar(-200), SkIntToScalar(100));
+ dent.moveTo(0, 0);
+ dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ dent.lineTo(0, 100*SK_Scalar1);
+ dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
+ dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
dent.close();
check_convexity(reporter, dent, SkPath::kConcave_Convexity);
}
@@ -137,16 +351,18 @@ static void test_convexity(skiatest::Reporter* reporter) {
SkPath path;
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
- path.addCircle(0, 0, 10);
+ path.addCircle(0, 0, SkIntToScalar(10));
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
- path.addCircle(0, 0, 10); // 2nd circle
+ path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
path.reset();
- path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction);
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
path.reset();
- path.addRect(0, 0, 10, 10, SkPath::kCW_Direction);
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
static const struct {
const char* fPathStr;
@@ -170,6 +386,631 @@ static void test_convexity(skiatest::Reporter* reporter) {
}
}
+// Simple isRect test is inline TestPath, below.
+// test_isRect provides more extensive testing.
+static void test_isRect(skiatest::Reporter* reporter) {
+ // passing tests (all moveTo / lineTo...
+ SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
+ SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
+ SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
+ SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+ SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
+ SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
+ {1, 0}, {.5f, 0}};
+ SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
+ {0, 1}, {0, .5f}};
+ SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
+
+ // failing tests
+ SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
+ SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
+ SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
+ SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
+ SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
+ SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
+ SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
+ SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
+
+ // failing, no close
+ SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
+ SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
+
+ size_t testLen[] = {
+ sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
+ sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
+ sizeof(rd), sizeof(re),
+ sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
+ sizeof(f7), sizeof(f8),
+ sizeof(c1), sizeof(c2)
+ };
+ SkPoint* tests[] = {
+ r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
+ f1, f2, f3, f4, f5, f6, f7, f8,
+ c1, c2
+ };
+ SkPoint* lastPass = re;
+ SkPoint* lastClose = f8;
+ bool fail = false;
+ bool close = true;
+ const size_t testCount = sizeof(tests) / sizeof(tests[0]);
+ size_t index;
+ for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
+ SkPath path;
+ path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
+ for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
+ path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
+ }
+ if (close) {
+ path.close();
+ }
+ REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
+ if (tests[testIndex] == lastPass) {
+ fail = true;
+ }
+ if (tests[testIndex] == lastClose) {
+ close = false;
+ }
+ }
+
+ // fail, close then line
+ SkPath path1;
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ path1.lineTo(1, 0);
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, move in the middle
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.moveTo(1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, move on the edge
+ path1.reset();
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, quad
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.quadTo(1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, cubic
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+}
+
+static void test_flattening(skiatest::Reporter* reporter) {
+ SkPath p;
+
+ static const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(10) },
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
+ };
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+
+ SkWriter32 writer(100);
+ p.flatten(writer);
+ size_t size = writer.size();
+ SkAutoMalloc storage(size);
+ writer.flatten(storage.get());
+ SkReader32 reader(storage.get(), size);
+
+ SkPath p1;
+ REPORTER_ASSERT(reporter, p1 != p);
+ p1.unflatten(reader);
+ REPORTER_ASSERT(reporter, p1 == p);
+}
+
+static void test_transform(skiatest::Reporter* reporter) {
+ SkPath p, p1;
+
+ static const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(10) },
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
+ };
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+
+ SkMatrix matrix;
+ matrix.reset();
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p == p1);
+
+ matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
+ p.transform(matrix, &p1);
+ SkPoint pts1[7];
+ int count = p1.getPoints(pts1, 7);
+ REPORTER_ASSERT(reporter, 7 == count);
+ for (int i = 0; i < count; ++i) {
+ SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
+ REPORTER_ASSERT(reporter, newPt == pts1[i]);
+ }
+}
+
+static void test_zero_length_paths(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pt;
+ SkRect bounds;
+
+ // Lone moveTo case
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 1 == p.countPoints());
+ p.getLastPt(&pt);
+ REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
+ bounds.set(0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // MoveTo-MoveTo case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ p.getLastPt(&pt);
+ REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-close case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.close();
+ bounds.set(0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 1 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-close-moveTo-close case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.lineTo(SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-lineTo-moveTo-lineTo case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.lineTo(SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line-close case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.lineTo(SK_Scalar1, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line-close-moveTo-line-close case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.lineTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 3 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-close case
+ p.close();
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 3 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 6 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-cubicTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.cubicTo(SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-close case
+ p.close();
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.cubicTo(SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1);
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.cubicTo(SK_Scalar1*2, SK_Scalar1,
+ SK_Scalar1*2, SK_Scalar1,
+ SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 8 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+}
+
+struct SegmentInfo {
+ SkPath fPath;
+ int fPointCount;
+};
+
+#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
+
+static void test_segment_masks(skiatest::Reporter* reporter) {
+ SkPath p;
+ p.moveTo(0, 0);
+ p.quadTo(100, 100, 200, 200);
+ REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p.reset();
+ p.moveTo(0, 0);
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+}
+
+static void test_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::Iter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that setting an empty path works
+ noPathIter.setPath(p, false);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that close path makes no difference for an empty path
+ noPathIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::Iter iter(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that close path makes no difference
+ SkPath::Iter forceCloseIter(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that a move-only path produces nothing when iterated.
+ p.moveTo(SK_Scalar1, 0);
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // No matter how many moves we add, we should still get nothing back.
+ p.moveTo(SK_Scalar1*2, 0);
+ p.moveTo(SK_Scalar1*3, 0);
+ p.moveTo(SK_Scalar1*4, 0);
+ p.moveTo(SK_Scalar1*5, 0);
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Nor should force closing
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Initial closes should be ignored
+ p.reset();
+ p.close();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+ // Even if force closed
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Move/close sequences should also be ignored
+ p.reset();
+ p.close();
+ p.moveTo(SK_Scalar1, 0);
+ p.close();
+ p.close();
+ p.moveTo(SK_Scalar1*2, 0);
+ p.close();
+ p.moveTo(SK_Scalar1*3, 0);
+ p.moveTo(SK_Scalar1*4, 0);
+ p.close();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+ // Even if force closed
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // The GM degeneratesegments.cpp test is more extensive
+}
+
+static void test_raw_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::RawIter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that setting an empty path works
+ noPathIter.setPath(p);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::RawIter iter(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that a move-only path returns the move.
+ p.moveTo(SK_Scalar1, 0);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // No matter how many moves we add, we should get them all back
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Initial close is never ever stored
+ p.reset();
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Move/close sequences
+ p.reset();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1, 0);
+ p.close();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Generate random paths and verify
+ SkPoint randomPts[25];
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 0; j < 5; ++j) {
+ randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
+ }
+ }
+
+ // 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 nextVerb;
+ for (int i = 0; i < 500; ++i) {
+ p.reset();
+ bool lastWasClose = true;
+ bool haveMoveTo = false;
+ int numPoints = 0;
+ int numVerbs = (rand.nextU() >> 16) % 10;
+ int numIterVerbs = 0;
+ for (int j = 0; j < numVerbs; ++j) {
+ do {
+ nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
+ } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
+ int numRequiredPts;
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.moveTo(expectedPts[numPoints]);
+ numPoints += 1;
+ lastWasClose = false;
+ haveMoveTo = true;
+ break;
+ case SkPath::kLine_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.lineTo(expectedPts[numPoints]);
+ numPoints += 1;
+ lastWasClose = false;
+ break;
+ case SkPath::kQuad_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
+ numPoints += 2;
+ lastWasClose = false;
+ break;
+ case SkPath::kCubic_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
+ p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
+ expectedPts[numPoints + 2]);
+ numPoints += 3;
+ lastWasClose = false;
+ break;
+ case SkPath::kClose_Verb:
+ p.close();
+ lastWasClose = true;
+ break;
+ default:;
+ }
+ expectedVerbs[numIterVerbs++] = nextVerb;
+ }
+
+ iter.setPath(p);
+ numVerbs = numIterVerbs;
+ numIterVerbs = 0;
+ int numIterPts = 0;
+ SkPoint lastMoveTo;
+ SkPoint lastPt;
+ lastMoveTo.set(0, 0);
+ lastPt.set(0, 0);
+ while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
+ REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
+ numIterVerbs++;
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints);
+ REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
+ lastPt = lastMoveTo = pts[0];
+ numIterPts += 1;
+ break;
+ case SkPath::kLine_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ lastPt = pts[1];
+ numIterPts += 1;
+ break;
+ case SkPath::kQuad_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ lastPt = pts[2];
+ numIterPts += 2;
+ break;
+ case SkPath::kCubic_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
+ lastPt = pts[3];
+ numIterPts += 3;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
+ lastPt = lastMoveTo;
+ break;
+ default:;
+ }
+ }
+ REPORTER_ASSERT(reporter, numIterPts == numPoints);
+ REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
+ }
+}
+
void TestPath(skiatest::Reporter* reporter);
void TestPath(skiatest::Reporter* reporter) {
{
@@ -186,6 +1027,8 @@ void TestPath(skiatest::Reporter* reporter) {
SkRect bounds, bounds2;
REPORTER_ASSERT(reporter, p.isEmpty());
+ REPORTER_ASSERT(reporter, 0 == p.countPoints());
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
REPORTER_ASSERT(reporter, p.isConvex());
REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
REPORTER_ASSERT(reporter, !p.isInverseFillType());
@@ -198,14 +1041,24 @@ void TestPath(skiatest::Reporter* reporter) {
p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
check_convex_bounds(reporter, p, bounds);
+ // we have quads or cubics
+ REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
p.reset();
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, p.isEmpty());
+
p.addOval(bounds);
check_convex_bounds(reporter, p, bounds);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
p.reset();
p.addRect(bounds);
check_convex_bounds(reporter, p, bounds);
+ // we have only lines
+ REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
REPORTER_ASSERT(reporter, p != p2);
REPORTER_ASSERT(reporter, !(p == p2));
@@ -222,9 +1075,8 @@ void TestPath(skiatest::Reporter* reporter) {
p.offset(SK_Scalar1*3, SK_Scalar1*4);
REPORTER_ASSERT(reporter, bounds == p.getBounds());
-#if 0 // isRect needs to be implemented
REPORTER_ASSERT(reporter, p.isRect(NULL));
- bounds.setEmpty();
+ bounds2.setEmpty();
REPORTER_ASSERT(reporter, p.isRect(&bounds2));
REPORTER_ASSERT(reporter, bounds == bounds2);
@@ -232,16 +1084,19 @@ void TestPath(skiatest::Reporter* reporter) {
bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
p.addRect(bounds);
REPORTER_ASSERT(reporter, !p.isRect(NULL));
-#endif
-
- SkPoint pt;
-
- p.moveTo(SK_Scalar1, 0);
- p.getLastPt(&pt);
- REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
+ test_isRect(reporter);
+ test_zero_length_paths(reporter);
+ test_direction(reporter);
test_convexity(reporter);
test_convexity2(reporter);
+ test_close(reporter);
+ test_segment_masks(reporter);
+ test_flattening(reporter);
+ test_transform(reporter);
+ test_bounds(reporter);
+ test_iter(reporter);
+ test_raw_iter(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/PointTest.cpp b/tests/PointTest.cpp
new file mode 100644
index 0000000..876a272
--- /dev/null
+++ b/tests/PointTest.cpp
@@ -0,0 +1,46 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+// Unit tests for src/core/SkPoint.cpp and its header
+
+#include "SkPoint.h"
+#include "Test.h"
+
+// Tests that SkPoint::length() and SkPoint::Length() both return
+// approximately expectedLength for this (x,y).
+static void test_length(skiatest::Reporter* reporter, SkScalar x, SkScalar y,
+ SkScalar expectedLength) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar s1 = point.length();
+ SkScalar s2 = SkPoint::Length(x, y);
+ REPORTER_ASSERT(reporter, s1 == s2);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLength));
+}
+
+// Tests SkPoint::Normalize() for this (x,y)
+static void test_Normalize(skiatest::Reporter* reporter,
+ SkScalar x, SkScalar y) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar oldLength = point.length();
+ SkScalar returned = SkPoint::Normalize(&point);
+ SkScalar newLength = point.length();
+ REPORTER_ASSERT(reporter, returned == oldLength);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
+}
+
+void PointTest(skiatest::Reporter* reporter) {
+ test_length(reporter, SkIntToScalar(3), SkIntToScalar(4), SkIntToScalar(5));
+ test_length(reporter, SkFloatToScalar(0.6), SkFloatToScalar(0.8),
+ SK_Scalar1);
+ test_Normalize(reporter, SkIntToScalar(3), SkIntToScalar(4));
+ test_Normalize(reporter, SkFloatToScalar(0.6), SkFloatToScalar(0.8));
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Point", PointTestClass, PointTest)
diff --git a/tests/QuickRejectTest.cpp b/tests/QuickRejectTest.cpp
new file mode 100644
index 0000000..8cde327
--- /dev/null
+++ b/tests/QuickRejectTest.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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 "SkCanvas.h"
+#include "SkDrawLooper.h"
+#include "Test.h"
+
+/*
+ * Subclass of looper that just draws once, with an offset in X.
+ */
+class TestLooper : public SkDrawLooper {
+public:
+ bool fOnce;
+
+ virtual void init(SkCanvas*) SK_OVERRIDE {
+ fOnce = true;
+ }
+
+ virtual bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE {
+ if (fOnce) {
+ fOnce = false;
+ canvas->translate(SkIntToScalar(10), 0);
+ return true;
+ }
+ return false;
+ }
+
+ virtual Factory getFactory() SK_OVERRIDE {
+ return NULL;
+ }
+};
+
+static void test_drawBitmap(skiatest::Reporter* reporter) {
+ SkBitmap src;
+ src.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ src.allocPixels();
+ src.eraseColor(SK_ColorWHITE);
+
+ SkBitmap dst;
+ dst.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ dst.allocPixels();
+ dst.eraseColor(0);
+
+ SkCanvas canvas(dst);
+ SkPaint paint;
+
+ // we are initially transparent
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // we see the bitmap drawn
+ canvas.drawBitmap(src, 0, 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+
+ // reverify we are clear again
+ dst.eraseColor(0);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // if the bitmap is clipped out, we don't draw it
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // now install our looper, which will draw, since it internally translates
+ // to the left. The test is to ensure that canvas' quickReject machinary
+ // allows us through, even though sans-looper we would look like we should
+ // be clipped out.
+ paint.setLooper(new TestLooper)->unref();
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+}
+
+static void test(skiatest::Reporter* reporter) {
+ test_drawBitmap(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("QuickReject", QuickRejectClass, test)
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
new file mode 100644
index 0000000..b531e92
--- /dev/null
+++ b/tests/ReadPixelsTest.cpp
@@ -0,0 +1,391 @@
+
+/*
+ * 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 "SkRegion.h"
+#include "SkGpuDevice.h"
+
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+
+namespace {
+SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0xff;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+SkPMColor getBitmapColor(int x, int y, int w, int h) {
+ int n = y * w + x;
+
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ return SkPackARGB32(0xff, r, g , b);
+}
+
+SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
+ uint32_t color,
+ bool* premul) {
+ const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
+ U8CPU a,r,g,b;
+ *premul = false;
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ return color;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ *premul = true;
+ a = SkGetPackedA32(color);
+ r = SkGetPackedR32(color);
+ g = SkGetPackedG32(color);
+ b = SkGetPackedB32(color);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kBGRA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[2]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[0]);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kRGBA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[2]);
+ break;
+ }
+ if (*premul) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
+void fillCanvas(SkCanvas* canvas) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
+ bool alloc = bmp.allocPixels();
+ SkASSERT(alloc);
+ SkAutoLockPixels alp(bmp);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
+ *pixel = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+void fillBitmap(SkBitmap* bitmap) {
+ SkASSERT(bitmap->lockPixelsAreWritable());
+ SkAutoLockPixels alp(*bitmap);
+ int w = bitmap->width();
+ int h = bitmap->height();
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
+ *pixel = getBitmapColor(x, y, w, h);
+ }
+ }
+}
+
+bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+// checks the bitmap contains correct pixels after the readPixels
+// if the bitmap was prefilled with pixels it checks that these weren't
+// overwritten in the area outside the readPixels.
+bool checkRead(skiatest::Reporter* reporter,
+ const SkBitmap& bitmap,
+ int x, int y,
+ bool checkCanvasPixels,
+ bool checkBitmapPixels,
+ SkCanvas::Config8888 config8888) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
+ SkASSERT(!bitmap.isNull());
+ SkASSERT(checkCanvasPixels || checkBitmapPixels);
+
+ int bw = bitmap.width();
+ int bh = bitmap.height();
+
+ SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
+ SkIRect clippedSrcRect = DEV_RECT;
+ if (!clippedSrcRect.intersect(srcRect)) {
+ clippedSrcRect.setEmpty();
+ }
+ bool failed = false;
+ SkAutoLockPixels alp(bitmap);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels());
+ for (int by = 0; by < bh; ++by) {
+ for (int bx = 0; bx < bw; ++bx) {
+ int devx = bx + srcRect.fLeft;
+ int devy = by + srcRect.fTop;
+
+ uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel());
+
+ if (clippedSrcRect.contains(devx, devy)) {
+ if (checkCanvasPixels) {
+ SkPMColor canvasPixel = getCanvasColor(devx, devy);
+ bool didPremul;
+ SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, pixel, &didPremul);
+ bool check;
+ REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul));
+ if (!check) {
+ failed = true;
+ }
+ }
+ } else if (checkBitmapPixels) {
+ REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel);
+ if (getBitmapColor(bx, by, bw, bh) != pixel) {
+ failed = true;
+ }
+ }
+ }
+ }
+ return !failed;
+}
+
+enum BitmapInit {
+ kFirstBitmapInit = 0,
+
+ kNoPixels_BitmapInit = kFirstBitmapInit,
+ kTight_BitmapInit,
+ kRowBytes_BitmapInit,
+
+ kBitmapInitCnt
+};
+
+BitmapInit nextBMI(BitmapInit bmi) {
+ int x = bmi;
+ return static_cast<BitmapInit>(++x);
+}
+
+
+void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) {
+ int w = rect.width();
+ int h = rect.height();
+ int rowBytes = 0;
+ bool alloc = true;
+ switch (init) {
+ case kNoPixels_BitmapInit:
+ alloc = false;
+ case kTight_BitmapInit:
+ break;
+ case kRowBytes_BitmapInit:
+ rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor);
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
+ if (alloc) {
+ bitmap->allocPixels();
+ }
+}
+
+void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) {
+ SkCanvas canvas;
+
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (int dtype = 1; dtype < 2; ++dtype) {
+
+ if (0 == dtype) {
+ canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config,
+ DEV_W,
+ DEV_H,
+ 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,
+ DEV_W,
+ DEV_H))->unref();
+ }
+ fillCanvas(&canvas);
+
+ static const SkCanvas::Config8888 gReadConfigs[] = {
+ SkCanvas::kNative_Premul_Config8888,
+ 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_Premul_Config8888,
+ SkCanvas::kBGRA_Unpremul_Config8888,
+#endif
+ SkCanvas::kRGBA_Premul_Config8888,
+ SkCanvas::kRGBA_Unpremul_Config8888,
+ };
+ for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
+ const SkIRect& srcRect = testRects[rect];
+ for (BitmapInit bmi = kFirstBitmapInit;
+ bmi < kBitmapInitCnt;
+ bmi = nextBMI(bmi)) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
+ SkCanvas::Config8888 config8888 = gReadConfigs[c];
+ SkBitmap bmp;
+ init_bitmap(&bmp, srcRect, bmi);
+
+ // if the bitmap has pixels allocated before the readPixels,
+ // note that and fill them with pattern
+ bool startsWithPixels = !bmp.isNull();
+ if (startsWithPixels) {
+ fillBitmap(&bmp);
+ }
+
+ bool success =
+ canvas.readPixels(&bmp, srcRect.fLeft,
+ srcRect.fTop, config8888);
+
+ // we expect to succeed when the read isn't fully clipped
+ // out.
+ bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT);
+ // determine whether we expected the read to succeed.
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+
+ if (success || startsWithPixels) {
+ checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
+ success, startsWithPixels, config8888);
+ } else {
+ // if we had no pixels beforehand and the readPixels
+ // failed then our bitmap should still not have pixels
+ REPORTER_ASSERT(reporter, bmp.isNull());
+ }
+ }
+ // check the old webkit version of readPixels that clips the
+ // bitmap size
+ SkBitmap wkbmp;
+ bool success = canvas.readPixels(srcRect, &wkbmp);
+ SkIRect clippedRect = DEV_RECT;
+ if (clippedRect.intersect(srcRect)) {
+ REPORTER_ASSERT(reporter, success);
+ checkRead(reporter, wkbmp, clippedRect.fLeft,
+ clippedRect.fTop, true, false,
+ SkCanvas::kNative_Premul_Config8888);
+ } else {
+ REPORTER_ASSERT(reporter, !success);
+ }
+ }
+ }
+ }
+}
+}
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest)
+
diff --git a/tests/Reader32Test.cpp b/tests/Reader32Test.cpp
index cad2d33..13f2fc4 100644
--- a/tests/Reader32Test.cpp
+++ b/tests/Reader32Test.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * 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 "SkReader32.h"
#include "Test.h"
diff --git a/tests/RefDictTest.cpp b/tests/RefDictTest.cpp
index f52541b..83d1aef 100644
--- a/tests/RefDictTest.cpp
+++ b/tests/RefDictTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRefDict.h"
diff --git a/tests/RegionTest.cpp b/tests/RegionTest.cpp
index ee34d8b..a1bf699 100644
--- a/tests/RegionTest.cpp
+++ b/tests/RegionTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRegion.h"
#include "SkRandom.h"
diff --git a/tests/ScalarTest.cpp b/tests/ScalarTest.cpp
new file mode 100644
index 0000000..d2c05ab
--- /dev/null
+++ b/tests/ScalarTest.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "SkFloatingPoint.h"
+#include "SkMath.h"
+#include "SkPoint.h"
+#include "SkRandom.h"
+
+#ifdef SK_CAN_USE_FLOAT
+
+static bool isFinite_int(float x) {
+ uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
+ int exponent = bits << 1 >> 24;
+ return exponent != 0xFF;
+}
+
+static bool isFinite_float(float x) {
+ return sk_float_isfinite(x);
+}
+
+static bool isFinite_mulzero(float x) {
+ float y = x * 0;
+ return y == y;
+}
+
+// return true if the float is finite
+typedef bool (*IsFiniteProc1)(float);
+
+static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
+ return proc(x) && proc(y);
+}
+
+static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
+ return proc(x * 0 + y * 0);
+}
+
+// return true if both floats are finite
+typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
+
+#endif
+
+enum FloatClass {
+ kFinite,
+ kInfinite,
+ kNaN
+};
+
+static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
+ // our sk_float_is... function may return int instead of bool,
+ // hence the double ! to turn it into a bool
+ REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
+}
+
+static void test_isfinite(skiatest::Reporter* reporter) {
+#ifdef SK_CAN_USE_FLOAT
+ struct Rec {
+ float fValue;
+ bool fIsFinite;
+ };
+
+ float max = 3.402823466e+38f;
+ float inf = max * max;
+ float nan = inf * 0;
+
+ test_floatclass(reporter, 0, kFinite);
+ test_floatclass(reporter, max, kFinite);
+ test_floatclass(reporter, -max, kFinite);
+ test_floatclass(reporter, inf, kInfinite);
+ test_floatclass(reporter, -inf, kInfinite);
+ test_floatclass(reporter, nan, kNaN);
+ test_floatclass(reporter, -nan, kNaN);
+
+ const Rec data[] = {
+ { 0, true },
+ { 1, true },
+ { -1, true },
+ { max * 0.75, true },
+ { max, true },
+ { -max * 0.75, true },
+ { -max, true },
+ { inf, false },
+ { -inf, false },
+ { nan, false },
+ };
+
+ const IsFiniteProc1 gProc1[] = {
+ isFinite_int,
+ isFinite_float,
+ isFinite_mulzero
+ };
+ const IsFiniteProc2 gProc2[] = {
+ isFinite2_and,
+ isFinite2_mulzeroadd
+ };
+
+ size_t i, n = SK_ARRAY_COUNT(data);
+
+ for (i = 0; i < n; ++i) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ const Rec& rec = data[i];
+ bool finite = gProc1[k](rec.fValue);
+ REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ const Rec& rec0 = data[i];
+ for (size_t j = 0; j < n; ++j) {
+ const Rec& rec1 = data[j];
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ IsFiniteProc1 proc1 = gProc1[k];
+
+ for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
+ bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
+ bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
+ REPORTER_ASSERT(reporter, finite2 == finite);
+ }
+ }
+ }
+ }
+#endif
+}
+
+static void TestScalar(skiatest::Reporter* reporter) {
+ test_isfinite(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)
+
diff --git a/tests/ShaderOpacityTest.cpp b/tests/ShaderOpacityTest.cpp
new file mode 100644
index 0000000..a8177ee
--- /dev/null
+++ b/tests/ShaderOpacityTest.cpp
@@ -0,0 +1,119 @@
+
+/*
+ * 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 "SkShader.h"
+#include "SkGradientShader.h"
+#include "SkColorShader.h"
+
+static void test_bitmap(skiatest::Reporter* reporter) {
+ SkBitmap bmp;
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+
+ // test 1: bitmap without pixel data
+ SkShader* shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // From this point on, we have pixels
+ bmp.allocPixels();
+
+ // test 2: not opaque by default
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // test 3: explicitly opaque
+ bmp.setIsOpaque(true);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, shader->isOpaque());
+ shader->unref();
+
+ // test 4: explicitly not opaque
+ bmp.setIsOpaque(false);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+}
+
+static void test_gradient(skiatest::Reporter* reporter)
+{
+ SkPoint pts[2];
+ pts[0].iset(0, 0);
+ pts[1].iset(1, 0);
+ SkColor colors[2];
+ SkScalar pos[2] = {SkIntToScalar(0), SkIntToScalar(1)};
+ int count = 2;
+ SkShader::TileMode mode = SkShader::kClamp_TileMode;
+
+ // test 1: all opaque
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ SkShader* grad = SkGradientShader::CreateLinear(pts, colors, pos, count,
+ mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, grad->isOpaque());
+ grad->unref();
+
+ // test 2: all 0 alpha
+ colors[0] = SkColorSetARGB(0, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 3: one opaque, one transparent
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0x40, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 4: test 3, swapped
+ colors[0] = SkColorSetARGB(0x40, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+}
+
+static void test_color(skiatest::Reporter* reporter)
+{
+ SkColorShader colorShader1(SkColorSetARGB(0,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader1.isOpaque());
+ SkColorShader colorShader2(SkColorSetARGB(0xFF,0,0,0));
+ REPORTER_ASSERT(reporter, colorShader2.isOpaque());
+ SkColorShader colorShader3(SkColorSetARGB(0x7F,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader3.isOpaque());
+
+ // with inherrited color, shader must declare itself as opaque,
+ // since lack of opacity will depend solely on the paint
+ SkColorShader colorShader4;
+ REPORTER_ASSERT(reporter, colorShader4.isOpaque());
+}
+
+static void test_shader_opacity(skiatest::Reporter* reporter)
+{
+ test_gradient(reporter);
+ test_color(reporter);
+ test_bitmap(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("ShaderOpacity", ShaderOpacityTestClass, test_shader_opacity)
diff --git a/tests/Sk64Test.cpp b/tests/Sk64Test.cpp
index 9fb49eb..64eef75 100644
--- a/tests/Sk64Test.cpp
+++ b/tests/Sk64Test.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRandom.h"
#include <math.h>
diff --git a/tests/SortTest.cpp b/tests/SortTest.cpp
index 2ca5553..9b4642f 100644
--- a/tests/SortTest.cpp
+++ b/tests/SortTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRandom.h"
#include "SkTSearch.h"
diff --git a/tests/SrcOverTest.cpp b/tests/SrcOverTest.cpp
index e95485b..d1e65a9 100644
--- a/tests/SrcOverTest.cpp
+++ b/tests/SrcOverTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkColorPriv.h"
#include "SkXfermode.h"
diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp
index e62f2ed..85b1b2e 100644
--- a/tests/StreamTest.cpp
+++ b/tests/StreamTest.cpp
@@ -1,6 +1,14 @@
+
+/*
+ * 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 "SkRandom.h"
#include "SkStream.h"
+#include "SkData.h"
#define MAX_SIZE (256 * 1024)
@@ -81,13 +89,51 @@ static void TestWStream(skiatest::Reporter* reporter) {
for (i = 0; i < 100; i++) {
REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
}
- REPORTER_ASSERT(reporter, memcmp(dst, ds.getStream(), 100*26) == 0);
+
+ {
+ SkData* data = ds.copyToData();
+ REPORTER_ASSERT(reporter, 100 * 26 == data->size());
+ REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0);
+ data->unref();
+ }
delete[] dst;
}
+static void TestPackedUInt(skiatest::Reporter* reporter) {
+ // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
+ // so we test values around each of those transitions (and a few others)
+ const size_t sizes[] = {
+ 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
+ 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
+ 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
+ 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
+ };
+
+
+ size_t i;
+ char buffer[sizeof(sizes) * 4];
+
+ SkMemoryWStream wstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ bool success = wstream.writePackedUInt(sizes[i]);
+ REPORTER_ASSERT(reporter, success);
+ }
+ wstream.flush();
+
+ SkMemoryStream rstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ size_t n = rstream.readPackedUInt();
+ if (sizes[i] != n) {
+ SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n);
+ }
+ REPORTER_ASSERT(reporter, sizes[i] == n);
+ }
+}
+
static void TestStreams(skiatest::Reporter* reporter) {
TestRStream(reporter);
TestWStream(reporter);
+ TestPackedUInt(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/StringTest.cpp b/tests/StringTest.cpp
index 270ccfd..52a038d 100644
--- a/tests/StringTest.cpp
+++ b/tests/StringTest.cpp
@@ -1,5 +1,38 @@
+
+/*
+ * 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 "SkString.h"
+#include <stdarg.h>
+
+
+// Windows vsnprintf doesn't 0-terminate safely), but is so far
+// encapsulated in SkString that we can't test it directly.
+
+#ifdef SK_BUILD_FOR_WIN
+ #define VSNPRINTF(buffer, size, format, args) \
+ vsnprintf_s(buffer, size, _TRUNCATE, format, args)
+#else
+ #define VSNPRINTF vsnprintf
+#endif
+
+#define ARGS_TO_BUFFER(format, buffer, size) \
+ do { \
+ va_list args; \
+ va_start(args, format); \
+ VSNPRINTF(buffer, size, format, args); \
+ va_end(args); \
+ } while (0)
+
+void printfAnalog(char* buffer, int size, const char format[], ...) {
+ ARGS_TO_BUFFER(format, buffer, size);
+}
+
+
static void TestString(skiatest::Reporter* reporter) {
SkString a;
@@ -74,8 +107,13 @@ static void TestString(skiatest::Reporter* reporter) {
{ -SK_Scalar1, "-1" },
{ SK_Scalar1/2, "0.5" },
#ifdef SK_SCALAR_IS_FLOAT
+ #ifdef SK_BUILD_FOR_WIN
+ { 3.4028234e38f, "3.4028235e+038" },
+ { -3.4028234e38f, "-3.4028235e+038" },
+ #else
{ 3.4028234e38f, "3.4028235e+38" },
{ -3.4028234e38f, "-3.4028235e+38" },
+ #endif
#endif
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
@@ -85,6 +123,19 @@ static void TestString(skiatest::Reporter* reporter) {
// SkDebugf(" received <%s> expected <%s>\n", a.c_str(), gRec[i].fString);
REPORTER_ASSERT(reporter, a.equals(gRec[i].fString));
}
+
+ REPORTER_ASSERT(reporter, SkStringPrintf("%i", 0).equals("0"));
+
+ char buffer [40];
+ memset(buffer, 'a', 40);
+ REPORTER_ASSERT(reporter, buffer[18] == 'a');
+ REPORTER_ASSERT(reporter, buffer[19] == 'a');
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+ printfAnalog(buffer, 20, "%30d", 0);
+ REPORTER_ASSERT(reporter, buffer[18] == ' ');
+ REPORTER_ASSERT(reporter, buffer[19] == 0);
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+
}
#include "TestClassDef.h"
diff --git a/tests/Test.cpp b/tests/Test.cpp
index 2bcd3e0..1c3b691 100644
--- a/tests/Test.cpp
+++ b/tests/Test.cpp
@@ -1,5 +1,16 @@
+
+/*
+ * 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 "GrContext.h"
+#include "SkNativeGLContext.h"
+#include "SkTLazy.h"
+
using namespace skiatest;
Reporter::Reporter() {
@@ -63,3 +74,24 @@ bool Test::run() {
return fReporter->getCurrSuccess();
}
+///////////////////////////////////////////////////////////////////////////////
+
+
+GrContext* GpuTest::GetContext() {
+ // preserve this order, we want gGrContext destroyed after gEGLContext
+ static SkTLazy<SkNativeGLContext> gGLContext;
+ static SkAutoTUnref<GrContext> gGrContext;
+
+ if (NULL == gGrContext.get()) {
+ gGLContext.init();
+ if (gGLContext.get()->init(800, 600)) {
+ GrPlatform3DContext ctx = reinterpret_cast<GrPlatform3DContext>(gGLContext.get()->gl());
+ gGrContext.reset(GrContext::Create(kOpenGL_Shaders_GrEngine, ctx));
+ }
+ }
+ if (gGLContext.get()) {
+ gGLContext.get()->makeCurrent();
+ }
+ return gGrContext.get();
+}
+
diff --git a/tests/Test.h b/tests/Test.h
index de51801..8728040 100644
--- a/tests/Test.h
+++ b/tests/Test.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef skiatest_Test_DEFINED
#define skiatest_Test_DEFINED
@@ -5,6 +12,9 @@
#include "SkString.h"
#include "SkTRegistry.h"
+class GrContext;
+class SkGLContext;
+
namespace skiatest {
class Test;
@@ -87,6 +97,17 @@ namespace skiatest {
SkString fName;
};
+ class GpuTest : public Test{
+ public:
+ GpuTest() : Test() {
+ fContext = GetContext();
+ }
+ protected:
+ GrContext* fContext;
+ private:
+ static GrContext* GetContext();
+ };
+
typedef SkTRegistry<Test*, void*> TestRegistry;
}
diff --git a/tests/TestClassDef.h b/tests/TestClassDef.h
index 0773f5a..ffef2a1 100644
--- a/tests/TestClassDef.h
+++ b/tests/TestClassDef.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
/* This file is meant to be included by .cpp files, so it can spew out a
customized class + global definition.
@@ -22,3 +29,18 @@
static TestRegistry gReg(classname::Factory); \
}
+#define DEFINE_GPUTESTCLASS(uiname, classname, function) \
+ namespace skiatest { \
+ class classname : public GpuTest { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(classname); } \
+ protected: \
+ virtual void onGetName(SkString* name) { name->set(uiname); } \
+ virtual void onRun(Reporter* reporter) { \
+ if (fContext) { \
+ function(reporter, fContext); \
+ } \
+ } \
+ }; \
+ static TestRegistry gReg(classname::Factory); \
+ }
diff --git a/tests/TestSize.cpp b/tests/TestSize.cpp
index 9e0aaaa..97a6668 100644
--- a/tests/TestSize.cpp
+++ b/tests/TestSize.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkSize.h"
diff --git a/tests/ToUnicode.cpp b/tests/ToUnicode.cpp
new file mode 100644
index 0000000..c0a945a
--- /dev/null
+++ b/tests/ToUnicode.cpp
@@ -0,0 +1,133 @@
+
+/*
+ * Copyright 2010 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include <string>
+
+#include "Test.h"
+#include "SkData.h"
+#include "SkPDFTypes.h"
+#include "SkPDFFont.h"
+#include "SkStream.h"
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const char* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data.size()) {
+ return false;
+ }
+ if (len != strlen(buffer)) {
+ return false;
+ }
+ return memcmp(data.bytes() + offset, buffer, len) == 0;
+}
+
+void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
+ const SkPDFGlyphSet* subset,
+ SkDynamicMemoryWStream* cmap);
+
+static void TestToUnicode(skiatest::Reporter* reporter) {
+ SkTDArray<SkUnichar> glyphToUnicode;
+ SkTDArray<uint16_t> glyphsInSubset;
+ SkPDFGlyphSet subset;
+
+ glyphToUnicode.push(0); // 0
+ glyphToUnicode.push(0); // 1
+ glyphToUnicode.push(0); // 2
+ glyphsInSubset.push(3);
+ glyphToUnicode.push(0x20); // 3
+ glyphsInSubset.push(4);
+ glyphToUnicode.push(0x25); // 4
+ glyphsInSubset.push(5);
+ glyphToUnicode.push(0x27); // 5
+ glyphsInSubset.push(6);
+ glyphToUnicode.push(0x28); // 6
+ glyphsInSubset.push(7);
+ glyphToUnicode.push(0x29); // 7
+ glyphsInSubset.push(8);
+ glyphToUnicode.push(0x2F); // 8
+ glyphsInSubset.push(9);
+ glyphToUnicode.push(0x33); // 9
+ glyphToUnicode.push(0); // 10
+ glyphsInSubset.push(11);
+ glyphToUnicode.push(0x35); // 11
+ glyphsInSubset.push(12);
+ glyphToUnicode.push(0x36); // 12
+ for (uint16_t i = 13; i < 0xFE; ++i) {
+ glyphToUnicode.push(0); // Zero from index 0x9 to 0xFD
+ }
+ glyphsInSubset.push(0xFE);
+ glyphToUnicode.push(0x1010);
+ glyphsInSubset.push(0xFF);
+ glyphToUnicode.push(0x1011);
+ glyphsInSubset.push(0x100);
+ glyphToUnicode.push(0x1012);
+ glyphsInSubset.push(0x101);
+ glyphToUnicode.push(0x1013);
+
+ SkDynamicMemoryWStream buffer;
+ subset.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset, &buffer);
+
+ char expectedResult[] =
+"4 beginbfchar\n\
+<0003> <0020>\n\
+<0004> <0025>\n\
+<0008> <002F>\n\
+<0009> <0033>\n\
+endbfchar\n\
+4 beginbfrange\n\
+<0005> <0007> <0027>\n\
+<000B> <000C> <0035>\n\
+<00FE> <00FF> <1010>\n\
+<0100> <0101> <1012>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+
+ glyphToUnicode.reset();
+ glyphsInSubset.reset();
+ SkPDFGlyphSet subset2;
+
+ // Test mapping:
+ // I n s t a l
+ // Glyph id 2c 51 56 57 44 4f
+ // Unicode 49 6e 73 74 61 6c
+ for (size_t i = 0; i < 100; ++i) {
+ glyphToUnicode.push(i + 29);
+ }
+
+ glyphsInSubset.push(0x2C);
+ glyphsInSubset.push(0x44);
+ glyphsInSubset.push(0x4F);
+ glyphsInSubset.push(0x51);
+ glyphsInSubset.push(0x56);
+ glyphsInSubset.push(0x57);
+
+ SkDynamicMemoryWStream buffer2;
+ subset2.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset2, &buffer2);
+
+ char expectedResult2[] =
+"4 beginbfchar\n\
+<002C> <0049>\n\
+<0044> <0061>\n\
+<004F> <006C>\n\
+<0051> <006E>\n\
+endbfchar\n\
+1 beginbfrange\n\
+<0056> <0057> <0073>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer2, 0, expectedResult2,
+ buffer2.getOffset()));
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("ToUnicode", ToUnicodeTestClass, TestToUnicode)
diff --git a/tests/TriangulationTest.cpp b/tests/TriangulationTest.cpp
index 9d47181..8d692c7 100644
--- a/tests/TriangulationTest.cpp
+++ b/tests/TriangulationTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "../../src/core/SkConcaveToTriangles.h"
#include "SkGeometry.h"
diff --git a/tests/UnicodeTest.cpp b/tests/UnicodeTest.cpp
new file mode 100644
index 0000000..602ff81
--- /dev/null
+++ b/tests/UnicodeTest.cpp
@@ -0,0 +1,45 @@
+
+/*
+ * 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 "SkUtils.h"
+
+// Unicode Variation Selector ranges: inclusive
+#define UVS_MIN0 0x180B
+#define UVS_MAX0 0x180D
+#define UVS_MIN1 0xFE00
+#define UVS_MAX1 0xFE0F
+#define UVS_MIN2 0xE0100
+#define UVS_MAX2 0xE01EF
+
+static bool isUVS(SkUnichar uni) {
+ return (uni >= UVS_MIN0 && uni <= UVS_MAX0) ||
+ (uni >= UVS_MIN1 && uni <= UVS_MAX1) ||
+ (uni >= UVS_MIN2 && uni <= UVS_MAX2);
+}
+
+static void test_uvs(skiatest::Reporter* reporter) {
+ // [min, max], [min, max] ... inclusive
+ static const SkUnichar gRanges[] = {
+ UVS_MIN0, UVS_MAX0, UVS_MIN1, UVS_MAX1, UVS_MIN2, UVS_MAX2
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRanges); i += 2) {
+ for (SkUnichar uni = gRanges[i] - 8; uni <= gRanges[i+1] + 8; ++uni) {
+ bool uvs0 = isUVS(uni);
+ bool uvs1 = SkUnichar_IsVariationSelector(uni);
+ REPORTER_ASSERT(reporter, uvs0 == uvs1);
+ }
+ }
+}
+
+static void TestUnicode(skiatest::Reporter* reporter) {
+ test_uvs(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Unicode", TestUnicodeClass, TestUnicode)
diff --git a/tests/UtilsTest.cpp b/tests/UtilsTest.cpp
index 4f36afe..f1b1ea9 100644
--- a/tests/UtilsTest.cpp
+++ b/tests/UtilsTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkRandom.h"
#include "SkRefCnt.h"
diff --git a/tests/WArrayTest.cpp b/tests/WArrayTest.cpp
new file mode 100644
index 0000000..428ca5f
--- /dev/null
+++ b/tests/WArrayTest.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 the implementation so we can make an appropriate template instance.
+#include "SkAdvancedTypefaceMetrics.cpp"
+
+using namespace skia_advanced_typeface_metrics_utils;
+
+namespace {
+
+// Negative values and zeros in a range plus trailing zeros.
+// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+const int16_t data1[] = {-1, 0, -3, 4, 5, 6, 7, 0, 0, 0, 8, 0, 0, 0, 0};
+const char* expected1 = "0[-1 0 -3 4 5 6 7 0 0 0 8]";
+
+// Run with leading and trailing zeros.
+// Test rules: d 0 1 2 3 4 5 6 7 8 9 10 11
+const int16_t data2[] = {0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 0, 0};
+const char* expected2 = "3 9 100";
+
+// Removing 0's from a range.
+// Test rules: a 0 1 2 3 4 5 6 7 8 9 10 11
+const int16_t data3[] = {1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 0, 5};
+const char* expected3 = "0[1 2 0 0 0 3 4] 11[5]";
+
+// Removing 0's from a run/range and between runs.
+// Test rules: a, b 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15
+const int16_t data4[] = {1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 0, 3, 4};
+const char* expected4 = "0[1 0 0 0 1] 5 7 2 8[3] 13[3 4]";
+
+// Runs that starts outside a range.
+// Test rules: a, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+const int16_t data5[] = {1, 1, 2, 3, 0, 0, 0, 0, 5, 5, 6, 7, 0, 0, 0, 0, 8, 0};
+const char* expected5 = "0 1 1 2[2 3] 8 9 5 10[6 7] 16[8]";
+
+// Zeros and runs that should be broken out.
+// Test rules: a, b, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+const int16_t data6[] = {1, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 6};
+const char* expected6 = "0[1] 5[1 2 3 3 4] 10 12 5 13[6]";
+
+// Don't cares that aren't enough to break out a run.
+// Test rules: c 0 1 2 3 4 5
+const int16_t data7[] = {1, 2, 10, 11, 2, 3};
+const char* expected7 = "0[1 2 10 11 2 3]";
+const uint32_t subset7[] = {0, 1, 4, 5};
+const char* expectedSubset7 = "0[1 2 0 0 2 3]";
+
+// Don't cares that are enough to break out a run.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data8[] = {1, 2, 10, 11, 12, 2, 3};
+const char* expected8 = "0[1 2 10 11 12 2 3]";
+const uint32_t subset8[] = {0, 1, 5, 6};
+const char* expectedSubset8 = "0[1] 1 5 2 6[3]";
+
+// Leading don't cares.
+// Test rules: d 0 1 2 3 4
+const int16_t data9[] = {1, 1, 10, 2, 3};
+const char* expected9 = "0 1 1 2[10 2 3]";
+const uint32_t subset9[] = {0, 1, 3, 4};
+const char* expectedSubset9 = "0 1 1 3[2 3]";
+
+// Almost run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5
+const int16_t data10[] = {1, 2, 10, 11, 12, 3};
+const char* expected10 = "0[1 2 10 11 12 3]";
+const uint32_t subset10[] = {0, 1, 5};
+const char* expectedSubset10 = "0[1 2 0 0 0 3]";
+
+// Run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data11[] = {1, 2, 10, 11, 12, 13, 3};
+const char* expected11 = "0[1 2 10 11 12 13 3]";
+const uint32_t subset11[] = {0, 1, 6};
+const char* expectedSubset11 = "0[1 2] 6[3]";
+
+// Almost run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data12[] = {1, 10, 11, 2, 12, 13, 3};
+const char* expected12 = "0[1 10 11 2 12 13 3]";
+const uint32_t subset12[] = {0, 3, 6};
+const char* expectedSubset12 = "0[1 0 0 2 0 0 3]";
+
+// Run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6 7
+const int16_t data13[] = {1, 10, 11, 2, 2, 12, 13, 3};
+const char* expected13 = "0[1 10 11 2 2 12 13 3]";
+const uint32_t subset13[] = {0, 3, 4, 7};
+const char* expectedSubset13 = "0[1] 1 6 2 7[3]";
+
+// Enough don't cares to breakup something.
+// Test rules: a 0 1 2 3 4 5
+const int16_t data14[] = {1, 0, 0, 0, 0, 2};
+const char* expected14 = "0[1] 5[2]";
+const uint32_t subset14[] = {0, 5};
+const char* expectedSubset14 = "0[1] 5[2]";
+
+}
+
+static SkString stringify_advance_data(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* data) {
+ SkString result;
+ bool leadingSpace = false;
+ while (data != NULL) {
+ if (leadingSpace) {
+ result.appendf(" ");
+ } else {
+ leadingSpace = true;
+ }
+ switch(data->fType) {
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRun:
+ result.appendf("%d %d %d", data->fStartId, data->fEndId,
+ data->fAdvance[0]);
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRange:
+ result.appendf("%d[", data->fStartId);
+ for (int i = 0; i < data->fAdvance.count(); ++i) {
+ if (i > 0) {
+ result.appendf(" ");
+ }
+ result.appendf("%d", data->fAdvance[i]);
+ }
+ result.appendf("]");
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kDefault:
+ result.appendf("<Default=%d>", data->fAdvance[0]);
+ break;
+ }
+ data = data->fNext.get();
+ }
+ return result;
+}
+
+class TestWData {
+ public:
+ TestWData(skiatest::Reporter* reporter,
+ const int16_t advances[],
+ int advanceLen,
+ const uint32_t subset[],
+ int subsetLen,
+ const char* expected)
+ : fAdvances(advances)
+ , fAdvancesLen(advanceLen)
+ , fSubset(subset)
+ , fSubsetLen(subsetLen)
+ , fExpected(expected) {
+ REPORTER_ASSERT(reporter, RunTest());
+ }
+
+ private:
+ const int16_t* fAdvances;
+ const int fAdvancesLen;
+ const uint32_t* fSubset;
+ const int fSubsetLen;
+ const char* fExpected;
+
+ static bool getAdvance(TestWData* testCase, int gId, int16_t* advance) {
+ if (gId >= 0 && gId < testCase->fAdvancesLen) {
+ *advance = testCase->fAdvances[gId];
+ return true;
+ }
+ return false;
+ }
+
+ bool RunTest() {
+ SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t> > result;
+ result.reset(getAdvanceData(this, fAdvancesLen, fSubset, fSubsetLen,
+ getAdvance));
+
+ SkString stringResult = stringify_advance_data(result.get());
+ if (!stringResult.equals(fExpected)) {
+ printf("Expected: %s\n Result: %s\n", fExpected,
+ stringResult.c_str());
+ return false;
+ }
+ return true;
+ }
+};
+
+static void TestWArray(skiatest::Reporter* reporter) {
+ TestWData(reporter, data1, SK_ARRAY_COUNT(data1), NULL, 0, expected1);
+ TestWData(reporter, data2, SK_ARRAY_COUNT(data2), NULL, 0, expected2);
+ TestWData(reporter, data3, SK_ARRAY_COUNT(data3), NULL, 0, expected3);
+ TestWData(reporter, data4, SK_ARRAY_COUNT(data4), NULL, 0, expected4);
+ TestWData(reporter, data5, SK_ARRAY_COUNT(data5), NULL, 0, expected5);
+ TestWData(reporter, data6, SK_ARRAY_COUNT(data6), NULL, 0, expected6);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), NULL, 0, expected7);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), subset7,
+ SK_ARRAY_COUNT(subset7), expectedSubset7);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), NULL, 0, expected8);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), subset8,
+ SK_ARRAY_COUNT(subset8), expectedSubset8);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), NULL, 0, expected9);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), subset9,
+ SK_ARRAY_COUNT(subset9), expectedSubset9);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), NULL, 0, expected10);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), subset10,
+ SK_ARRAY_COUNT(subset10), expectedSubset10);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), NULL, 0, expected11);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), subset11,
+ SK_ARRAY_COUNT(subset11), expectedSubset11);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), NULL, 0, expected12);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), subset12,
+ SK_ARRAY_COUNT(subset12), expectedSubset12);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), NULL, 0, expected13);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), subset13,
+ SK_ARRAY_COUNT(subset13), expectedSubset13);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), NULL, 0, expected14);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), subset14,
+ SK_ARRAY_COUNT(subset14), expectedSubset14);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("WArray", WArrayTest, TestWArray)
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
new file mode 100644
index 0000000..0c5b7b9
--- /dev/null
+++ b/tests/WritePixelsTest.cpp
@@ -0,0 +1,419 @@
+
+/*
+ * 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 "SkRegion.h"
+#include "SkGpuDevice.h"
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+static const U8CPU DEV_PAD = 0xee;
+
+namespace {
+SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0x0;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+bool config8888IsPremul(SkCanvas::Config8888 config8888) {
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ case SkCanvas::kBGRA_Premul_Config8888:
+ case SkCanvas::kRGBA_Premul_Config8888:
+ return true;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ return false;
+ default:
+ SkASSERT(0);
+ return false;
+ }
+}
+
+// assumes any premu/.unpremul has been applied
+uint32_t packConfig8888(SkCanvas::Config8888 config8888,
+ U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+ uint32_t r32;
+ uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ case SkCanvas::kNative_Unpremul_Config8888:
+ r32 = SkPackARGB32NoCheck(a, r, g, b);
+ break;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ result[0] = b;
+ result[1] = g;
+ result[2] = r;
+ result[3] = a;
+ break;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ result[0] = r;
+ result[1] = g;
+ result[2] = b;
+ result[3] = a;
+ break;
+ default:
+ SkASSERT(0);
+ return 0;
+ }
+ return r32;
+}
+
+uint32_t getBitmapColor(int x, int y, int w, int h, SkCanvas::Config8888 config8888) {
+ int n = y * w + x;
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ U8CPU a = 0;
+ switch ((x+y) % 5) {
+ case 4:
+ a = 0xff;
+ break;
+ case 3:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 1:
+ a = 0x01;
+ break;
+ case 0:
+ a = 0x00;
+ break;
+ }
+ if (config8888IsPremul(config8888)) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return packConfig8888(config8888, a, r, g , b);
+}
+
+void fillCanvas(SkCanvas* canvas) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
+ bool alloc = bmp.allocPixels();
+ SkASSERT(alloc);
+ SkAutoLockPixels alp(bmp);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
+ *pixel = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
+ uint32_t color,
+ bool* premul) {
+ const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
+ U8CPU a,r,g,b;
+ *premul = false;
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ return color;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ *premul = true;
+ a = SkGetPackedA32(color);
+ r = SkGetPackedR32(color);
+ g = SkGetPackedG32(color);
+ b = SkGetPackedB32(color);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kBGRA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[2]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[0]);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kRGBA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[2]);
+ break;
+ default:
+ GrCrash("Unexpected Config8888");
+ }
+ if (*premul) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
+bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+bool checkWrite(skiatest::Reporter* reporter,
+ SkCanvas* canvas,
+ const SkBitmap& bitmap,
+ int writeX, int writeY,
+ SkCanvas::Config8888 config8888) {
+ SkDevice* dev = canvas->getDevice();
+ if (!dev) {
+ return false;
+ }
+ SkBitmap devBmp = dev->accessBitmap(false);
+ if (devBmp.width() != DEV_W ||
+ devBmp.height() != DEV_H ||
+ devBmp.config() != SkBitmap::kARGB_8888_Config ||
+ devBmp.isNull()) {
+ return false;
+ }
+ SkAutoLockPixels alp(devBmp);
+
+ intptr_t canvasPixels = reinterpret_cast<intptr_t>(devBmp.getPixels());
+ size_t canvasRowBytes = devBmp.rowBytes();
+ SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
+ for (int cy = 0; cy < DEV_H; ++cy) {
+ const SkPMColor* canvasRow = reinterpret_cast<const SkPMColor*>(canvasPixels);
+ for (int cx = 0; cx < DEV_W; ++cx) {
+ SkPMColor canvasPixel = canvasRow[cx];
+ if (writeRect.contains(cx, cy)) {
+ int bx = cx - writeX;
+ int by = cy - writeY;
+ uint32_t bmpColor8888 = getBitmapColor(bx, by, bitmap.width(), bitmap.height(), config8888);
+ bool mul;
+ SkPMColor bmpPMColor = convertConfig8888ToPMColor(config8888, bmpColor8888, &mul);
+ bool check;
+ REPORTER_ASSERT(reporter, check = checkPixel(bmpPMColor, canvasPixel, mul));
+ if (!check) {
+ return false;
+ }
+ } else {
+ bool check;
+ SkPMColor testColor = getCanvasColor(cx, cy);
+ REPORTER_ASSERT(reporter, check = (canvasPixel == testColor));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ if (cy != DEV_H -1) {
+ const char* pad = reinterpret_cast<const char*>(canvasPixels + 4 * DEV_W);
+ for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
+ bool check;
+ REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ canvasPixels += canvasRowBytes;
+ }
+
+ return true;
+}
+
+enum DevType {
+ kRaster_DevType,
+ kGpu_DevType,
+};
+
+struct CanvasConfig {
+ DevType fDevType;
+ bool fTightRowBytes;
+};
+
+static const CanvasConfig gCanvasConfigs[] = {
+ {kRaster_DevType, true},
+ {kRaster_DevType, false},
+#ifdef SK_SCALAR_IS_FLOAT
+ {kGpu_DevType, true}, // row bytes has no meaning on gpu devices
+#endif
+};
+
+bool setupCanvas(SkCanvas* canvas, const CanvasConfig& c, GrContext* grCtx) {
+ switch (c.fDevType) {
+ case kRaster_DevType: {
+ SkBitmap bmp;
+ size_t rowBytes = c.fTightRowBytes ? 0 : 4 * DEV_W + 100;
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H, rowBytes);
+ if (!bmp.allocPixels()) {
+ return false;
+ }
+ // if rowBytes isn't tight then set the padding to a known value
+ if (rowBytes) {
+ SkAutoLockPixels alp(bmp);
+ memset(bmp.getPixels(), DEV_PAD, bmp.getSafeSize());
+ }
+ canvas->setDevice(new SkDevice(bmp))->unref();
+ } break;
+ case kGpu_DevType:
+ canvas->setDevice(new SkGpuDevice(grCtx,
+ SkBitmap::kARGB_8888_Config,
+ DEV_W, DEV_H))->unref();
+ break;
+ }
+ return true;
+}
+
+bool setupBitmap(SkBitmap* bitmap,
+ SkCanvas::Config8888 config8888,
+ int w, int h,
+ bool tightRowBytes) {
+ size_t rowBytes = tightRowBytes ? 0 : 4 * w + 60;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
+ if (!bitmap->allocPixels()) {
+ return false;
+ }
+ SkAutoLockPixels alp(*bitmap);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ uint32_t* pixel = reinterpret_cast<uint32_t*>(pixels + y * bitmap->rowBytes() + x * 4);
+ *pixel = getBitmapColor(x, y, w, h, config8888);
+ }
+ }
+ return true;
+}
+
+void WritePixelsTest(skiatest::Reporter* reporter, GrContext* context) {
+ SkCanvas canvas;
+
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gCanvasConfigs); ++i) {
+ REPORTER_ASSERT(reporter, setupCanvas(&canvas, gCanvasConfigs[i], context));
+
+ static const SkCanvas::Config8888 gReadConfigs[] = {
+ SkCanvas::kNative_Premul_Config8888,
+ SkCanvas::kNative_Unpremul_Config8888,
+ SkCanvas::kBGRA_Premul_Config8888,
+ SkCanvas::kBGRA_Unpremul_Config8888,
+ SkCanvas::kRGBA_Premul_Config8888,
+ SkCanvas::kRGBA_Unpremul_Config8888,
+ };
+ for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
+ const SkIRect& rect = testRects[r];
+ for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
+ fillCanvas(&canvas);
+ SkCanvas::Config8888 config8888 = gReadConfigs[c];
+ SkBitmap bmp;
+ REPORTER_ASSERT(reporter, setupBitmap(&bmp, config8888, rect.width(), rect.height(), SkToBool(tightBmp)));
+ canvas.writePixels(bmp, rect.fLeft, rect.fTop, config8888);
+ REPORTER_ASSERT(reporter, checkWrite(reporter, &canvas, bmp, rect.fLeft, rect.fTop, config8888));
+ }
+ }
+ }
+ }
+}
+}
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("WritePixels", WritePixelsTestClass, WritePixelsTest)
+
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
index 63b1209..a9a07ad 100644
--- a/tests/Writer32Test.cpp
+++ b/tests/Writer32Test.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * 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 "SkReader32.h"
#include "SkWriter32.h"
#include "Test.h"
diff --git a/tests/XfermodeTest.cpp b/tests/XfermodeTest.cpp
index b552ce0..966da51 100644
--- a/tests/XfermodeTest.cpp
+++ b/tests/XfermodeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkColor.h"
#include "SkXfermode.h"
@@ -39,5 +46,27 @@ static void test_asMode(skiatest::Reporter* reporter) {
bogusXfer->unref();
}
+static void test_IsMode(skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(NULL,
+ SkXfermode::kSrcOver_Mode));
+
+ for (int i = 0; i <= SkXfermode::kLastMode; ++i) {
+ SkXfermode::Mode mode = (SkXfermode::Mode)i;
+
+ SkXfermode* xfer = SkXfermode::Create(mode);
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(xfer, mode));
+ SkSafeUnref(xfer);
+
+ if (SkXfermode::kSrcOver_Mode != mode) {
+ REPORTER_ASSERT(reporter, !SkXfermode::IsMode(NULL, mode));
+ }
+ }
+}
+
+static void test_xfermodes(skiatest::Reporter* reporter) {
+ test_asMode(reporter);
+ test_IsMode(reporter);
+}
+
#include "TestClassDef.h"
-DEFINE_TESTCLASS("Xfermode", XfermodeTestClass, test_asMode)
+DEFINE_TESTCLASS("Xfermode", XfermodeTestClass, test_xfermodes)
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index f931d62..b740590 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * 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 "SkGraphics.h"
#include "Test.h"
@@ -97,11 +104,40 @@ private:
int main (int argc, char * const argv[]) {
SkAutoGraphics ag;
-
+
bool androidMode = false;
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-android")) {
+ const char* matchStr = NULL;
+
+ char* const* stop = argv + argc;
+ for (++argv; argv < stop; ++argv) {
+ if (strcmp(*argv, "-android") == 0) {
androidMode = true;
+
+ } else if (strcmp(*argv, "--match") == 0) {
+ ++argv;
+ if (argv < stop && **argv) {
+ matchStr = *argv;
+ }
+ }
+ }
+
+ {
+ SkString header("Skia UnitTests:");
+ if (matchStr) {
+ header.appendf(" --match %s", matchStr);
+ }
+#ifdef SK_DEBUG
+ header.append(" SK_DEBUG");
+#else
+ header.append(" SK_RELEASE");
+#endif
+#ifdef SK_SCALAR_IS_FIXED
+ header.append(" SK_SCALAR_IS_FIXED");
+#else
+ header.append(" SK_SCALAR_IS_FLOAT");
+#endif
+ if (!androidMode) {
+ SkDebugf("%s\n", header.c_str());
}
}
@@ -111,17 +147,24 @@ int main (int argc, char * const argv[]) {
const int count = Iter::Count();
int index = 0;
- int successCount = 0;
+ int failCount = 0;
+ int skipCount = 0;
while ((test = iter.next()) != NULL) {
reporter.setIndexOfTotal(index, count);
- successCount += test->run();
+ if (NULL != matchStr && !strstr(test->getName(), matchStr)) {
+ ++skipCount;
+ } else {
+ if (!test->run()) {
+ ++failCount;
+ }
+ }
SkDELETE(test);
index += 1;
}
if (!androidMode) {
- SkDebugf("Finished %d tests, %d failures.\n", count,
- count - successCount);
+ SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
+ count, failCount, skipCount);
}
- return (count == successCount) ? 0 : 1;
+ return (failCount == 0) ? 0 : 1;
}
diff --git a/tests/tests_files.mk b/tests/tests_files.mk
deleted file mode 100644
index 667c9b5..0000000
--- a/tests/tests_files.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-SOURCE := \
- BitmapCopyTest.cpp \
- BitmapGetColorTest.cpp \
- BlitRowTest.cpp \
- ClampRangeTest.cpp \
- ClipCubicTest.cpp \
- ClipStackTest.cpp \
- ClipperTest.cpp \
- ColorFilterTest.cpp \
- ColorTest.cpp \
- DequeTest.cpp \
- DrawBitmapRectTest.cpp \
- FillPathTest.cpp \
- FlateTest.cpp \
- GeometryTest.cpp \
- InfRectTest.cpp \
- MathTest.cpp \
- MatrixTest.cpp \
- MetaDataTest.cpp \
- PackBitsTest.cpp \
- PaintTest.cpp \
- ParsePathTest.cpp \
- PathCoverageTest.cpp \
- PathMeasureTest.cpp \
- PathTest.cpp \
- Reader32Test.cpp \
- RefDictTest.cpp \
- RegionTest.cpp \
- Sk64Test.cpp \
- skia_test.cpp \
- SortTest.cpp \
- SrcOverTest.cpp \
- StreamTest.cpp \
- StringTest.cpp \
- Test.cpp \
- TestSize.cpp \
- UtilsTest.cpp \
- Writer32Test.cpp \
- XfermodeTest.cpp