PathOpsExtendedTest.cpp revision 1b24933e52f50773de29332387a12721811f3012
14bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo/* 24bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo * Copyright 2012 Google Inc. 34bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo * 44bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo * Use of this source code is governed by a BSD-style license that can be 50dce41c2ece9020d5ac9bb68c9772432fac85e64Louis Yung-Chieh Lo * found in the LICENSE file. 60dce41c2ece9020d5ac9bb68c9772432fac85e64Louis Yung-Chieh Lo */ 74bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo 84bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo#include "PathOpsExtendedTest.h" 93ecaf776d82d29573be083b2e5c6ddc5b9f49c70vbendeb#include "PathOpsThreadedCommon.h" 104bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo#include "SkBitmap.h" 1137f6b55a25f337f555da1dfbe585d32cd004103dLouis Yung-Chieh Lo#include "SkCanvas.h" 1237f6b55a25f337f555da1dfbe585d32cd004103dLouis Yung-Chieh Lo#include "SkForceLinking.h" 1337f6b55a25f337f555da1dfbe585d32cd004103dLouis Yung-Chieh Lo#include "SkMatrix.h" 1437f6b55a25f337f555da1dfbe585d32cd004103dLouis Yung-Chieh Lo#include "SkMutex.h" 154bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo#include "SkPaint.h" 1649fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo#include "SkRTConf.h" 173ecaf776d82d29573be083b2e5c6ddc5b9f49c70vbendeb#include "SkStream.h" 1849fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo 1949fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo#ifdef SK_BUILD_FOR_MAC 2049fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo#include <sys/sysctl.h> 214bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo#endif 2249fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo 2349fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo__SK_FORCE_IMAGE_DECODER_LINKING; 2449fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo 2549fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh LoDEFINE_bool2(runFail, f, false, "run tests known to fail."); 2649fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh LoDEFINE_bool2(runBinary, f, false, "run tests known to fail binary sect."); 2749fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lo 2849fa8e51ad4dff55b74d852d270ce5d0b9590034Louis Yung-Chieh Lostatic const char marker[] = 294bbf21e47663914d355941ff61fcbf262b4085acLouis Yung-Chieh Lo "</div>\n" 300dce41c2ece9020d5ac9bb68c9772432fac85e64Louis Yung-Chieh Lo "\n" 31 "<script type=\"text/javascript\">\n" 32 "\n" 33 "var testDivs = [\n"; 34 35static const char* opStrs[] = { 36 "kDifference_SkPathOp", 37 "kIntersect_SkPathOp", 38 "kUnion_SkPathOp", 39 "kXor_PathOp", 40 "kReverseDifference_SkPathOp", 41}; 42 43static const char* opSuffixes[] = { 44 "d", 45 "i", 46 "u", 47 "o", 48}; 49 50#if DEBUG_SHOW_TEST_NAME 51static void showPathData(const SkPath& path) { 52 SkPath::RawIter iter(path); 53 uint8_t verb; 54 SkPoint pts[4]; 55 SkPoint firstPt = {0, 0}, lastPt = {0, 0}; 56 bool firstPtSet = false; 57 bool lastPtSet = true; 58 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 59 switch (verb) { 60 case SkPath::kMove_Verb: 61 if (firstPtSet && lastPtSet && firstPt != lastPt) { 62 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY, 63 firstPt.fX, firstPt.fY); 64 lastPtSet = false; 65 } 66 firstPt = pts[0]; 67 firstPtSet = true; 68 continue; 69 case SkPath::kLine_Verb: 70 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0].fY, 71 pts[1].fX, pts[1].fY); 72 lastPt = pts[1]; 73 lastPtSet = true; 74 break; 75 case SkPath::kQuad_Verb: 76 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", 77 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 78 lastPt = pts[2]; 79 lastPtSet = true; 80 break; 81 case SkPath::kConic_Verb: 82 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}, //weight=%1.9g\n", 83 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, 84 iter.conicWeight()); 85 lastPt = pts[2]; 86 lastPtSet = true; 87 break; 88 case SkPath::kCubic_Verb: 89 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", 90 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, 91 pts[3].fX, pts[3].fY); 92 lastPt = pts[3]; 93 lastPtSet = true; 94 break; 95 case SkPath::kClose_Verb: 96 if (firstPtSet && lastPtSet && firstPt != lastPt) { 97 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY, 98 firstPt.fX, firstPt.fY); 99 } 100 firstPtSet = lastPtSet = false; 101 break; 102 default: 103 SkDEBUGFAIL("bad verb"); 104 return; 105 } 106 } 107 if (firstPtSet && lastPtSet && firstPt != lastPt) { 108 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", lastPt.fX, lastPt.fY, 109 firstPt.fX, firstPt.fY); 110 } 111} 112#endif 113 114void showOp(const SkPathOp op) { 115 switch (op) { 116 case kDifference_SkPathOp: 117 SkDebugf("op difference\n"); 118 break; 119 case kIntersect_SkPathOp: 120 SkDebugf("op intersect\n"); 121 break; 122 case kUnion_SkPathOp: 123 SkDebugf("op union\n"); 124 break; 125 case kXOR_SkPathOp: 126 SkDebugf("op xor\n"); 127 break; 128 case kReverseDifference_SkPathOp: 129 SkDebugf("op reverse difference\n"); 130 break; 131 default: 132 SkASSERT(0); 133 } 134} 135 136#if DEBUG_SHOW_TEST_NAME 137static char hexorator(int x) { 138 if (x < 10) { 139 return x + '0'; 140 } 141 x -= 10; 142 SkASSERT(x < 26); 143 return x + 'A'; 144} 145#endif 146 147void ShowTestName(PathOpsThreadState* state, int a, int b, int c, int d) { 148#if DEBUG_SHOW_TEST_NAME 149 state->fSerialNo[0] = hexorator(state->fA); 150 state->fSerialNo[1] = hexorator(state->fB); 151 state->fSerialNo[2] = hexorator(state->fC); 152 state->fSerialNo[3] = hexorator(state->fD); 153 state->fSerialNo[4] = hexorator(a); 154 state->fSerialNo[5] = hexorator(b); 155 state->fSerialNo[6] = hexorator(c); 156 state->fSerialNo[7] = hexorator(d); 157 state->fSerialNo[8] = '\0'; 158 SkDebugf("%s\n", state->fSerialNo); 159 if (strcmp(state->fSerialNo, state->fKey) == 0) { 160 SkDebugf("%s\n", state->fPathStr); 161 } 162#endif 163} 164 165const int bitWidth = 64; 166const int bitHeight = 64; 167 168static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) { 169 SkRect larger = one.getBounds(); 170 larger.join(two.getBounds()); 171 SkScalar largerWidth = larger.width(); 172 if (largerWidth < 4) { 173 largerWidth = 4; 174 } 175 SkScalar largerHeight = larger.height(); 176 if (largerHeight < 4) { 177 largerHeight = 4; 178 } 179 SkScalar hScale = (bitWidth - 2) / largerWidth; 180 SkScalar vScale = (bitHeight - 2) / largerHeight; 181 scale.reset(); 182 scale.preScale(hScale, vScale); 183} 184 185static int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPath& scaledTwo, 186 int& error2x2) { 187 if (bits.width() == 0) { 188 bits.allocN32Pixels(bitWidth * 2, bitHeight); 189 } 190 SkCanvas canvas(bits); 191 canvas.drawColor(SK_ColorWHITE); 192 SkPaint paint; 193 canvas.save(); 194 const SkRect& bounds1 = scaledOne.getBounds(); 195 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); 196 canvas.drawPath(scaledOne, paint); 197 canvas.restore(); 198 canvas.save(); 199 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); 200 canvas.drawPath(scaledTwo, paint); 201 canvas.restore(); 202 int errors2 = 0; 203 int errors = 0; 204 for (int y = 0; y < bitHeight - 1; ++y) { 205 uint32_t* addr1 = bits.getAddr32(0, y); 206 uint32_t* addr2 = bits.getAddr32(0, y + 1); 207 uint32_t* addr3 = bits.getAddr32(bitWidth, y); 208 uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1); 209 for (int x = 0; x < bitWidth - 1; ++x) { 210 // count 2x2 blocks 211 bool err = addr1[x] != addr3[x]; 212 if (err) { 213 errors2 += addr1[x + 1] != addr3[x + 1] 214 && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1]; 215 errors++; 216 } 217 } 218 } 219 error2x2 = errors2; 220 return errors; 221} 222 223static int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits, SkPath& scaledOne, 224 SkPath& scaledTwo, int& error2x2) { 225 SkMatrix scale; 226 scaleMatrix(one, two, scale); 227 one.transform(scale, &scaledOne); 228 two.transform(scale, &scaledTwo); 229 return pathsDrawTheSame(bits, scaledOne, scaledTwo, error2x2); 230} 231 232bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) { 233 if (!drawPaths) { 234 return true; 235 } 236 const SkRect& bounds1 = one.getBounds(); 237 const SkRect& bounds2 = two.getBounds(); 238 SkRect larger = bounds1; 239 larger.join(bounds2); 240 SkBitmap bits; 241 char out[256]; 242 int bitWidth = SkScalarCeilToInt(larger.width()) + 2; 243 if (bitWidth * 2 + 1 >= (int) sizeof(out)) { 244 return false; 245 } 246 int bitHeight = SkScalarCeilToInt(larger.height()) + 2; 247 if (bitHeight >= (int) sizeof(out)) { 248 return false; 249 } 250 bits.allocN32Pixels(bitWidth * 2, bitHeight); 251 SkCanvas canvas(bits); 252 canvas.drawColor(SK_ColorWHITE); 253 SkPaint paint; 254 canvas.save(); 255 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); 256 canvas.drawPath(one, paint); 257 canvas.restore(); 258 canvas.save(); 259 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); 260 canvas.drawPath(two, paint); 261 canvas.restore(); 262 for (int y = 0; y < bitHeight; ++y) { 263 uint32_t* addr1 = bits.getAddr32(0, y); 264 int x; 265 char* outPtr = out; 266 for (x = 0; x < bitWidth; ++x) { 267 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; 268 } 269 *outPtr++ = '|'; 270 for (x = bitWidth; x < bitWidth * 2; ++x) { 271 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; 272 } 273 *outPtr++ = '\0'; 274 SkDebugf("%s\n", out); 275 } 276 return true; 277} 278 279int comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPath& one, 280 const SkPath& two, SkBitmap& bitmap) { 281 int errors2x2; 282 SkPath scaledOne, scaledTwo; 283 (void) pathsDrawTheSame(one, two, bitmap, scaledOne, scaledTwo, errors2x2); 284 if (errors2x2 == 0) { 285 return 0; 286 } 287 const int MAX_ERRORS = 9; 288 return errors2x2 > MAX_ERRORS ? errors2x2 : 0; 289} 290 291const int gTestFirst = 41; 292static int gTestNo = gTestFirst; 293static SkTDArray<SkPathOp> gTestOp; 294 295static void showPathOpPath(const char* testName, const SkPath& one, const SkPath& two, 296 const SkPath& a, const SkPath& b, const SkPath& scaledOne, const SkPath& scaledTwo, 297 const SkPathOp shapeOp, const SkMatrix& scale) { 298 SkASSERT((unsigned) shapeOp < SK_ARRAY_COUNT(opStrs)); 299 if (!testName) { 300 testName = "xOp"; 301 } 302 SkDebugf("static void %s%d%s(skiatest::Reporter* reporter, const char* filename) {\n", 303 testName, gTestNo, opSuffixes[shapeOp]); 304 *gTestOp.append() = shapeOp; 305 ++gTestNo; 306 SkDebugf(" SkPath path, pathB;\n"); 307 SkPathOpsDebug::ShowOnePath(a, "path", false); 308 SkPathOpsDebug::ShowOnePath(b, "pathB", false); 309 SkDebugf(" testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]); 310 SkDebugf("}\n"); 311 drawAsciiPaths(scaledOne, scaledTwo, false); 312} 313 314void ShowTestArray(const char* testName) { 315 if (!testName) { 316 testName = "xOp"; 317 } 318 for (int x = gTestFirst; x < gTestNo; ++x) { 319 SkDebugf(" TEST(%s%d%s),\n", testName, x, opSuffixes[gTestOp[x - gTestFirst]]); 320 } 321} 322 323SK_DECLARE_STATIC_MUTEX(compareDebugOut3); 324 325static int comparePaths(skiatest::Reporter* reporter, const char* testName, const SkPath& one, 326 const SkPath& scaledOne, const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap, 327 const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale, 328 bool expectSuccess) { 329 int errors2x2; 330 const int MAX_ERRORS = 8; 331 (void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2); 332 if (!expectSuccess) { 333 if (errors2x2 < MAX_ERRORS) { 334 REPORTER_ASSERT(reporter, 0); 335 } 336 return 0; 337 } 338 if (errors2x2 == 0) { 339 return 0; 340 } 341 if (errors2x2 >= MAX_ERRORS) { 342 SkAutoMutexAcquire autoM(compareDebugOut3); 343 showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale); 344 SkDebugf("\n/*"); 345 REPORTER_ASSERT(reporter, 0); 346 SkDebugf(" */\n"); 347 } 348 return errors2x2 >= MAX_ERRORS ? errors2x2 : 0; 349} 350 351// Default values for when reporter->verbose() is false. 352static int testNumber = 55; 353static const char* testName = "pathOpTest"; 354 355static void writeTestName(const char* nameSuffix, SkMemoryWStream& outFile) { 356 outFile.writeText(testName); 357 outFile.writeDecAsText(testNumber); 358 ++testNumber; 359 if (nameSuffix) { 360 outFile.writeText(nameSuffix); 361 } 362} 363 364static void outputToStream(const char* pathStr, const char* pathPrefix, const char* nameSuffix, 365 const char* testFunction, bool twoPaths, SkMemoryWStream& outFile) { 366#if 0 367 outFile.writeText("\n<div id=\""); 368 writeTestName(nameSuffix, outFile); 369 outFile.writeText("\">\n"); 370 if (pathPrefix) { 371 outFile.writeText(pathPrefix); 372 } 373 outFile.writeText(pathStr); 374 outFile.writeText("</div>\n\n"); 375 376 outFile.writeText(marker); 377 outFile.writeText(" "); 378 writeTestName(nameSuffix, outFile); 379 outFile.writeText(",\n\n\n"); 380#endif 381 outFile.writeText("static void "); 382 writeTestName(nameSuffix, outFile); 383 outFile.writeText("(skiatest::Reporter* reporter) {\n SkPath path"); 384 if (twoPaths) { 385 outFile.writeText(", pathB"); 386 } 387 outFile.writeText(";\n"); 388 if (pathPrefix) { 389 outFile.writeText(pathPrefix); 390 } 391 outFile.writeText(pathStr); 392 outFile.writeText(" "); 393 outFile.writeText(testFunction); 394 outFile.writeText("\n}\n\n"); 395#if 0 396 outFile.writeText("static void (*firstTest)() = "); 397 writeTestName(nameSuffix, outFile); 398 outFile.writeText(";\n\n"); 399 400 outFile.writeText("static struct {\n"); 401 outFile.writeText(" void (*fun)();\n"); 402 outFile.writeText(" const char* str;\n"); 403 outFile.writeText("} tests[] = {\n"); 404 outFile.writeText(" TEST("); 405 writeTestName(nameSuffix, outFile); 406 outFile.writeText("),\n"); 407#endif 408 outFile.flush(); 409} 410 411SK_DECLARE_STATIC_MUTEX(simplifyDebugOut); 412 413bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state, 414 const char* pathStr) { 415 SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType; 416 path.setFillType(fillType); 417 state.fReporter->bumpTestCount(); 418 if (!Simplify(path, &out)) { 419 SkDebugf("%s did not expect failure\n", __FUNCTION__); 420 REPORTER_ASSERT(state.fReporter, 0); 421 return false; 422 } 423 if (!state.fReporter->verbose()) { 424 return true; 425 } 426 int result = comparePaths(state.fReporter, NULL, path, out, *state.fBitmap); 427 if (result) { 428 SkAutoMutexAcquire autoM(simplifyDebugOut); 429 char temp[8192]; 430 sk_bzero(temp, sizeof(temp)); 431 SkMemoryWStream stream(temp, sizeof(temp)); 432 const char* pathPrefix = NULL; 433 const char* nameSuffix = NULL; 434 if (fillType == SkPath::kEvenOdd_FillType) { 435 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; 436 nameSuffix = "x"; 437 } 438 const char testFunction[] = "testSimplify(reporter, path);"; 439 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, stream); 440 SkDebugf("%s", temp); 441 REPORTER_ASSERT(state.fReporter, 0); 442 } 443 state.fReporter->bumpTestCount(); 444 return result == 0; 445} 446 447static bool inner_simplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename, 448 bool checkFail) { 449#if 0 && DEBUG_SHOW_TEST_NAME 450 showPathData(path); 451#endif 452 SkPath out; 453 if (!Simplify(path, &out)) { 454 SkDebugf("%s did not expect %s failure\n", __FUNCTION__, filename); 455 REPORTER_ASSERT(reporter, 0); 456 return false; 457 } 458 SkBitmap bitmap; 459 int errors = comparePaths(reporter, filename, path, out, bitmap); 460 if (!checkFail) { 461 if (!errors) { 462 SkDebugf("%s failing test %s now succeeds\n", __FUNCTION__, filename); 463 REPORTER_ASSERT(reporter, 0); 464 return false; 465 } 466 } else if (errors) { 467 REPORTER_ASSERT(reporter, 0); 468 } 469 reporter->bumpTestCount(); 470 return errors == 0; 471} 472 473bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename) { 474 return inner_simplify(reporter, path, filename, true); 475} 476 477bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path, const char* filename, 478 bool checkFail) { 479 return inner_simplify(reporter, path, filename, checkFail); 480} 481 482#if DEBUG_SHOW_TEST_NAME 483static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) { 484 SkDebugf("\n"); 485 showPathData(a); 486 showOp(shapeOp); 487 showPathData(b); 488} 489#endif 490 491bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, bool expectSuccess); 492 493static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, 494 const SkPathOp shapeOp, const char* testName, bool expectSuccess) { 495#if 0 && DEBUG_SHOW_TEST_NAME 496 showName(a, b, shapeOp); 497#endif 498 SkPath out; 499 if (!OpDebug(a, b, shapeOp, &out, expectSuccess)) { 500 SkDebugf("%s did not expect failure\n", __FUNCTION__); 501 REPORTER_ASSERT(reporter, 0); 502 return false; 503 } 504 if (!reporter->verbose()) { 505 return true; 506 } 507 SkPath pathOut, scaledPathOut; 508 SkRegion rgnA, rgnB, openClip, rgnOut; 509 openClip.setRect(-16000, -16000, 16000, 16000); 510 rgnA.setPath(a, openClip); 511 rgnB.setPath(b, openClip); 512 rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp); 513 rgnOut.getBoundaryPath(&pathOut); 514 515 SkMatrix scale; 516 scaleMatrix(a, b, scale); 517 SkRegion scaledRgnA, scaledRgnB, scaledRgnOut; 518 SkPath scaledA, scaledB; 519 scaledA.addPath(a, scale); 520 scaledA.setFillType(a.getFillType()); 521 scaledB.addPath(b, scale); 522 scaledB.setFillType(b.getFillType()); 523 scaledRgnA.setPath(scaledA, openClip); 524 scaledRgnB.setPath(scaledB, openClip); 525 scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp); 526 scaledRgnOut.getBoundaryPath(&scaledPathOut); 527 SkBitmap bitmap; 528 SkPath scaledOut; 529 scaledOut.addPath(out, scale); 530 scaledOut.setFillType(out.getFillType()); 531 int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap, 532 a, b, shapeOp, scale, expectSuccess); 533 reporter->bumpTestCount(); 534 return result == 0; 535} 536 537bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, 538 const SkPathOp shapeOp, const char* testName) { 539 return innerPathOp(reporter, a, b, shapeOp, testName, true); 540} 541 542bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, 543 const SkPathOp shapeOp, const char* testName, bool checkFail) { 544 return innerPathOp(reporter, a, b, shapeOp, testName, checkFail); 545} 546 547bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, 548 const SkPathOp shapeOp, const char* testName) { 549 return innerPathOp(reporter, a, b, shapeOp, testName, false); 550} 551 552bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, 553 const SkPathOp shapeOp, const char* testName) { 554#if DEBUG_SHOW_TEST_NAME 555 showName(a, b, shapeOp); 556#endif 557 SkPath orig; 558 orig.lineTo(54, 43); 559 SkPath out = orig; 560 if (Op(a, b, shapeOp, &out) ) { 561 SkDebugf("%s test is expected to fail\n", __FUNCTION__); 562 REPORTER_ASSERT(reporter, 0); 563 return false; 564 } 565 SkASSERT(out == orig); 566 return true; 567} 568 569SK_DECLARE_STATIC_MUTEX(gMutex); 570 571void initializeTests(skiatest::Reporter* reporter, const char* test) { 572#if 0 // doesn't work yet 573 SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); 574 SK_CONF_SET("images.png.suppressDecoderWarnings", true); 575#endif 576 if (reporter->verbose()) { 577 SkAutoMutexAcquire lock(gMutex); 578 testName = test; 579 size_t testNameSize = strlen(test); 580 SkFILEStream inFile("../../experimental/Intersection/op.htm"); 581 if (inFile.isValid()) { 582 SkTDArray<char> inData; 583 inData.setCount((int) inFile.getLength()); 584 size_t inLen = inData.count(); 585 inFile.read(inData.begin(), inLen); 586 inFile.setPath(NULL); 587 char* insert = strstr(inData.begin(), marker); 588 if (insert) { 589 insert += sizeof(marker) - 1; 590 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1; 591 testNumber = atoi(numLoc) + 1; 592 } 593 } 594 } 595} 596 597void outputProgress(char* ramStr, const char* pathStr, SkPath::FillType pathFillType) { 598 const char testFunction[] = "testSimplify(path);"; 599 const char* pathPrefix = NULL; 600 const char* nameSuffix = NULL; 601 if (pathFillType == SkPath::kEvenOdd_FillType) { 602 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n"; 603 nameSuffix = "x"; 604 } 605 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE); 606 outputToStream(pathStr, pathPrefix, nameSuffix, testFunction, false, rRamStream); 607} 608 609void outputProgress(char* ramStr, const char* pathStr, SkPathOp op) { 610 const char testFunction[] = "testOp(path);"; 611 SkASSERT((size_t) op < SK_ARRAY_COUNT(opSuffixes)); 612 const char* nameSuffix = opSuffixes[op]; 613 SkMemoryWStream rRamStream(ramStr, PATH_STR_SIZE); 614 outputToStream(pathStr, NULL, nameSuffix, testFunction, true, rRamStream); 615} 616 617void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count, 618 void (*firstTest)(skiatest::Reporter* , const char* filename), 619 void (*skipTest)(skiatest::Reporter* , const char* filename), 620 void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse) { 621 size_t index; 622 if (firstTest) { 623 index = count - 1; 624 while (index > 0 && tests[index].fun != firstTest) { 625 --index; 626 } 627#if DEBUG_SHOW_TEST_NAME 628 SkDebugf("\n<div id=\"%s\">\n", tests[index].str); 629#endif 630 (*tests[index].fun)(reporter, tests[index].str); 631 if (tests[index].fun == stopTest) { 632 return; 633 } 634 } 635 index = reverse ? count - 1 : 0; 636 size_t last = reverse ? 0 : count - 1; 637 bool foundSkip = !skipTest; 638 do { 639 if (tests[index].fun == skipTest) { 640 foundSkip = true; 641 } 642 if (foundSkip && tests[index].fun != firstTest) { 643 #if DEBUG_SHOW_TEST_NAME 644 SkDebugf("\n<div id=\"%s\">\n", tests[index].str); 645 #endif 646 (*tests[index].fun)(reporter, tests[index].str); 647 } 648 if (tests[index].fun == stopTest || index == last) { 649 break; 650 } 651 index += reverse ? -1 : 1; 652 } while (true); 653#if DEBUG_SHOW_TEST_NAME 654 SkDebugf( 655 "\n" 656 "</div>\n" 657 "\n" 658 "<script type=\"text/javascript\">\n" 659 "\n" 660 "var testDivs = [\n" 661 ); 662 index = reverse ? count - 1 : 0; 663 last = reverse ? 0 : count - 1; 664 foundSkip = !skipTest; 665 do { 666 if (tests[index].fun == skipTest) { 667 foundSkip = true; 668 } 669 if (foundSkip && tests[index].fun != firstTest) { 670 SkDebugf(" %s,\n", tests[index].str); 671 } 672 if (tests[index].fun == stopTest || index == last) { 673 break; 674 } 675 index += reverse ? -1 : 1; 676 } while (true); 677#endif 678} 679