blob: 0b2fd06fbf771548c31fb0ab7e2927c6ce130aa0 [file] [log] [blame]
caryclark@google.comcd4421d2012-03-01 19:16:31 +00001#include "EdgeWalker_Test.h"
2#include "Intersection_Tests.h"
3#include "SkBitmap.h"
4#include "SkCanvas.h"
5#include "SkPaint.h"
6
caryclark@google.com2e7f4c82012-03-20 21:11:59 +00007static bool gShowPath = false;
caryclark@google.com198e0542012-03-30 18:47:02 +00008static bool gComparePaths = true;
caryclark@google.com752b60e2012-03-22 21:11:17 +00009static bool gDrawLastAsciiPaths = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000010static bool gDrawAllAsciiPaths = false;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000011static bool gShowAsciiPaths = false;
caryclark@google.com752b60e2012-03-22 21:11:17 +000012static bool gComparePathsAssert = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000013
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000014void showPath(const SkPath& path, const char* str) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000015 SkDebugf("%s\n", !str ? "original:" : str);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000016 SkPath::Iter iter(path, true);
17 uint8_t verb;
18 SkPoint pts[4];
19 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
20 switch (verb) {
21 case SkPath::kMove_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000022 SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000023 continue;
24 case SkPath::kLine_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000025 SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000026 break;
27 case SkPath::kQuad_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000028 SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000029 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
30 break;
31 case SkPath::kCubic_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000032 SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000033 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
34 pts[3].fX, pts[3].fY);
35 break;
36 case SkPath::kClose_Verb:
37 SkDebugf("path.close();\n");
38 continue;
39 default:
40 SkDEBUGFAIL("bad verb");
41 return;
42 }
43 }
44}
45
caryclark@google.com198e0542012-03-30 18:47:02 +000046static int pathsDrawTheSame(const SkPath& one, const SkPath& two,
47 SkBitmap& bits, SkCanvas* c) {
48 SkCanvas* canvasPtr = c;
49 if (!c) {
50 canvasPtr = new SkCanvas(bits);
51 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +000052 const SkRect& bounds1 = one.getBounds();
53 const SkRect& bounds2 = two.getBounds();
54 SkRect larger = bounds1;
55 larger.join(bounds2);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000056 int bitWidth = SkScalarCeil(larger.width()) + 2;
57 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com198e0542012-03-30 18:47:02 +000058 if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) {
59 if (bits.width() >= 200) {
60 SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight);
61 }
62 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
63 bits.allocPixels();
64 canvasPtr->setBitmapDevice(bits);
65 }
66 SkCanvas& canvas = *canvasPtr;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000067 canvas.drawColor(SK_ColorWHITE);
68 SkPaint paint;
69 canvas.save();
70 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
71 canvas.drawPath(one, paint);
72 canvas.restore();
73 canvas.save();
74 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
75 canvas.drawPath(two, paint);
76 canvas.restore();
caryclark@google.com198e0542012-03-30 18:47:02 +000077 int errors = 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000078 for (int y = 0; y < bitHeight; ++y) {
79 uint32_t* addr1 = bits.getAddr32(0, y);
80 uint32_t* addr2 = bits.getAddr32(bitWidth, y);
81 for (int x = 0; x < bitWidth; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +000082 errors += addr1[x] != addr2[x];
caryclark@google.comcd4421d2012-03-01 19:16:31 +000083 }
84 }
caryclark@google.com198e0542012-03-30 18:47:02 +000085 if (!c) {
86 delete canvasPtr;
87 }
88 return errors;
89}
90
91void bitmapInit(SkBitmap& bits) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +000092}
93
caryclark@google.com752b60e2012-03-22 21:11:17 +000094bool drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +000095 bool drawPaths) {
96 if (!drawPaths) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000097 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000098 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000099 if (gShowAsciiPaths) {
100 showPath(one, "one:");
101 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000102 }
103 const SkRect& bounds1 = one.getBounds();
104 const SkRect& bounds2 = two.getBounds();
105 SkRect larger = bounds1;
106 larger.join(bounds2);
107 SkBitmap bits;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000108 char out[256];
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000109 int bitWidth = SkScalarCeil(larger.width()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000110 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
111 return false;
112 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000113 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000114 if (bitHeight >= (int) sizeof(out)) {
115 return false;
116 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000117 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
118 bits.allocPixels();
119 SkCanvas canvas(bits);
120 canvas.drawColor(SK_ColorWHITE);
121 SkPaint paint;
122 canvas.save();
123 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
124 canvas.drawPath(one, paint);
125 canvas.restore();
126 canvas.save();
127 canvas.translate(-bounds2.fLeft + 1 + bitWidth, -bounds2.fTop + 1);
128 canvas.drawPath(two, paint);
129 canvas.restore();
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000130 for (int y = 0; y < bitHeight; ++y) {
131 uint32_t* addr1 = bits.getAddr32(0, y);
132 int x;
133 char* outPtr = out;
134 for (x = 0; x < bitWidth; ++x) {
135 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
136 }
137 *outPtr++ = '|';
138 for (x = bitWidth; x < bitWidth * 2; ++x) {
139 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
140 }
141 *outPtr++ = '\0';
142 SkDebugf("%s\n", out);
143 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000144 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000145}
146
caryclark@google.com198e0542012-03-30 18:47:02 +0000147static int scaledDrawTheSame(const SkPath& one, const SkPath& two,
148 int a, int b, bool drawPaths, SkBitmap& bitmap, SkCanvas* canvas) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000149 SkMatrix scale;
150 scale.reset();
caryclark@google.com752b60e2012-03-22 21:11:17 +0000151 float aScale = 1.21f;
152 float bScale = 1.11f;
153 scale.preScale(a * aScale, b * bScale);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000154 SkPath scaledOne, scaledTwo;
155 one.transform(scale, &scaledOne);
156 two.transform(scale, &scaledTwo);
caryclark@google.com198e0542012-03-30 18:47:02 +0000157 int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas);
158 if (errors == 0) {
159 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000160 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000161 while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
162 scale.reset();
163 aScale *= 0.5f;
164 bScale *= 0.5f;
165 scale.preScale(a * aScale, b * bScale);
166 one.transform(scale, &scaledOne);
167 two.transform(scale, &scaledTwo);
168 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000169 return errors;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000170}
171
caryclark@google.com198e0542012-03-30 18:47:02 +0000172static int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
173 SkCanvas* canvas) {
174 int errors = pathsDrawTheSame(one, two, bitmap, canvas);
175 if (errors == 0) {
176 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000177 }
178 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
179 for (int x = 9; x <= 33; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000180 errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths,
181 bitmap, canvas);
182 if (errors == 0) {
183 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000184 }
185 }
186 if (!gDrawAllAsciiPaths) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000187 errors = scaledDrawTheSame(one, two, 9, 7, false, bitmap, canvas);
188 if (errors > 4) {
189 scaledDrawTheSame(one, two, 9, 7, true, bitmap, canvas);
190 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000191 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000192 if (errors > 0) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
193 if (errors > 4 && gComparePathsAssert) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000194 showPath(one);
195 showPath(two, "simplified:");
196 SkASSERT(0);
197 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000198 return errors;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000199}
200
201// doesn't work yet
202void comparePathsTiny(const SkPath& one, const SkPath& two) {
203 const SkRect& bounds1 = one.getBounds();
204 const SkRect& bounds2 = two.getBounds();
205 SkRect larger = bounds1;
206 larger.join(bounds2);
207 SkBitmap bits;
208 int bitWidth = SkScalarCeil(larger.width()) + 2;
209 int bitHeight = SkScalarCeil(larger.height()) + 2;
210 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
211 bits.allocPixels();
212 SkCanvas canvas(bits);
213 canvas.drawColor(SK_ColorWHITE);
214 SkPaint paint;
215 canvas.save();
216 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
217 canvas.drawPath(one, paint);
218 canvas.restore();
219 canvas.save();
220 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
221 canvas.drawPath(two, paint);
222 canvas.restore();
223 for (int y = 0; y < bitHeight; ++y) {
224 uint8_t* addr1 = bits.getAddr1(0, y);
225 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
226 for (int x = 0; x < bits.rowBytes(); ++x) {
227 SkASSERT(addr1[x] == addr2[x]);
228 }
229 }
230}
231
caryclark@google.com198e0542012-03-30 18:47:02 +0000232bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap,
233 SkCanvas* canvas) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000234 if (gShowPath) {
235 showPath(path);
236 }
237 simplify(path, fill, out);
caryclark@google.com752b60e2012-03-22 21:11:17 +0000238 if (!gComparePaths) {
239 return true;
240 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000241 return comparePaths(path, out, bitmap, canvas) == 0;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000242}