blob: d0b82c16952e4c3270e51d4b358da5540a1f0a11 [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"
caryclark@google.comfb173422012-04-10 18:28:55 +00006#include <algorithm>
caryclark@google.comcd4421d2012-03-01 19:16:31 +00007
caryclark@google.com78e17132012-04-17 11:40:34 +00008#undef SkASSERT
9#define SkASSERT(cond) while (!(cond)) { sk_throw(); }
10
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000011static bool gShowPath = false;
caryclark@google.com198e0542012-03-30 18:47:02 +000012static bool gComparePaths = true;
caryclark@google.com752b60e2012-03-22 21:11:17 +000013static bool gDrawLastAsciiPaths = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000014static bool gDrawAllAsciiPaths = false;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000015static bool gShowAsciiPaths = false;
caryclark@google.com752b60e2012-03-22 21:11:17 +000016static bool gComparePathsAssert = true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000017
caryclark@google.com2e7f4c82012-03-20 21:11:59 +000018void showPath(const SkPath& path, const char* str) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000019 SkDebugf("%s\n", !str ? "original:" : str);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000020 SkPath::Iter iter(path, true);
21 uint8_t verb;
22 SkPoint pts[4];
23 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
24 switch (verb) {
25 case SkPath::kMove_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000026 SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000027 continue;
28 case SkPath::kLine_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000029 SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000030 break;
31 case SkPath::kQuad_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000032 SkDebugf("path.quadTo(%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 break;
35 case SkPath::kCubic_Verb:
caryclark@google.comd88e0892012-03-27 13:23:51 +000036 SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
caryclark@google.comcd4421d2012-03-01 19:16:31 +000037 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
38 pts[3].fX, pts[3].fY);
39 break;
40 case SkPath::kClose_Verb:
41 SkDebugf("path.close();\n");
42 continue;
43 default:
44 SkDEBUGFAIL("bad verb");
45 return;
46 }
47 }
48}
49
caryclark@google.com198e0542012-03-30 18:47:02 +000050static int pathsDrawTheSame(const SkPath& one, const SkPath& two,
51 SkBitmap& bits, SkCanvas* c) {
52 SkCanvas* canvasPtr = c;
53 if (!c) {
54 canvasPtr = new SkCanvas(bits);
55 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +000056 const SkRect& bounds1 = one.getBounds();
57 const SkRect& bounds2 = two.getBounds();
58 SkRect larger = bounds1;
59 larger.join(bounds2);
caryclark@google.comcd4421d2012-03-01 19:16:31 +000060 int bitWidth = SkScalarCeil(larger.width()) + 2;
61 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com198e0542012-03-30 18:47:02 +000062 if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) {
63 if (bits.width() >= 200) {
64 SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight);
65 }
66 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
67 bits.allocPixels();
68 canvasPtr->setBitmapDevice(bits);
69 }
70 SkCanvas& canvas = *canvasPtr;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000071 canvas.drawColor(SK_ColorWHITE);
72 SkPaint paint;
73 canvas.save();
74 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
75 canvas.drawPath(one, paint);
76 canvas.restore();
77 canvas.save();
78 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
79 canvas.drawPath(two, paint);
80 canvas.restore();
caryclark@google.com198e0542012-03-30 18:47:02 +000081 int errors = 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000082 for (int y = 0; y < bitHeight; ++y) {
83 uint32_t* addr1 = bits.getAddr32(0, y);
84 uint32_t* addr2 = bits.getAddr32(bitWidth, y);
85 for (int x = 0; x < bitWidth; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +000086 errors += addr1[x] != addr2[x];
caryclark@google.comcd4421d2012-03-01 19:16:31 +000087 }
88 }
caryclark@google.com198e0542012-03-30 18:47:02 +000089 if (!c) {
90 delete canvasPtr;
91 }
92 return errors;
93}
94
95void bitmapInit(SkBitmap& bits) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +000096}
97
caryclark@google.com752b60e2012-03-22 21:11:17 +000098bool drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +000099 bool drawPaths) {
100 if (!drawPaths) {
caryclark@google.com752b60e2012-03-22 21:11:17 +0000101 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000102 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000103 if (gShowAsciiPaths) {
104 showPath(one, "one:");
105 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000106 }
107 const SkRect& bounds1 = one.getBounds();
108 const SkRect& bounds2 = two.getBounds();
109 SkRect larger = bounds1;
110 larger.join(bounds2);
111 SkBitmap bits;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000112 char out[256];
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000113 int bitWidth = SkScalarCeil(larger.width()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000114 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
115 return false;
116 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000117 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000118 if (bitHeight >= (int) sizeof(out)) {
119 return false;
120 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000121 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
122 bits.allocPixels();
123 SkCanvas canvas(bits);
124 canvas.drawColor(SK_ColorWHITE);
125 SkPaint paint;
126 canvas.save();
127 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
128 canvas.drawPath(one, paint);
129 canvas.restore();
130 canvas.save();
caryclark@google.comfb173422012-04-10 18:28:55 +0000131 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000132 canvas.drawPath(two, paint);
133 canvas.restore();
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000134 for (int y = 0; y < bitHeight; ++y) {
135 uint32_t* addr1 = bits.getAddr32(0, y);
136 int x;
137 char* outPtr = out;
138 for (x = 0; x < bitWidth; ++x) {
139 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
140 }
141 *outPtr++ = '|';
142 for (x = bitWidth; x < bitWidth * 2; ++x) {
143 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
144 }
145 *outPtr++ = '\0';
146 SkDebugf("%s\n", out);
147 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000148 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000149}
150
caryclark@google.com198e0542012-03-30 18:47:02 +0000151static int scaledDrawTheSame(const SkPath& one, const SkPath& two,
152 int a, int b, bool drawPaths, SkBitmap& bitmap, SkCanvas* canvas) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000153 SkMatrix scale;
154 scale.reset();
caryclark@google.com752b60e2012-03-22 21:11:17 +0000155 float aScale = 1.21f;
156 float bScale = 1.11f;
157 scale.preScale(a * aScale, b * bScale);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000158 SkPath scaledOne, scaledTwo;
159 one.transform(scale, &scaledOne);
160 two.transform(scale, &scaledTwo);
caryclark@google.com198e0542012-03-30 18:47:02 +0000161 int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas);
162 if (errors == 0) {
163 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000164 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000165 while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
166 scale.reset();
167 aScale *= 0.5f;
168 bScale *= 0.5f;
169 scale.preScale(a * aScale, b * bScale);
170 one.transform(scale, &scaledOne);
171 two.transform(scale, &scaledTwo);
172 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000173 return errors;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000174}
175
caryclark@google.com78e17132012-04-17 11:40:34 +0000176static int max = 0;
177
caryclark@google.com198e0542012-03-30 18:47:02 +0000178static int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
179 SkCanvas* canvas) {
180 int errors = pathsDrawTheSame(one, two, bitmap, canvas);
181 if (errors == 0) {
182 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000183 }
184 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
185 for (int x = 9; x <= 33; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000186 errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths,
187 bitmap, canvas);
188 if (errors == 0) {
189 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000190 }
191 }
192 if (!gDrawAllAsciiPaths) {
caryclark@google.comfb173422012-04-10 18:28:55 +0000193 const SkRect& bounds1 = one.getBounds();
194 const SkRect& bounds2 = two.getBounds();
195 SkRect larger = bounds1;
196 larger.join(bounds2);
197 SkScalar xScale = std::max(80.0f / larger.width(), 1.0f);
198 SkScalar yScale = std::max(60.0f / larger.height(), 1.0f);
199 errors = scaledDrawTheSame(one, two, xScale, yScale, false, bitmap, canvas);
caryclark@google.com78e17132012-04-17 11:40:34 +0000200 if (errors > 50) {
caryclark@google.comfb173422012-04-10 18:28:55 +0000201 scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas);
caryclark@google.com198e0542012-03-30 18:47:02 +0000202 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000203 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000204 if (errors > max) {
205 SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
206 max = errors;
207 }
208 const int MAX_ERRORS = 100;
209 if (errors > MAX_ERRORS) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
210 if (errors > MAX_ERRORS && gComparePathsAssert) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000211 showPath(one);
212 showPath(two, "simplified:");
213 SkASSERT(0);
214 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000215 return errors > MAX_ERRORS ? errors : 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000216}
217
218// doesn't work yet
219void comparePathsTiny(const SkPath& one, const SkPath& two) {
220 const SkRect& bounds1 = one.getBounds();
221 const SkRect& bounds2 = two.getBounds();
222 SkRect larger = bounds1;
223 larger.join(bounds2);
224 SkBitmap bits;
225 int bitWidth = SkScalarCeil(larger.width()) + 2;
226 int bitHeight = SkScalarCeil(larger.height()) + 2;
227 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
228 bits.allocPixels();
229 SkCanvas canvas(bits);
230 canvas.drawColor(SK_ColorWHITE);
231 SkPaint paint;
232 canvas.save();
233 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
234 canvas.drawPath(one, paint);
235 canvas.restore();
236 canvas.save();
237 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
238 canvas.drawPath(two, paint);
239 canvas.restore();
240 for (int y = 0; y < bitHeight; ++y) {
241 uint8_t* addr1 = bits.getAddr1(0, y);
242 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
243 for (int x = 0; x < bits.rowBytes(); ++x) {
244 SkASSERT(addr1[x] == addr2[x]);
245 }
246 }
247}
248
caryclark@google.com198e0542012-03-30 18:47:02 +0000249bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap,
250 SkCanvas* canvas) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000251 if (gShowPath) {
252 showPath(path);
253 }
254 simplify(path, fill, out);
caryclark@google.com752b60e2012-03-22 21:11:17 +0000255 if (!gComparePaths) {
256 return true;
257 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000258 return comparePaths(path, out, bitmap, canvas) == 0;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000259}
caryclark@google.com78e17132012-04-17 11:40:34 +0000260
261State4::State4() {
262 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100);
263 bitmap.allocPixels();
264 canvas = new SkCanvas(bitmap);
265}
266
267void createThread(State4* statePtr, void* (*test)(void* )) {
268 int threadError = pthread_create(&statePtr->threadID, NULL, test,
269 (void*) statePtr);
270 SkASSERT(!threadError);
271}
272
273void waitForCompletion(State4 threadState[], int& threadIndex) {
274 for (int index = 0; index < threadIndex; ++index) {
275 pthread_join(threadState[index].threadID, NULL);
276 }
277 SkDebugf(".");
278 threadIndex = 0;
279}