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