blob: 7a7dcb375914c64e8cdf637f34c17dc98a6ec159 [file] [log] [blame]
caryclark@google.com818b0cc2013-04-08 11:50:46 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "PathOpsExtendedTest.h"
caryclark@google.com66089e42013-04-10 15:55:37 +00009#include "PathOpsThreadedCommon.h"
caryclark@google.com818b0cc2013-04-08 11:50:46 +000010#include "SkBitmap.h"
11#include "SkCanvas.h"
12#include "SkMatrix.h"
13#include "SkPaint.h"
14#include "SkStream.h"
caryclark@google.coma5e55922013-05-07 18:51:31 +000015#include "SkThreadPool.h"
caryclark@google.com818b0cc2013-04-08 11:50:46 +000016
17#ifdef SK_BUILD_FOR_MAC
18#include <sys/sysctl.h>
19#endif
20
caryclark@google.com818b0cc2013-04-08 11:50:46 +000021static const char marker[] =
22 "</div>\n"
23 "\n"
24 "<script type=\"text/javascript\">\n"
25 "\n"
26 "var testDivs = [\n";
27
28static const char* opStrs[] = {
29 "kDifference_PathOp",
30 "kIntersect_PathOp",
31 "kUnion_PathOp",
32 "kXor_PathOp",
caryclark@google.com6dc7df62013-04-25 11:51:54 +000033 "kReverseDifference_PathOp",
caryclark@google.com818b0cc2013-04-08 11:50:46 +000034};
35
36static const char* opSuffixes[] = {
37 "d",
38 "i",
39 "u",
caryclark@google.com66089e42013-04-10 15:55:37 +000040 "o",
caryclark@google.com818b0cc2013-04-08 11:50:46 +000041};
42
43static bool gShowPath = false;
44static bool gComparePaths = true;
caryclark@google.com818b0cc2013-04-08 11:50:46 +000045static bool gComparePathsAssert = true;
46static bool gPathStrAssert = true;
caryclark@google.com818b0cc2013-04-08 11:50:46 +000047
caryclark@google.com07e97fc2013-07-08 17:17:02 +000048static const char* gFillTypeStr[] = {
49 "kWinding_FillType",
50 "kEvenOdd_FillType",
51 "kInverseWinding_FillType",
52 "kInverseEvenOdd_FillType"
53};
54
55static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
caryclark@google.com818b0cc2013-04-08 11:50:46 +000056 uint8_t verb;
57 SkPoint pts[4];
58 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
59 switch (verb) {
60 case SkPath::kMove_Verb:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000061 SkDebugf(" %s.moveTo(%#1.9gf, %#1.9gf);\n", pathName, pts[0].fX, pts[0].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000062 continue;
63 case SkPath::kLine_Verb:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000064 SkDebugf(" %s.lineTo(%#1.9gf, %#1.9gf);\n", pathName, pts[1].fX, pts[1].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000065 break;
66 case SkPath::kQuad_Verb:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000067 SkDebugf(" %s.quadTo(%#1.9gf, %#1.9gf, %#1.9gf, %#1.9gf);\n", pathName,
caryclark@google.com818b0cc2013-04-08 11:50:46 +000068 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
69 break;
70 case SkPath::kCubic_Verb:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000071 SkDebugf(" %s.cubicTo(%#1.9gf, %#1.9gf, %#1.9gf, %#1.9gf, %#1.9gf, %#1.9gf);\n",
72 pathName, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000073 break;
74 case SkPath::kClose_Verb:
caryclark@google.com07e97fc2013-07-08 17:17:02 +000075 SkDebugf(" %s.close();\n", pathName);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000076 break;
77 default:
78 SkDEBUGFAIL("bad verb");
79 return;
80 }
81 }
82}
83
caryclark@google.com07e97fc2013-07-08 17:17:02 +000084static void showPath(const SkPath& path, const char* pathName, bool includeDeclaration) {
85 SkPath::RawIter iter(path);
caryclark@google.com818b0cc2013-04-08 11:50:46 +000086#define SUPPORT_RECT_CONTOUR_DETECTION 0
87#if SUPPORT_RECT_CONTOUR_DETECTION
88 int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
89 if (rectCount > 0) {
90 SkTDArray<SkRect> rects;
91 SkTDArray<SkPath::Direction> directions;
92 rects.setCount(rectCount);
93 directions.setCount(rectCount);
94 path.rectContours(rects.begin(), directions.begin());
95 for (int contour = 0; contour < rectCount; ++contour) {
96 const SkRect& rect = rects[contour];
97 SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
98 rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
99 ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
100 }
101 return;
102 }
103#endif
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000104 SkPath::FillType fillType = path.getFillType();
105 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000106 if (includeDeclaration) {
107 SkDebugf(" SkPath %s;\n", pathName);
108 }
109 SkDebugf(" %s.setFillType(SkPath::%s);\n", pathName, gFillTypeStr[fillType]);
110 iter.setPath(path);
111 showPathContours(iter, pathName);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000112}
113
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000114#if DEBUG_SHOW_TEST_NAME
115static void showPathData(const SkPath& path) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000116 SkPath::RawIter iter(path);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000117 uint8_t verb;
118 SkPoint pts[4];
119 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
120 switch (verb) {
121 case SkPath::kMove_Verb:
122 continue;
123 case SkPath::kLine_Verb:
caryclark@google.com66089e42013-04-10 15:55:37 +0000124 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0].fY,
125 pts[1].fX, pts[1].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000126 break;
127 case SkPath::kQuad_Verb:
128 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
caryclark@google.com66089e42013-04-10 15:55:37 +0000129 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000130 break;
131 case SkPath::kCubic_Verb:
132 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
caryclark@google.com66089e42013-04-10 15:55:37 +0000133 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
134 pts[3].fX, pts[3].fY);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000135 break;
136 case SkPath::kClose_Verb:
137 break;
138 default:
139 SkDEBUGFAIL("bad verb");
140 return;
141 }
142 }
143}
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000144#endif
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000145
146void showOp(const SkPathOp op) {
147 switch (op) {
148 case kDifference_PathOp:
149 SkDebugf("op difference\n");
150 break;
151 case kIntersect_PathOp:
152 SkDebugf("op intersect\n");
153 break;
154 case kUnion_PathOp:
155 SkDebugf("op union\n");
156 break;
157 case kXOR_PathOp:
158 SkDebugf("op xor\n");
159 break;
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000160 case kReverseDifference_PathOp:
161 SkDebugf("op reverse difference\n");
162 break;
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000163 default:
164 SkASSERT(0);
165 }
166}
167
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000168#if DEBUG_SHOW_TEST_NAME
169
170void ShowFunctionHeader(const char* functionName) {
171 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter) {\n", functionName);
172 if (strcmp("skphealth_com76", functionName) == 0) {
173 SkDebugf("found it\n");
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000174 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000175}
176
177static const char* gOpStrs[] = {
178 "kDifference_PathOp",
179 "kIntersect_PathOp",
180 "kUnion_PathOp",
181 "kXor_PathOp",
182 "kReverseDifference_PathOp",
183};
184
185void ShowOp(SkPathOp op, const char* pathOne, const char* pathTwo) {
186 SkDebugf(" testPathOp(reporter, %s, %s, %s);\n", pathOne, pathTwo, gOpStrs[op]);
187 SkDebugf("}\n");
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000188}
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000189#endif
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000190
caryclark@google.com03610322013-04-18 15:58:21 +0000191#if DEBUG_SHOW_TEST_NAME
192static char hexorator(int x) {
193 if (x < 10) {
194 return x + '0';
195 }
196 x -= 10;
197 SkASSERT(x < 26);
198 return x + 'A';
199}
200#endif
201
202void ShowTestName(PathOpsThreadState* state, int a, int b, int c, int d) {
203#if DEBUG_SHOW_TEST_NAME
204 state->fSerialNo[0] = hexorator(state->fA);
205 state->fSerialNo[1] = hexorator(state->fB);
206 state->fSerialNo[2] = hexorator(state->fC);
207 state->fSerialNo[3] = hexorator(state->fD);
208 state->fSerialNo[4] = hexorator(a);
209 state->fSerialNo[5] = hexorator(b);
210 state->fSerialNo[6] = hexorator(c);
211 state->fSerialNo[7] = hexorator(d);
212 state->fSerialNo[8] = '\0';
213 SkDebugf("%s\n", state->fSerialNo);
214 if (strcmp(state->fSerialNo, state->fKey) == 0) {
215 SkDebugf("%s\n", state->fPathStr);
216 }
217#endif
218}
219
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000220const int bitWidth = 64;
221const int bitHeight = 64;
222
223static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
224 SkRect larger = one.getBounds();
225 larger.join(two.getBounds());
226 SkScalar largerWidth = larger.width();
227 if (largerWidth < 4) {
228 largerWidth = 4;
229 }
230 SkScalar largerHeight = larger.height();
231 if (largerHeight < 4) {
232 largerHeight = 4;
233 }
234 SkScalar hScale = (bitWidth - 2) / largerWidth;
235 SkScalar vScale = (bitHeight - 2) / largerHeight;
236 scale.reset();
237 scale.preScale(hScale, vScale);
238}
239
240static int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPath& scaledTwo,
241 int& error2x2) {
242 if (bits.width() == 0) {
243 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
244 bits.allocPixels();
245 }
246 SkCanvas canvas(bits);
247 canvas.drawColor(SK_ColorWHITE);
248 SkPaint paint;
249 canvas.save();
250 const SkRect& bounds1 = scaledOne.getBounds();
251 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
252 canvas.drawPath(scaledOne, paint);
253 canvas.restore();
254 canvas.save();
255 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
256 canvas.drawPath(scaledTwo, paint);
257 canvas.restore();
258 int errors2 = 0;
259 int errors = 0;
260 for (int y = 0; y < bitHeight - 1; ++y) {
261 uint32_t* addr1 = bits.getAddr32(0, y);
262 uint32_t* addr2 = bits.getAddr32(0, y + 1);
263 uint32_t* addr3 = bits.getAddr32(bitWidth, y);
264 uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
265 for (int x = 0; x < bitWidth - 1; ++x) {
266 // count 2x2 blocks
267 bool err = addr1[x] != addr3[x];
268 if (err) {
269 errors2 += addr1[x + 1] != addr3[x + 1]
270 && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
271 errors++;
272 }
273 }
274 }
275 if (errors2 >= 6 || errors > 160) {
276 SkDebugf("%s errors2=%d errors=%d\n", __FUNCTION__, errors2, errors);
277 }
278 error2x2 = errors2;
279 return errors;
280}
281
282static int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits, SkPath& scaledOne,
283 SkPath& scaledTwo, int& error2x2) {
284 SkMatrix scale;
285 scaleMatrix(one, two, scale);
286 one.transform(scale, &scaledOne);
287 two.transform(scale, &scaledTwo);
288 return pathsDrawTheSame(bits, scaledOne, scaledTwo, error2x2);
289}
290
291bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) {
292 if (!drawPaths) {
293 return true;
294 }
295 const SkRect& bounds1 = one.getBounds();
296 const SkRect& bounds2 = two.getBounds();
297 SkRect larger = bounds1;
298 larger.join(bounds2);
299 SkBitmap bits;
300 char out[256];
301 int bitWidth = SkScalarCeil(larger.width()) + 2;
302 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
303 return false;
304 }
305 int bitHeight = SkScalarCeil(larger.height()) + 2;
306 if (bitHeight >= (int) sizeof(out)) {
307 return false;
308 }
309 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
310 bits.allocPixels();
311 SkCanvas canvas(bits);
312 canvas.drawColor(SK_ColorWHITE);
313 SkPaint paint;
314 canvas.save();
315 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
316 canvas.drawPath(one, paint);
317 canvas.restore();
318 canvas.save();
319 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
320 canvas.drawPath(two, paint);
321 canvas.restore();
322 for (int y = 0; y < bitHeight; ++y) {
323 uint32_t* addr1 = bits.getAddr32(0, y);
324 int x;
325 char* outPtr = out;
326 for (x = 0; x < bitWidth; ++x) {
327 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
328 }
329 *outPtr++ = '|';
330 for (x = bitWidth; x < bitWidth * 2; ++x) {
331 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
332 }
333 *outPtr++ = '\0';
334 SkDebugf("%s\n", out);
335 }
336 return true;
337}
338
339static void showSimplifiedPath(const SkPath& one, const SkPath& two,
340 const SkPath& scaledOne, const SkPath& scaledTwo) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000341 showPath(one, "path", false);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000342 drawAsciiPaths(scaledOne, scaledTwo, true);
343}
344
345static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const SkPath& two,
346 SkBitmap& bitmap) {
347 int errors2x2;
348 SkPath scaledOne, scaledTwo;
349 int errors = pathsDrawTheSame(one, two, bitmap, scaledOne, scaledTwo, errors2x2);
350 if (errors2x2 == 0) {
351 return 0;
352 }
353 const int MAX_ERRORS = 9;
354 if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
355 showSimplifiedPath(one, two, scaledOne, scaledTwo);
356 }
357 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
358 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
359 showSimplifiedPath(one, two, scaledOne, scaledTwo);
360 REPORTER_ASSERT(reporter, 0);
361 }
362 return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
363}
364
365static void showPathOpPath(const SkPath& one, const SkPath& two, const SkPath& a, const SkPath& b,
366 const SkPath& scaledOne, const SkPath& scaledTwo, const SkPathOp shapeOp,
367 const SkMatrix& scale) {
caryclark@google.comad65a3e2013-04-15 19:13:59 +0000368 SkASSERT((unsigned) shapeOp < SK_ARRAY_COUNT(opStrs));
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000369 SkDebugf("static void xOp#%s(skiatest::Reporter* reporter) {\n", opSuffixes[shapeOp]);
370 SkDebugf(" SkPath path, pathB;\n");
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000371 showPath(a, "path", false);
372 showPath(b, "pathB", false);
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000373 SkDebugf(" testPathOp(reporter, path, pathB, %s);\n", opStrs[shapeOp]);
374 SkDebugf("}\n");
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000375 drawAsciiPaths(scaledOne, scaledTwo, true);
376}
377
378static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const SkPath& scaledOne,
379 const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap,
skia.committer@gmail.com391ca662013-04-11 07:01:45 +0000380 const SkPath& a, const SkPath& b, const SkPathOp shapeOp,
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000381 const SkMatrix& scale) {
382 int errors2x2;
383 int errors = pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
384 if (errors2x2 == 0) {
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000385 if (gShowPath) {
386 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
387 }
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000388 return 0;
389 }
390 const int MAX_ERRORS = 8;
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000391 if (gShowPath || errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000392 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
393 }
394 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
395 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
396 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
397 REPORTER_ASSERT(reporter, 0);
398 }
399 return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
400}
401
caryclark@google.com66089e42013-04-10 15:55:37 +0000402static int testNumber;
403static const char* testName;
404
405static void writeTestName(const char* nameSuffix, SkMemoryWStream& outFile) {
406 outFile.writeText(testName);
407 outFile.writeDecAsText(testNumber);
408 if (nameSuffix) {
409 outFile.writeText(nameSuffix);
410 }
411}
412
413static void outputToStream(const char* pathStr, const char* pathPrefix, const char* nameSuffix,
414 const char* testFunction, bool twoPaths, SkMemoryWStream& outFile) {
415 outFile.writeText("<div id=\"");
416 writeTestName(nameSuffix, outFile);
417 outFile.writeText("\">\n");
418 if (pathPrefix) {
419 outFile.writeText(pathPrefix);
420 }
421 outFile.writeText(pathStr);
422 outFile.writeText("</div>\n\n");
423
424 outFile.writeText(marker);
425 outFile.writeText(" ");
426 writeTestName(nameSuffix, outFile);
427 outFile.writeText(",\n\n\n");
428
429 outFile.writeText("static void ");
430 writeTestName(nameSuffix, outFile);
431 outFile.writeText("() {\n SkPath path");
432 if (twoPaths) {
433 outFile.writeText(", pathB");
434 }
435 outFile.writeText(";\n");
436 if (pathPrefix) {
437 outFile.writeText(pathPrefix);
438 }
439 outFile.writeText(pathStr);
440 outFile.writeText(" ");
441 outFile.writeText(testFunction);
442 outFile.writeText("\n}\n\n");
443 outFile.writeText("static void (*firstTest)() = ");
444 writeTestName(nameSuffix, outFile);
445 outFile.writeText(";\n\n");
446
447 outFile.writeText("static struct {\n");
448 outFile.writeText(" void (*fun)();\n");
449 outFile.writeText(" const char* str;\n");
450 outFile.writeText("} tests[] = {\n");
451 outFile.writeText(" TEST(");
452 writeTestName(nameSuffix, outFile);
453 outFile.writeText("),\n");
454 outFile.flush();
455}
456
457bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
458 const char* pathStr) {
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000459 SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType;
460 path.setFillType(fillType);
461 if (gShowPath) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000462 showPath(path, "path", false);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000463 }
caryclark@google.com66560ca2013-04-26 19:51:16 +0000464 if (!Simplify(path, &out)) {
465 SkDebugf("%s did not expect failure\n", __FUNCTION__);
466 REPORTER_ASSERT(state.fReporter, 0);
467 return false;
468 }
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000469 if (!gComparePaths) {
470 return true;
471 }
caryclark@google.com66089e42013-04-10 15:55:37 +0000472 int result = comparePaths(state.fReporter, path, out, *state.fBitmap);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000473 if (result && gPathStrAssert) {
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000474 char temp[8192];
475 sk_bzero(temp, sizeof(temp));
476 SkMemoryWStream stream(temp, sizeof(temp));
477 const char* pathPrefix = NULL;
478 const char* nameSuffix = NULL;
479 if (fillType == SkPath::kEvenOdd_FillType) {
480 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
481 nameSuffix = "x";
482 }
483 const char testFunction[] = "testSimplifyx(path);";
caryclark@google.com66089e42013-04-10 15:55:37 +0000484 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, stream);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000485 SkDebugf(temp);
caryclark@google.com66089e42013-04-10 15:55:37 +0000486 REPORTER_ASSERT(state.fReporter, 0);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000487 }
caryclark@google.com66089e42013-04-10 15:55:37 +0000488 state.fReporter->bumpTestCount();
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000489 return result == 0;
490}
491
492bool testSimplify(skiatest::Reporter* reporter, const SkPath& path) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000493#if DEBUG_SHOW_TEST_NAME
caryclark@google.com03610322013-04-18 15:58:21 +0000494 showPathData(path);
495#endif
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000496 SkPath out;
caryclark@google.com66560ca2013-04-26 19:51:16 +0000497 if (!Simplify(path, &out)) {
498 SkDebugf("%s did not expect failure\n", __FUNCTION__);
499 REPORTER_ASSERT(reporter, 0);
500 return false;
501 }
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000502 SkBitmap bitmap;
503 int result = comparePaths(reporter, path, out, bitmap);
504 if (result && gPathStrAssert) {
505 REPORTER_ASSERT(reporter, 0);
506 }
caryclark@google.com66089e42013-04-10 15:55:37 +0000507 reporter->bumpTestCount();
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000508 return result == 0;
509}
510
caryclark@google.coma5e55922013-05-07 18:51:31 +0000511#if DEBUG_SHOW_TEST_NAME
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000512void DebugShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp, const char* testName) {
513 ShowFunctionHeader(testName);
514 showPath(a, "path", true);
515 showPath(b, "pathB", true);
516 ShowOp(shapeOp, "path", "pathB");
517}
518#endif
519
520bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
521 const SkPathOp shapeOp, const char* testName) {
522#if DEBUG_SHOW_TEST_NAME
523 if (testName == NULL) {
524 showPathData(a);
525 showOp(shapeOp);
526 showPathData(b);
527 } else {
528 DebugShowPath(a, b, shapeOp, testName);
529 }
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000530#endif
531 SkPath out;
caryclark@google.com66560ca2013-04-26 19:51:16 +0000532 if (!Op(a, b, shapeOp, &out) ) {
533 SkDebugf("%s did not expect failure\n", __FUNCTION__);
534 REPORTER_ASSERT(reporter, 0);
535 return false;
536 }
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000537 SkPath pathOut, scaledPathOut;
538 SkRegion rgnA, rgnB, openClip, rgnOut;
539 openClip.setRect(-16000, -16000, 16000, 16000);
540 rgnA.setPath(a, openClip);
541 rgnB.setPath(b, openClip);
542 rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
543 rgnOut.getBoundaryPath(&pathOut);
544
545 SkMatrix scale;
546 scaleMatrix(a, b, scale);
547 SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
548 SkPath scaledA, scaledB;
549 scaledA.addPath(a, scale);
550 scaledA.setFillType(a.getFillType());
551 scaledB.addPath(b, scale);
552 scaledB.setFillType(b.getFillType());
553 scaledRgnA.setPath(scaledA, openClip);
554 scaledRgnB.setPath(scaledB, openClip);
555 scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
556 scaledRgnOut.getBoundaryPath(&scaledPathOut);
557 SkBitmap bitmap;
558 SkPath scaledOut;
559 scaledOut.addPath(out, scale);
560 scaledOut.setFillType(out.getFillType());
561 int result = comparePaths(reporter, pathOut, scaledPathOut, out, scaledOut, bitmap, a, b,
562 shapeOp, scale);
563 if (result && gPathStrAssert) {
564 REPORTER_ASSERT(reporter, 0);
565 }
caryclark@google.com66089e42013-04-10 15:55:37 +0000566 reporter->bumpTestCount();
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000567 return result == 0;
568}
569
caryclark@google.com16cfe402013-04-18 18:47:37 +0000570int initializeTests(skiatest::Reporter* reporter, const char* test) {
caryclark@google.com66089e42013-04-10 15:55:37 +0000571#ifdef SK_DEBUG
572 gDebugMaxWindSum = 4;
573 gDebugMaxWindValue = 4;
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000574#endif
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000575 testName = test;
caryclark@google.com66089e42013-04-10 15:55:37 +0000576 size_t testNameSize = strlen(test);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000577 SkFILEStream inFile("../../experimental/Intersection/op.htm");
578 if (inFile.isValid()) {
579 SkTDArray<char> inData;
580 inData.setCount(inFile.getLength());
581 size_t inLen = inData.count();
582 inFile.read(inData.begin(), inLen);
583 inFile.setPath(NULL);
584 char* insert = strstr(inData.begin(), marker);
585 if (insert) {
586 insert += sizeof(marker) - 1;
587 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1;
588 testNumber = atoi(numLoc) + 1;
589 }
590 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000591 return reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000592}
593
caryclark@google.com66089e42013-04-10 15:55:37 +0000594void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType pathFillType) {
595 const char testFunction[] = "testSimplify(path);";
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000596 const char* pathPrefix = NULL;
597 const char* nameSuffix = NULL;
598 if (pathFillType == SkPath::kEvenOdd_FillType) {
599 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
600 nameSuffix = "x";
601 }
caryclark@google.com66089e42013-04-10 15:55:37 +0000602 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE);
603 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, rRamStream);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000604}
605
caryclark@google.com66089e42013-04-10 15:55:37 +0000606void outputProgress(char* ramStr, const char* pathStr, SkPathOp op) {
607 const char testFunction[] = "testOp(path);";
caryclark@google.comad65a3e2013-04-15 19:13:59 +0000608 SkASSERT((size_t) op < SK_ARRAY_COUNT(opSuffixes));
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000609 const char* nameSuffix = opSuffixes[op];
caryclark@google.com66089e42013-04-10 15:55:37 +0000610 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE);
611 outputToStream(pathStr, NULL, nameSuffix, testFunction, true, rRamStream);
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000612}
613
614void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
615 void (*firstTest)(skiatest::Reporter* ),
616 void (*stopTest)(skiatest::Reporter* ), bool reverse) {
617 size_t index;
618 if (firstTest) {
619 index = count - 1;
620 while (index > 0 && tests[index].fun != firstTest) {
621 --index;
622 }
caryclark@google.coma5e55922013-05-07 18:51:31 +0000623#if DEBUG_SHOW_TEST_NAME
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000624 SkDebugf("<div id=\"%s\">\n", tests[index].str);
625 SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
626#endif
627 (*tests[index].fun)(reporter);
628 }
629 index = reverse ? count - 1 : 0;
630 size_t last = reverse ? 0 : count - 1;
631 do {
632 if (tests[index].fun != firstTest) {
caryclark@google.coma5e55922013-05-07 18:51:31 +0000633 #if DEBUG_SHOW_TEST_NAME
caryclark@google.com818b0cc2013-04-08 11:50:46 +0000634 SkDebugf("<div id=\"%s\">\n", tests[index].str);
635 SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
636 #endif
637 (*tests[index].fun)(reporter);
638 }
639 if (tests[index].fun == stopTest) {
640 SkDebugf("lastTest\n");
641 }
642 if (index == last) {
643 break;
644 }
645 index += reverse ? -1 : 1;
646 } while (true);
647}