EdgeWalker_TestUtility.cpp revision 1577e8f9c5bc8436cc71d3438c6d0b9f02c38338
15503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include "EdgeWalker_Test.h" 25503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include "Intersection_Tests.h" 35503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include "SkBitmap.h" 45503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include "SkCanvas.h" 55503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include "SkPaint.h" 65503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#include <algorithm> 75503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen 85503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#undef SkASSERT 95503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen#define SkASSERT(cond) while (!(cond)) { sk_throw(); } 105503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen 115503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gShowPath = false; 125503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gComparePaths = true; 135503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gDrawLastAsciiPaths = true; 145503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gDrawAllAsciiPaths = false; 155503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gShowAsciiPaths = false; 165503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic bool gComparePathsAssert = true; 1721b1984e161b0cadee331d32bfd721eccfdf4b1fJohnny Chen 185503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenvoid showPath(const SkPath& path, const char* str) { 195503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDebugf("%s\n", !str ? "original:" : str); 205503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkPath::Iter iter(path, true); 215503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen uint8_t verb; 225503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkPoint pts[4]; 235503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 245503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen switch (verb) { 255503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen case SkPath::kMove_Verb: 2621b1984e161b0cadee331d32bfd721eccfdf4b1fJohnny Chen SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY); 275503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen continue; 285503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen case SkPath::kLine_Verb: 295503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY); 305503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen break; 315503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen case SkPath::kQuad_Verb: 325503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", 335503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 345503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen break; 355503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen case SkPath::kCubic_Verb: 365503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", 375503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, 385503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen pts[3].fX, pts[3].fY); 395503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen break; 405503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen case SkPath::kClose_Verb: 415503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDebugf("path.close();\n"); 425503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen continue; 435503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen default: 445503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkDEBUGFAIL("bad verb"); 455503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen return; 465503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen } 475503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen } 485503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen} 495503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen 505503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chenstatic int pathsDrawTheSame(const SkPath& one, const SkPath& two, 515503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkBitmap& bits, SkCanvas* c) { 525503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkCanvas* canvasPtr = c; 535503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen if (!c) { 545503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvasPtr = new SkCanvas(bits); 555503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen } 565503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen const SkRect& bounds1 = one.getBounds(); 575503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen const SkRect& bounds2 = two.getBounds(); 585503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkRect larger = bounds1; 595503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen larger.join(bounds2); 605503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen int bitWidth = SkScalarCeil(larger.width()) + 2; 61166b89f089d6bec5bb9dd40470a4dc951ffc9daaGreg Clayton int bitHeight = SkScalarCeil(larger.height()) + 2; 625503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen if (bits.width() < bitWidth * 2 || bits.height() < bitHeight) { 635503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen if (bits.width() >= 200) { 6462ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen SkDebugf("%s bitWidth=%d bitHeight=%d\n", __FUNCTION__, bitWidth, bitHeight); 6562ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen } 6662ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); 6762ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen bits.allocPixels(); 6862ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen canvasPtr->setBitmapDevice(bits); 6962ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen } 7062ebe5aca6d93eecba7c9917440107f4b24a09cdJohnny Chen SkCanvas& canvas = *canvasPtr; 71638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.drawColor(SK_ColorWHITE); 72638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen SkPaint paint; 73638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.save(); 74638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); 75638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.drawPath(one, paint); 76638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.restore(); 77638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.save(); 78638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); 79638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.drawPath(two, paint); 80638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen canvas.restore(); 81638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen int errors = 0; 82638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen for (int y = 0; y < bitHeight; ++y) { 83638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen uint32_t* addr1 = bits.getAddr32(0, y); 84638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen uint32_t* addr2 = bits.getAddr32(bitWidth, y); 85084fd8945b922818e069adfb72ac39936466e221Johnny Chen for (int x = 0; x < bitWidth; ++x) { 86638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen errors += addr1[x] != addr2[x]; 87638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen } 88084fd8945b922818e069adfb72ac39936466e221Johnny Chen } 89084fd8945b922818e069adfb72ac39936466e221Johnny Chen if (!c) { 90084fd8945b922818e069adfb72ac39936466e221Johnny Chen delete canvasPtr; 91638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen } 92638ebcfea6328816ba5e9fd21e40cf5d3f060e2eJohnny Chen return errors; 93084fd8945b922818e069adfb72ac39936466e221Johnny Chen} 94f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen 95f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chenvoid bitmapInit(SkBitmap& bits) { 96f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen} 97f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen 98f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chenbool drawAsciiPaths(const SkPath& one, const SkPath& two, 99f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen bool drawPaths) { 100f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen if (!drawPaths) { 101f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen return true; 102f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen } 103f24f1cd1584fd2af8f3dfa6919fe493b86b17729Johnny Chen if (gShowAsciiPaths) { 104ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen showPath(one, "one:"); 105ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen showPath(two, "two:"); 106ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen } 107ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen const SkRect& bounds1 = one.getBounds(); 108ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen const SkRect& bounds2 = two.getBounds(); 109ab881d86a527f17df84c200322b2e5c9bf64b0deJohnny Chen SkRect larger = bounds1; 1105503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen larger.join(bounds2); 1115503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkBitmap bits; 1125503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen char out[256]; 1135503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen int bitWidth = SkScalarCeil(larger.width()) + 2; 1145503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen if (bitWidth * 2 + 1 >= (int) sizeof(out)) { 1154b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen return false; 1164b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen } 1174b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen int bitHeight = SkScalarCeil(larger.height()) + 2; 1184b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen if (bitHeight >= (int) sizeof(out)) { 1194b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen return false; 1204b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen } 1214b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight); 1224b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen bits.allocPixels(); 1234b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen SkCanvas canvas(bits); 1244b067250787b3d1763a58fa142cc21cf995e942cJohnny Chen canvas.drawColor(SK_ColorWHITE); 1255503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen SkPaint paint; 1265503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.save(); 1275503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); 1285503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.drawPath(one, paint); 1295503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.restore(); 1305503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.save(); 1315503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); 1325503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.drawPath(two, paint); 1335503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen canvas.restore(); 1345503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen for (int y = 0; y < bitHeight; ++y) { 1355503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen uint32_t* addr1 = bits.getAddr32(0, y); 1365503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen int x; 1375503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen char* outPtr = out; 1385503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen for (x = 0; x < bitWidth; ++x) { 1395503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; 1405503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen } 1415503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen *outPtr++ = '|'; 1425503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen for (x = bitWidth; x < bitWidth * 2; ++x) { 1435503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x'; 1445503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen } 1455503d468e43aae7d047c9b98baf626fc5b6c352dJohnny Chen *outPtr++ = '\0'; 146 SkDebugf("%s\n", out); 147 } 148 return true; 149} 150 151static int scaledDrawTheSame(const SkPath& one, const SkPath& two, 152 int a, int b, bool drawPaths, SkBitmap& bitmap, SkCanvas* canvas) { 153 SkMatrix scale; 154 scale.reset(); 155 float aScale = 1.21f; 156 float bScale = 1.11f; 157 scale.preScale(a * aScale, b * bScale); 158 SkPath scaledOne, scaledTwo; 159 one.transform(scale, &scaledOne); 160 two.transform(scale, &scaledTwo); 161 int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas); 162 if (errors == 0) { 163 return 0; 164 } 165 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 } 173 return errors; 174} 175 176static int max = 0; 177 178int 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; 183 } 184 drawAsciiPaths(one, two, gDrawAllAsciiPaths); 185 for (int x = 9; x <= 33; ++x) { 186 errors = scaledDrawTheSame(one, two, x, x - (x >> 2), gDrawAllAsciiPaths, 187 bitmap, canvas); 188 if (errors == 0) { 189 return 0; 190 } 191 } 192 if (!gDrawAllAsciiPaths) { 193 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); 200 if (errors > 50) { 201 scaledDrawTheSame(one, two, xScale, yScale, true, bitmap, canvas); 202 } 203 } 204 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) { 211 showPath(one); 212 showPath(two, "simplified:"); 213 SkASSERT(0); 214 } 215 return errors > MAX_ERRORS ? errors : 0; 216} 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 249bool testSimplify(const SkPath& path, bool fill, SkPath& out, SkBitmap& bitmap, 250 SkCanvas* canvas) { 251 if (gShowPath) { 252 showPath(path); 253 } 254 simplify(path, fill, out); 255 if (!gComparePaths) { 256 return true; 257 } 258 return comparePaths(path, out, bitmap, canvas) == 0; 259} 260 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} 280