blob: 2a29648a251fd8d676516199114f8565c547359a [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.coma3f05fa2012-06-01 17:44:28 +000013//static 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
caryclark@google.com752b60e2012-03-22 21:11:17 +000095bool drawAsciiPaths(const SkPath& one, const SkPath& two,
caryclark@google.comcd4421d2012-03-01 19:16:31 +000096 bool drawPaths) {
97 if (!drawPaths) {
caryclark@google.com752b60e2012-03-22 21:11:17 +000098 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +000099 }
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000100 if (gShowAsciiPaths) {
101 showPath(one, "one:");
102 showPath(two, "two:");
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000103 }
104 const SkRect& bounds1 = one.getBounds();
105 const SkRect& bounds2 = two.getBounds();
106 SkRect larger = bounds1;
107 larger.join(bounds2);
108 SkBitmap bits;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000109 char out[256];
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000110 int bitWidth = SkScalarCeil(larger.width()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000111 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
112 return false;
113 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000114 int bitHeight = SkScalarCeil(larger.height()) + 2;
caryclark@google.com752b60e2012-03-22 21:11:17 +0000115 if (bitHeight >= (int) sizeof(out)) {
116 return false;
117 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000118 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
119 bits.allocPixels();
120 SkCanvas canvas(bits);
121 canvas.drawColor(SK_ColorWHITE);
122 SkPaint paint;
123 canvas.save();
124 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
125 canvas.drawPath(one, paint);
126 canvas.restore();
127 canvas.save();
caryclark@google.comfb173422012-04-10 18:28:55 +0000128 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000129 canvas.drawPath(two, paint);
130 canvas.restore();
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000131 for (int y = 0; y < bitHeight; ++y) {
132 uint32_t* addr1 = bits.getAddr32(0, y);
133 int x;
134 char* outPtr = out;
135 for (x = 0; x < bitWidth; ++x) {
136 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
137 }
138 *outPtr++ = '|';
139 for (x = bitWidth; x < bitWidth * 2; ++x) {
140 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
141 }
142 *outPtr++ = '\0';
143 SkDebugf("%s\n", out);
144 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000145 return true;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000146}
147
caryclark@google.com198e0542012-03-30 18:47:02 +0000148static int scaledDrawTheSame(const SkPath& one, const SkPath& two,
caryclark@google.coma3f05fa2012-06-01 17:44:28 +0000149 SkScalar a, SkScalar b, bool drawPaths, SkBitmap& bitmap,
150 SkCanvas* canvas) {
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000151 SkMatrix scale;
152 scale.reset();
caryclark@google.com752b60e2012-03-22 21:11:17 +0000153 float aScale = 1.21f;
154 float bScale = 1.11f;
155 scale.preScale(a * aScale, b * bScale);
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000156 SkPath scaledOne, scaledTwo;
157 one.transform(scale, &scaledOne);
158 two.transform(scale, &scaledTwo);
caryclark@google.com198e0542012-03-30 18:47:02 +0000159 int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas);
160 if (errors == 0) {
161 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000162 }
caryclark@google.com752b60e2012-03-22 21:11:17 +0000163 while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
164 scale.reset();
165 aScale *= 0.5f;
166 bScale *= 0.5f;
167 scale.preScale(a * aScale, b * bScale);
168 one.transform(scale, &scaledOne);
169 two.transform(scale, &scaledTwo);
170 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000171 return errors;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000172}
173
caryclark@google.com78e17132012-04-17 11:40:34 +0000174static int max = 0;
175
caryclark@google.com1577e8f2012-05-22 17:01:14 +0000176int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap,
caryclark@google.com198e0542012-03-30 18:47:02 +0000177 SkCanvas* canvas) {
178 int errors = pathsDrawTheSame(one, two, bitmap, canvas);
179 if (errors == 0) {
180 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000181 }
182 drawAsciiPaths(one, two, gDrawAllAsciiPaths);
183 for (int x = 9; x <= 33; ++x) {
caryclark@google.com198e0542012-03-30 18:47:02 +0000184 errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths,
185 bitmap, canvas);
186 if (errors == 0) {
187 return 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000188 }
189 }
190 if (!gDrawAllAsciiPaths) {
caryclark@google.comfb173422012-04-10 18:28:55 +0000191 const SkRect& bounds1 = one.getBounds();
192 const SkRect& bounds2 = two.getBounds();
193 SkRect larger = bounds1;
194 larger.join(bounds2);
195 SkScalar xScale = std::max(80.0f / larger.width(), 1.0f);
196 SkScalar yScale = std::max(60.0f / larger.height(), 1.0f);
197 errors = scaledDrawTheSame(one, two, xScale, yScale, false, bitmap, canvas);
caryclark@google.com78e17132012-04-17 11:40:34 +0000198 if (errors > 50) {
caryclark@google.comfb173422012-04-10 18:28:55 +0000199 scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas);
caryclark@google.com198e0542012-03-30 18:47:02 +0000200 }
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000201 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000202 if (errors > max) {
203 SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
204 max = errors;
205 }
206 const int MAX_ERRORS = 100;
207 if (errors > MAX_ERRORS) SkDebugf("\n%s errors=%d\n", __FUNCTION__, errors);
208 if (errors > MAX_ERRORS && gComparePathsAssert) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000209 showPath(one);
210 showPath(two, "simplified:");
211 SkASSERT(0);
212 }
caryclark@google.com78e17132012-04-17 11:40:34 +0000213 return errors > MAX_ERRORS ? errors : 0;
caryclark@google.comcd4421d2012-03-01 19:16:31 +0000214}
215
216// doesn't work yet
217void comparePathsTiny(const SkPath& one, const SkPath& two) {
218 const SkRect& bounds1 = one.getBounds();
219 const SkRect& bounds2 = two.getBounds();
220 SkRect larger = bounds1;
221 larger.join(bounds2);
222 SkBitmap bits;
223 int bitWidth = SkScalarCeil(larger.width()) + 2;
224 int bitHeight = SkScalarCeil(larger.height()) + 2;
225 bits.setConfig(SkBitmap::kA1_Config, bitWidth * 2, bitHeight);
226 bits.allocPixels();
227 SkCanvas canvas(bits);
228 canvas.drawColor(SK_ColorWHITE);
229 SkPaint paint;
230 canvas.save();
231 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
232 canvas.drawPath(one, paint);
233 canvas.restore();
234 canvas.save();
235 canvas.translate(-bounds2.fLeft + 1, -bounds2.fTop + 1);
236 canvas.drawPath(two, paint);
237 canvas.restore();
238 for (int y = 0; y < bitHeight; ++y) {
239 uint8_t* addr1 = bits.getAddr1(0, y);
240 uint8_t* addr2 = bits.getAddr1(bitWidth, y);
241 for (int x = 0; x < bits.rowBytes(); ++x) {
242 SkASSERT(addr1[x] == addr2[x]);
243 }
244 }
245}
246
caryclark@google.com198e0542012-03-30 18:47:02 +0000247bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap,
248 SkCanvas* canvas) {
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000249 if (gShowPath) {
250 showPath(path);
251 }
252 simplify(path, fill, out);
caryclark@google.com752b60e2012-03-22 21:11:17 +0000253 if (!gComparePaths) {
254 return true;
255 }
caryclark@google.com198e0542012-03-30 18:47:02 +0000256 return comparePaths(path, out, bitmap, canvas) == 0;
caryclark@google.com2e7f4c82012-03-20 21:11:59 +0000257}
caryclark@google.com78e17132012-04-17 11:40:34 +0000258
259State4::State4() {
260 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100);
261 bitmap.allocPixels();
262 canvas = new SkCanvas(bitmap);
263}
264
265void createThread(State4* statePtr, void* (*test)(void* )) {
266 int threadError = pthread_create(&statePtr->threadID, NULL, test,
267 (void*) statePtr);
268 SkASSERT(!threadError);
269}
270
271void waitForCompletion(State4 threadState[], int& threadIndex) {
272 for (int index = 0; index < threadIndex; ++index) {
273 pthread_join(threadState[index].threadID, NULL);
274 }
275 SkDebugf(".");
276 threadIndex = 0;
277}