1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
12cb93a386Sopenharmony_ci#include "include/core/SkRegion.h"
13cb93a386Sopenharmony_ci#include "include/core/SkStream.h"
14cb93a386Sopenharmony_ci#include "include/private/SkMutex.h"
15cb93a386Sopenharmony_ci#include "include/utils/SkParsePath.h"
16cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
17cb93a386Sopenharmony_ci#include "tests/PathOpsDebug.h"
18cb93a386Sopenharmony_ci#include "tests/PathOpsExtendedTest.h"
19cb93a386Sopenharmony_ci#include "tests/PathOpsThreadedCommon.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci#include <stdlib.h>
22cb93a386Sopenharmony_ci#include <vector>
23cb93a386Sopenharmony_ci#include <string>
24cb93a386Sopenharmony_ci#include <algorithm>
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistd::vector<std::string> gUniqueNames;
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC
29cb93a386Sopenharmony_ci#include <sys/sysctl.h>
30cb93a386Sopenharmony_ci#endif
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci// std::to_string isn't implemented on android
33cb93a386Sopenharmony_ci#include <sstream>
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_citemplate <typename T>
36cb93a386Sopenharmony_cistd::string std_to_string(T value)
37cb93a386Sopenharmony_ci{
38cb93a386Sopenharmony_ci    std::ostringstream os ;
39cb93a386Sopenharmony_ci    os << value ;
40cb93a386Sopenharmony_ci    return os.str() ;
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_cibool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
44cb93a386Sopenharmony_ci             SkDEBUGPARAMS(bool skipAssert)
45cb93a386Sopenharmony_ci             SkDEBUGPARAMS(const char* testName));
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_cibool SimplifyDebug(const SkPath& one, SkPath* result
48cb93a386Sopenharmony_ci                   SkDEBUGPARAMS(bool skipAssert)
49cb93a386Sopenharmony_ci                   SkDEBUGPARAMS(const char* testName));
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_cistatic const char marker[] =
52cb93a386Sopenharmony_ci    "</div>\n"
53cb93a386Sopenharmony_ci    "\n"
54cb93a386Sopenharmony_ci    "<script type=\"text/javascript\">\n"
55cb93a386Sopenharmony_ci    "\n"
56cb93a386Sopenharmony_ci    "var testDivs = [\n";
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cistatic const char* opStrs[] = {
59cb93a386Sopenharmony_ci    "kDifference_SkPathOp",
60cb93a386Sopenharmony_ci    "kIntersect_SkPathOp",
61cb93a386Sopenharmony_ci    "kUnion_SkPathOp",
62cb93a386Sopenharmony_ci    "kXOR_PathOp",
63cb93a386Sopenharmony_ci    "kReverseDifference_SkPathOp",
64cb93a386Sopenharmony_ci};
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_cistatic const char* opSuffixes[] = {
67cb93a386Sopenharmony_ci    "d",
68cb93a386Sopenharmony_ci    "i",
69cb93a386Sopenharmony_ci    "u",
70cb93a386Sopenharmony_ci    "o",
71cb93a386Sopenharmony_ci    "r",
72cb93a386Sopenharmony_ci};
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_cienum class ExpectSuccess {
75cb93a386Sopenharmony_ci    kNo,
76cb93a386Sopenharmony_ci    kYes,
77cb93a386Sopenharmony_ci    kFlaky
78cb93a386Sopenharmony_ci};
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cienum class SkipAssert {
81cb93a386Sopenharmony_ci    kNo,
82cb93a386Sopenharmony_ci    kYes
83cb93a386Sopenharmony_ci};
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_cienum class ExpectMatch {
86cb93a386Sopenharmony_ci    kNo,
87cb93a386Sopenharmony_ci    kYes,
88cb93a386Sopenharmony_ci    kFlaky
89cb93a386Sopenharmony_ci};
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_civoid showOp(const SkPathOp op) {
92cb93a386Sopenharmony_ci    switch (op) {
93cb93a386Sopenharmony_ci        case kDifference_SkPathOp:
94cb93a386Sopenharmony_ci            SkDebugf("op difference\n");
95cb93a386Sopenharmony_ci            break;
96cb93a386Sopenharmony_ci        case kIntersect_SkPathOp:
97cb93a386Sopenharmony_ci            SkDebugf("op intersect\n");
98cb93a386Sopenharmony_ci            break;
99cb93a386Sopenharmony_ci        case kUnion_SkPathOp:
100cb93a386Sopenharmony_ci            SkDebugf("op union\n");
101cb93a386Sopenharmony_ci            break;
102cb93a386Sopenharmony_ci        case kXOR_SkPathOp:
103cb93a386Sopenharmony_ci            SkDebugf("op xor\n");
104cb93a386Sopenharmony_ci            break;
105cb93a386Sopenharmony_ci        case kReverseDifference_SkPathOp:
106cb93a386Sopenharmony_ci            SkDebugf("op reverse difference\n");
107cb93a386Sopenharmony_ci            break;
108cb93a386Sopenharmony_ci        default:
109cb93a386Sopenharmony_ci            SkASSERT(0);
110cb93a386Sopenharmony_ci    }
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ciconst int kBitWidth = 64;
114cb93a386Sopenharmony_ciconst int kBitHeight = 64;
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_cistatic void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
117cb93a386Sopenharmony_ci    SkRect larger = one.getBounds();
118cb93a386Sopenharmony_ci    larger.join(two.getBounds());
119cb93a386Sopenharmony_ci    SkScalar largerWidth = larger.width();
120cb93a386Sopenharmony_ci    if (largerWidth < 4) {
121cb93a386Sopenharmony_ci        largerWidth = 4;
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci    SkScalar largerHeight = larger.height();
124cb93a386Sopenharmony_ci    if (largerHeight < 4) {
125cb93a386Sopenharmony_ci        largerHeight = 4;
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci    SkScalar hScale = (kBitWidth - 2) / largerWidth;
128cb93a386Sopenharmony_ci    SkScalar vScale = (kBitHeight - 2) / largerHeight;
129cb93a386Sopenharmony_ci    scale.reset();
130cb93a386Sopenharmony_ci    scale.preScale(hScale, vScale);
131cb93a386Sopenharmony_ci    larger.fLeft *= hScale;
132cb93a386Sopenharmony_ci    larger.fRight *= hScale;
133cb93a386Sopenharmony_ci    larger.fTop *= vScale;
134cb93a386Sopenharmony_ci    larger.fBottom *= vScale;
135cb93a386Sopenharmony_ci    SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
136cb93a386Sopenharmony_ci            : 16000 < larger.fRight ? 16000 - larger.fRight : 0;
137cb93a386Sopenharmony_ci    SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
138cb93a386Sopenharmony_ci            : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
139cb93a386Sopenharmony_ci    scale.postTranslate(dx, dy);
140cb93a386Sopenharmony_ci}
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_cistatic int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPath& scaledTwo,
143cb93a386Sopenharmony_ci        int& error2x2) {
144cb93a386Sopenharmony_ci    if (bits.width() == 0) {
145cb93a386Sopenharmony_ci        bits.allocN32Pixels(kBitWidth * 2, kBitHeight);
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci    SkCanvas canvas(bits);
148cb93a386Sopenharmony_ci    canvas.drawColor(SK_ColorWHITE);
149cb93a386Sopenharmony_ci    SkPaint paint;
150cb93a386Sopenharmony_ci    canvas.save();
151cb93a386Sopenharmony_ci    const SkRect& bounds1 = scaledOne.getBounds();
152cb93a386Sopenharmony_ci    canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
153cb93a386Sopenharmony_ci    canvas.drawPath(scaledOne, paint);
154cb93a386Sopenharmony_ci    canvas.restore();
155cb93a386Sopenharmony_ci    canvas.save();
156cb93a386Sopenharmony_ci    canvas.translate(-bounds1.fLeft + 1 + kBitWidth, -bounds1.fTop + 1);
157cb93a386Sopenharmony_ci    canvas.drawPath(scaledTwo, paint);
158cb93a386Sopenharmony_ci    canvas.restore();
159cb93a386Sopenharmony_ci    int errors2 = 0;
160cb93a386Sopenharmony_ci    int errors = 0;
161cb93a386Sopenharmony_ci    for (int y = 0; y < kBitHeight - 1; ++y) {
162cb93a386Sopenharmony_ci        uint32_t* addr1 = bits.getAddr32(0, y);
163cb93a386Sopenharmony_ci        uint32_t* addr2 = bits.getAddr32(0, y + 1);
164cb93a386Sopenharmony_ci        uint32_t* addr3 = bits.getAddr32(kBitWidth, y);
165cb93a386Sopenharmony_ci        uint32_t* addr4 = bits.getAddr32(kBitWidth, y + 1);
166cb93a386Sopenharmony_ci        for (int x = 0; x < kBitWidth - 1; ++x) {
167cb93a386Sopenharmony_ci            // count 2x2 blocks
168cb93a386Sopenharmony_ci            bool err = addr1[x] != addr3[x];
169cb93a386Sopenharmony_ci            if (err) {
170cb93a386Sopenharmony_ci                errors2 += addr1[x + 1] != addr3[x + 1]
171cb93a386Sopenharmony_ci                        && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
172cb93a386Sopenharmony_ci                errors++;
173cb93a386Sopenharmony_ci            }
174cb93a386Sopenharmony_ci        }
175cb93a386Sopenharmony_ci    }
176cb93a386Sopenharmony_ci    error2x2 = errors2;
177cb93a386Sopenharmony_ci    return errors;
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cistatic int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits, SkPath& scaledOne,
181cb93a386Sopenharmony_ci        SkPath& scaledTwo, int& error2x2) {
182cb93a386Sopenharmony_ci    SkMatrix scale;
183cb93a386Sopenharmony_ci    scaleMatrix(one, two, scale);
184cb93a386Sopenharmony_ci    one.transform(scale, &scaledOne);
185cb93a386Sopenharmony_ci    two.transform(scale, &scaledTwo);
186cb93a386Sopenharmony_ci    return pathsDrawTheSame(bits, scaledOne, scaledTwo, error2x2);
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_cibool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) {
190cb93a386Sopenharmony_ci    if (!drawPaths) {
191cb93a386Sopenharmony_ci        return true;
192cb93a386Sopenharmony_ci    }
193cb93a386Sopenharmony_ci    const SkRect& bounds1 = one.getBounds();
194cb93a386Sopenharmony_ci    const SkRect& bounds2 = two.getBounds();
195cb93a386Sopenharmony_ci    SkRect larger = bounds1;
196cb93a386Sopenharmony_ci    larger.join(bounds2);
197cb93a386Sopenharmony_ci    SkBitmap bits;
198cb93a386Sopenharmony_ci    char out[256];
199cb93a386Sopenharmony_ci    int bitWidth = SkScalarCeilToInt(larger.width()) + 2;
200cb93a386Sopenharmony_ci    if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
201cb93a386Sopenharmony_ci        return false;
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci    int bitHeight = SkScalarCeilToInt(larger.height()) + 2;
204cb93a386Sopenharmony_ci    if (bitHeight >= (int) sizeof(out)) {
205cb93a386Sopenharmony_ci        return false;
206cb93a386Sopenharmony_ci    }
207cb93a386Sopenharmony_ci    bits.allocN32Pixels(bitWidth * 2, bitHeight);
208cb93a386Sopenharmony_ci    SkCanvas canvas(bits);
209cb93a386Sopenharmony_ci    canvas.drawColor(SK_ColorWHITE);
210cb93a386Sopenharmony_ci    SkPaint paint;
211cb93a386Sopenharmony_ci    canvas.save();
212cb93a386Sopenharmony_ci    canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
213cb93a386Sopenharmony_ci    canvas.drawPath(one, paint);
214cb93a386Sopenharmony_ci    canvas.restore();
215cb93a386Sopenharmony_ci    canvas.save();
216cb93a386Sopenharmony_ci    canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
217cb93a386Sopenharmony_ci    canvas.drawPath(two, paint);
218cb93a386Sopenharmony_ci    canvas.restore();
219cb93a386Sopenharmony_ci    for (int y = 0; y < bitHeight; ++y) {
220cb93a386Sopenharmony_ci        uint32_t* addr1 = bits.getAddr32(0, y);
221cb93a386Sopenharmony_ci        int x;
222cb93a386Sopenharmony_ci        char* outPtr = out;
223cb93a386Sopenharmony_ci        for (x = 0; x < bitWidth; ++x) {
224cb93a386Sopenharmony_ci            *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
225cb93a386Sopenharmony_ci        }
226cb93a386Sopenharmony_ci        *outPtr++ = '|';
227cb93a386Sopenharmony_ci        for (x = bitWidth; x < bitWidth * 2; ++x) {
228cb93a386Sopenharmony_ci            *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
229cb93a386Sopenharmony_ci        }
230cb93a386Sopenharmony_ci        *outPtr++ = '\0';
231cb93a386Sopenharmony_ci        SkDebugf("%s\n", out);
232cb93a386Sopenharmony_ci    }
233cb93a386Sopenharmony_ci    return true;
234cb93a386Sopenharmony_ci}
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ciint comparePaths(skiatest::Reporter* reporter, const char* filename, const SkPath& one,
237cb93a386Sopenharmony_ci        const SkPath& two, SkBitmap& bitmap) {
238cb93a386Sopenharmony_ci    int errors2x2;
239cb93a386Sopenharmony_ci    SkPath scaledOne, scaledTwo;
240cb93a386Sopenharmony_ci    (void) pathsDrawTheSame(one, two, bitmap, scaledOne, scaledTwo, errors2x2);
241cb93a386Sopenharmony_ci    if (errors2x2 == 0) {
242cb93a386Sopenharmony_ci        return 0;
243cb93a386Sopenharmony_ci    }
244cb93a386Sopenharmony_ci    const int MAX_ERRORS = 9;
245cb93a386Sopenharmony_ci    return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
246cb93a386Sopenharmony_ci}
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_cistatic SkTDArray<SkPathOp> gTestOp;
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_cistatic void showPathOpPath(const char* testName, const SkPath& one, const SkPath& two,
251cb93a386Sopenharmony_ci        const SkPath& a, const SkPath& b, const SkPath& scaledOne, const SkPath& scaledTwo,
252cb93a386Sopenharmony_ci        const SkPathOp shapeOp, const SkMatrix& scale) {
253cb93a386Sopenharmony_ci    SkASSERT((unsigned) shapeOp < SK_ARRAY_COUNT(opStrs));
254cb93a386Sopenharmony_ci    if (!testName) {
255cb93a386Sopenharmony_ci        testName = "xOp";
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci    SkDebugf("static void %s_%s(skiatest::Reporter* reporter, const char* filename) {\n",
258cb93a386Sopenharmony_ci        testName, opSuffixes[shapeOp]);
259cb93a386Sopenharmony_ci    *gTestOp.append() = shapeOp;
260cb93a386Sopenharmony_ci    SkDebugf("    SkPath path, pathB;\n");
261cb93a386Sopenharmony_ci    SkPathOpsDebug::ShowOnePath(a, "path", false);
262cb93a386Sopenharmony_ci    SkPathOpsDebug::ShowOnePath(b, "pathB", false);
263cb93a386Sopenharmony_ci    SkDebugf("    testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]);
264cb93a386Sopenharmony_ci    SkDebugf("}\n");
265cb93a386Sopenharmony_ci    drawAsciiPaths(scaledOne, scaledTwo, true);
266cb93a386Sopenharmony_ci}
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_cistatic int comparePaths(skiatest::Reporter* reporter, const char* testName, const SkPath& one,
269cb93a386Sopenharmony_ci        const SkPath& scaledOne, const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap,
270cb93a386Sopenharmony_ci        const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale,
271cb93a386Sopenharmony_ci        ExpectMatch expectMatch) {
272cb93a386Sopenharmony_ci    static SkMutex& compareDebugOut3 = *(new SkMutex);
273cb93a386Sopenharmony_ci    int errors2x2;
274cb93a386Sopenharmony_ci    const int MAX_ERRORS = 8;
275cb93a386Sopenharmony_ci    (void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
276cb93a386Sopenharmony_ci    if (ExpectMatch::kNo == expectMatch) {
277cb93a386Sopenharmony_ci        if (errors2x2 < MAX_ERRORS) {
278cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
279cb93a386Sopenharmony_ci        }
280cb93a386Sopenharmony_ci        return 0;
281cb93a386Sopenharmony_ci    }
282cb93a386Sopenharmony_ci    if (errors2x2 == 0) {
283cb93a386Sopenharmony_ci        return 0;
284cb93a386Sopenharmony_ci    }
285cb93a386Sopenharmony_ci    if (ExpectMatch::kYes == expectMatch && errors2x2 >= MAX_ERRORS) {
286cb93a386Sopenharmony_ci        SkAutoMutexExclusive autoM(compareDebugOut3);
287cb93a386Sopenharmony_ci        showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
288cb93a386Sopenharmony_ci        SkDebugf("\n/*");
289cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, 0);
290cb93a386Sopenharmony_ci        SkDebugf(" */\n");
291cb93a386Sopenharmony_ci    }
292cb93a386Sopenharmony_ci    return errors2x2 >= MAX_ERRORS ? errors2x2 : 0;
293cb93a386Sopenharmony_ci}
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci// Default values for when reporter->verbose() is false.
296cb93a386Sopenharmony_cistatic int sTestNumber = 55;
297cb93a386Sopenharmony_cistatic const char* sTestName = "pathOpTest";
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_cistatic void appendTestName(const char* nameSuffix, std::string& out) {
300cb93a386Sopenharmony_ci    out += sTestName;
301cb93a386Sopenharmony_ci    out += std_to_string(sTestNumber);
302cb93a386Sopenharmony_ci    ++sTestNumber;
303cb93a386Sopenharmony_ci    if (nameSuffix) {
304cb93a386Sopenharmony_ci        out.append(nameSuffix);
305cb93a386Sopenharmony_ci    }
306cb93a386Sopenharmony_ci}
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_cistatic void appendTest(const char* pathStr, const char* pathPrefix, const char* nameSuffix,
309cb93a386Sopenharmony_ci                       const char* testFunction, bool twoPaths, std::string& out) {
310cb93a386Sopenharmony_ci#if 0
311cb93a386Sopenharmony_ci    out.append("\n<div id=\"");
312cb93a386Sopenharmony_ci    appendTestName(nameSuffix, out);
313cb93a386Sopenharmony_ci    out.append("\">\n");
314cb93a386Sopenharmony_ci    if (pathPrefix) {
315cb93a386Sopenharmony_ci        out.append(pathPrefix);
316cb93a386Sopenharmony_ci    }
317cb93a386Sopenharmony_ci    out.append(pathStr);
318cb93a386Sopenharmony_ci    out.append("</div>\n\n");
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci    out.append(marker);
321cb93a386Sopenharmony_ci    out.append("    ");
322cb93a386Sopenharmony_ci    appendTestName(nameSuffix, out);
323cb93a386Sopenharmony_ci    out.append(",\n\n\n");
324cb93a386Sopenharmony_ci#endif
325cb93a386Sopenharmony_ci    out.append("static void ");
326cb93a386Sopenharmony_ci    appendTestName(nameSuffix, out);
327cb93a386Sopenharmony_ci    out.append("(skiatest::Reporter* reporter) {\n    SkPath path");
328cb93a386Sopenharmony_ci    if (twoPaths) {
329cb93a386Sopenharmony_ci        out.append(", pathB");
330cb93a386Sopenharmony_ci    }
331cb93a386Sopenharmony_ci    out.append(";\n");
332cb93a386Sopenharmony_ci    if (pathPrefix) {
333cb93a386Sopenharmony_ci        out.append(pathPrefix);
334cb93a386Sopenharmony_ci    }
335cb93a386Sopenharmony_ci    out += pathStr;
336cb93a386Sopenharmony_ci    out += "    ";
337cb93a386Sopenharmony_ci    out += testFunction;
338cb93a386Sopenharmony_ci#if 0
339cb93a386Sopenharmony_ci    out.append("static void (*firstTest)() = ");
340cb93a386Sopenharmony_ci    appendTestName(nameSuffix, out);
341cb93a386Sopenharmony_ci    out.append(";\n\n");
342cb93a386Sopenharmony_ci
343cb93a386Sopenharmony_ci    out.append("static struct {\n");
344cb93a386Sopenharmony_ci    out.append("    void (*fun)();\n");
345cb93a386Sopenharmony_ci    out.append("    const char* str;\n");
346cb93a386Sopenharmony_ci    out.append("} tests[] = {\n");
347cb93a386Sopenharmony_ci    out.append("    TEST(");
348cb93a386Sopenharmony_ci    appendTestName(nameSuffix, out);
349cb93a386Sopenharmony_ci    out.append("),\n");
350cb93a386Sopenharmony_ci#endif
351cb93a386Sopenharmony_ci}
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_civoid markTestFlakyForPathKit() {
354cb93a386Sopenharmony_ci    if (PathOpsDebug::gJson) {
355cb93a386Sopenharmony_ci        SkASSERT(!PathOpsDebug::gMarkJsonFlaky);
356cb93a386Sopenharmony_ci        PathOpsDebug::gMarkJsonFlaky = true;
357cb93a386Sopenharmony_ci    }
358cb93a386Sopenharmony_ci}
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_cibool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
361cb93a386Sopenharmony_ci                  const char* pathStr) {
362cb93a386Sopenharmony_ci    static SkMutex& simplifyDebugOut = *(new SkMutex);
363cb93a386Sopenharmony_ci    SkPathFillType fillType = useXor ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding;
364cb93a386Sopenharmony_ci    path.setFillType(fillType);
365cb93a386Sopenharmony_ci    state.fReporter->bumpTestCount();
366cb93a386Sopenharmony_ci    if (!Simplify(path, &out)) {
367cb93a386Sopenharmony_ci        SkDebugf("%s did not expect failure\n", __FUNCTION__);
368cb93a386Sopenharmony_ci        REPORTER_ASSERT(state.fReporter, 0);
369cb93a386Sopenharmony_ci        return false;
370cb93a386Sopenharmony_ci    }
371cb93a386Sopenharmony_ci    if (!state.fReporter->verbose()) {
372cb93a386Sopenharmony_ci        return true;
373cb93a386Sopenharmony_ci    }
374cb93a386Sopenharmony_ci    int result = comparePaths(state.fReporter, nullptr, path, out, *state.fBitmap);
375cb93a386Sopenharmony_ci    if (result) {
376cb93a386Sopenharmony_ci        SkAutoMutexExclusive autoM(simplifyDebugOut);
377cb93a386Sopenharmony_ci        std::string str;
378cb93a386Sopenharmony_ci        const char* pathPrefix = nullptr;
379cb93a386Sopenharmony_ci        const char* nameSuffix = nullptr;
380cb93a386Sopenharmony_ci        if (fillType == SkPathFillType::kEvenOdd) {
381cb93a386Sopenharmony_ci            pathPrefix = "    path.setFillType(SkPathFillType::kEvenOdd);\n";
382cb93a386Sopenharmony_ci            nameSuffix = "x";
383cb93a386Sopenharmony_ci        }
384cb93a386Sopenharmony_ci        const char testFunction[] = "testSimplify(reporter, path);";
385cb93a386Sopenharmony_ci        appendTest(pathStr, pathPrefix, nameSuffix, testFunction, false, str);
386cb93a386Sopenharmony_ci        SkDebugf("%s", str.c_str());
387cb93a386Sopenharmony_ci        REPORTER_ASSERT(state.fReporter, 0);
388cb93a386Sopenharmony_ci    }
389cb93a386Sopenharmony_ci    state.fReporter->bumpTestCount();
390cb93a386Sopenharmony_ci    return result == 0;
391cb93a386Sopenharmony_ci}
392cb93a386Sopenharmony_ci
393cb93a386Sopenharmony_cistatic void json_status(ExpectSuccess expectSuccess, ExpectMatch expectMatch, bool opSucceeded) {
394cb93a386Sopenharmony_ci    fprintf(PathOpsDebug::gOut, "  \"expectSuccess\": \"%s\",\n",
395cb93a386Sopenharmony_ci            ExpectSuccess::kNo == expectSuccess ? "no" :
396cb93a386Sopenharmony_ci            ExpectSuccess::kYes == expectSuccess ? "yes" : "flaky");
397cb93a386Sopenharmony_ci    if (PathOpsDebug::gMarkJsonFlaky) {
398cb93a386Sopenharmony_ci        expectMatch = ExpectMatch::kFlaky;
399cb93a386Sopenharmony_ci        PathOpsDebug::gMarkJsonFlaky = false;
400cb93a386Sopenharmony_ci    }
401cb93a386Sopenharmony_ci    fprintf(PathOpsDebug::gOut, "  \"expectMatch\": \"%s\",\n",
402cb93a386Sopenharmony_ci            ExpectMatch::kNo == expectMatch ? "no" :
403cb93a386Sopenharmony_ci            ExpectMatch::kYes == expectMatch ? "yes" : "flaky");
404cb93a386Sopenharmony_ci    fprintf(PathOpsDebug::gOut, "  \"succeeded\": %s,\n", opSucceeded ? "true" : "false");
405cb93a386Sopenharmony_ci}
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_cistatic void json_path_out(const SkPath& path, const char* pathName, const char* fillTypeName,
408cb93a386Sopenharmony_ci        bool lastField) {
409cb93a386Sopenharmony_ci    char const * const gFillTypeStrs[] = {
410cb93a386Sopenharmony_ci        "Winding",
411cb93a386Sopenharmony_ci        "EvenOdd",
412cb93a386Sopenharmony_ci        "InverseWinding",
413cb93a386Sopenharmony_ci        "InverseEvenOdd",
414cb93a386Sopenharmony_ci    };
415cb93a386Sopenharmony_ci    if (PathOpsDebug::gOutputSVG) {
416cb93a386Sopenharmony_ci        SkString svg;
417cb93a386Sopenharmony_ci        SkParsePath::ToSVGString(path, &svg);
418cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "  \"%s\": \"%s\",\n", pathName, svg.c_str());
419cb93a386Sopenharmony_ci    } else {
420cb93a386Sopenharmony_ci                                 // MOVE, LINE, QUAD, CONIC, CUBIC, CLOSE
421cb93a386Sopenharmony_ci        const int verbConst[] =  {     0,    1,    2,     3,     4,     5 };
422cb93a386Sopenharmony_ci        const int pointIndex[] = {     0,    1,    1,     1,     1,     0 };
423cb93a386Sopenharmony_ci        const int pointCount[] = {     1,    2,    3,     3,     4,     0 };
424cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "  \"%s\": [", pathName);
425cb93a386Sopenharmony_ci        bool first = true;
426cb93a386Sopenharmony_ci        for (auto [verb, points, w] : SkPathPriv::Iterate(path)) {
427cb93a386Sopenharmony_ci            if (first) {
428cb93a386Sopenharmony_ci                first = false;
429cb93a386Sopenharmony_ci            } else {
430cb93a386Sopenharmony_ci                fprintf(PathOpsDebug::gOut, ",\n    ");
431cb93a386Sopenharmony_ci            }
432cb93a386Sopenharmony_ci            int verbIndex = (int) verb;
433cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, "[%d", verbConst[verbIndex]);
434cb93a386Sopenharmony_ci            for (int i = pointIndex[verbIndex]; i < pointCount[verbIndex]; ++i) {
435cb93a386Sopenharmony_ci                fprintf(PathOpsDebug::gOut, ", \"0x%08x\", \"0x%08x\"",
436cb93a386Sopenharmony_ci                        SkFloat2Bits(points[i].fX), SkFloat2Bits(points[i].fY));
437cb93a386Sopenharmony_ci            }
438cb93a386Sopenharmony_ci            if (SkPathVerb::kConic == verb) {
439cb93a386Sopenharmony_ci                fprintf(PathOpsDebug::gOut, ", \"0x%08x\"", SkFloat2Bits(*w));
440cb93a386Sopenharmony_ci            }
441cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, "]");
442cb93a386Sopenharmony_ci        }
443cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "],\n");
444cb93a386Sopenharmony_ci    }
445cb93a386Sopenharmony_ci    fprintf(PathOpsDebug::gOut, "  \"fillType%s\": \"k%s_FillType\"%s", fillTypeName,
446cb93a386Sopenharmony_ci            gFillTypeStrs[(int) path.getFillType()], lastField ? "\n}" : ",\n");
447cb93a386Sopenharmony_ci}
448cb93a386Sopenharmony_ci
449cb93a386Sopenharmony_cistatic bool check_for_duplicate_names(const char* testName) {
450cb93a386Sopenharmony_ci    if (PathOpsDebug::gCheckForDuplicateNames) {
451cb93a386Sopenharmony_ci        if (gUniqueNames.end() != std::find(gUniqueNames.begin(), gUniqueNames.end(),
452cb93a386Sopenharmony_ci                std::string(testName))) {
453cb93a386Sopenharmony_ci            SkDebugf("%s", "");  // convenience for setting breakpoints
454cb93a386Sopenharmony_ci        }
455cb93a386Sopenharmony_ci        gUniqueNames.push_back(std::string(testName));
456cb93a386Sopenharmony_ci        return true;
457cb93a386Sopenharmony_ci    }
458cb93a386Sopenharmony_ci    return false;
459cb93a386Sopenharmony_ci}
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_cistatic bool inner_simplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename,
462cb93a386Sopenharmony_ci        ExpectSuccess expectSuccess, SkipAssert skipAssert, ExpectMatch expectMatch) {
463cb93a386Sopenharmony_ci    if (PathOpsDebug::gJson) {
464cb93a386Sopenharmony_ci        if (check_for_duplicate_names(filename)) {
465cb93a386Sopenharmony_ci            return true;
466cb93a386Sopenharmony_ci        }
467cb93a386Sopenharmony_ci        if (!PathOpsDebug::gOutFirst) {
468cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, ",\n");
469cb93a386Sopenharmony_ci        }
470cb93a386Sopenharmony_ci        PathOpsDebug::gOutFirst = false;
471cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "\"%s\": {\n", filename);
472cb93a386Sopenharmony_ci        json_path_out(path, "path", "", false);
473cb93a386Sopenharmony_ci    }
474cb93a386Sopenharmony_ci    SkPath out;
475cb93a386Sopenharmony_ci    if (!SimplifyDebug(path, &out  SkDEBUGPARAMS(SkipAssert::kYes == skipAssert)
476cb93a386Sopenharmony_ci            SkDEBUGPARAMS(sTestName))) {
477cb93a386Sopenharmony_ci        if (ExpectSuccess::kYes == expectSuccess) {
478cb93a386Sopenharmony_ci            SkDebugf("%s did not expect %s failure\n", __FUNCTION__, filename);
479cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
480cb93a386Sopenharmony_ci        }
481cb93a386Sopenharmony_ci        if (PathOpsDebug::gJson) {
482cb93a386Sopenharmony_ci            json_status(expectSuccess, expectMatch, false);
483cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, "  \"out\": \"\"\n}");
484cb93a386Sopenharmony_ci        }
485cb93a386Sopenharmony_ci        return false;
486cb93a386Sopenharmony_ci    } else {
487cb93a386Sopenharmony_ci        if (ExpectSuccess::kNo == expectSuccess) {
488cb93a386Sopenharmony_ci            SkDebugf("%s %s unexpected success\n", __FUNCTION__, filename);
489cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
490cb93a386Sopenharmony_ci        }
491cb93a386Sopenharmony_ci        if (PathOpsDebug::gJson) {
492cb93a386Sopenharmony_ci            json_status(expectSuccess, expectMatch, true);
493cb93a386Sopenharmony_ci            json_path_out(out, "out", "Out", true);
494cb93a386Sopenharmony_ci        }
495cb93a386Sopenharmony_ci    }
496cb93a386Sopenharmony_ci    SkBitmap bitmap;
497cb93a386Sopenharmony_ci    int errors = comparePaths(reporter, filename, path, out, bitmap);
498cb93a386Sopenharmony_ci    if (ExpectMatch::kNo == expectMatch) {
499cb93a386Sopenharmony_ci        if (!errors) {
500cb93a386Sopenharmony_ci            SkDebugf("%s failing test %s now succeeds\n", __FUNCTION__, filename);
501cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
502cb93a386Sopenharmony_ci            return false;
503cb93a386Sopenharmony_ci        }
504cb93a386Sopenharmony_ci    } else if (ExpectMatch::kYes == expectMatch && errors) {
505cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, 0);
506cb93a386Sopenharmony_ci    }
507cb93a386Sopenharmony_ci    reporter->bumpTestCount();
508cb93a386Sopenharmony_ci    return errors == 0;
509cb93a386Sopenharmony_ci}
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_cibool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
512cb93a386Sopenharmony_ci    return inner_simplify(reporter, path, filename, ExpectSuccess::kYes, SkipAssert::kNo,
513cb93a386Sopenharmony_ci            ExpectMatch::kYes);
514cb93a386Sopenharmony_ci}
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_cibool testSimplifyFuzz(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
517cb93a386Sopenharmony_ci    return inner_simplify(reporter, path, filename, ExpectSuccess::kFlaky, SkipAssert::kYes,
518cb93a386Sopenharmony_ci            ExpectMatch::kFlaky);
519cb93a386Sopenharmony_ci}
520cb93a386Sopenharmony_ci
521cb93a386Sopenharmony_cibool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path, const char* filename,
522cb93a386Sopenharmony_ci        bool checkFail) {
523cb93a386Sopenharmony_ci    return inner_simplify(reporter, path, filename, checkFail ?
524cb93a386Sopenharmony_ci            ExpectSuccess::kYes : ExpectSuccess::kNo, SkipAssert::kNo, ExpectMatch::kNo);
525cb93a386Sopenharmony_ci}
526cb93a386Sopenharmony_ci
527cb93a386Sopenharmony_cibool testSimplifyFail(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
528cb93a386Sopenharmony_ci    return inner_simplify(reporter, path, filename,
529cb93a386Sopenharmony_ci            ExpectSuccess::kNo, SkipAssert::kYes, ExpectMatch::kNo);
530cb93a386Sopenharmony_ci}
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_cistatic bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
533cb93a386Sopenharmony_ci        const SkPathOp shapeOp, const char* testName, ExpectSuccess expectSuccess,
534cb93a386Sopenharmony_ci        SkipAssert skipAssert, ExpectMatch expectMatch) {
535cb93a386Sopenharmony_ci    if (PathOpsDebug::gJson) {
536cb93a386Sopenharmony_ci        if (check_for_duplicate_names(testName)) {
537cb93a386Sopenharmony_ci            return true;
538cb93a386Sopenharmony_ci        }
539cb93a386Sopenharmony_ci        if (!PathOpsDebug::gOutFirst) {
540cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, ",\n");
541cb93a386Sopenharmony_ci        }
542cb93a386Sopenharmony_ci        PathOpsDebug::gOutFirst = false;
543cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "\"%s\": {\n", testName);
544cb93a386Sopenharmony_ci        json_path_out(a, "p1", "1", false);
545cb93a386Sopenharmony_ci        json_path_out(b, "p2", "2", false);
546cb93a386Sopenharmony_ci        fprintf(PathOpsDebug::gOut, "  \"op\": \"%s\",\n", opStrs[shapeOp]);
547cb93a386Sopenharmony_ci    }
548cb93a386Sopenharmony_ci    SkPath out;
549cb93a386Sopenharmony_ci    if (!OpDebug(a, b, shapeOp, &out  SkDEBUGPARAMS(SkipAssert::kYes == skipAssert)
550cb93a386Sopenharmony_ci            SkDEBUGPARAMS(testName))) {
551cb93a386Sopenharmony_ci        if (ExpectSuccess::kYes == expectSuccess) {
552cb93a386Sopenharmony_ci            SkDebugf("%s %s did not expect failure\n", __FUNCTION__, testName);
553cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
554cb93a386Sopenharmony_ci        }
555cb93a386Sopenharmony_ci        if (PathOpsDebug::gJson) {
556cb93a386Sopenharmony_ci            json_status(expectSuccess, expectMatch, false);
557cb93a386Sopenharmony_ci            fprintf(PathOpsDebug::gOut, "  \"out\": \"\"\n}");
558cb93a386Sopenharmony_ci        }
559cb93a386Sopenharmony_ci        return false;
560cb93a386Sopenharmony_ci    } else {
561cb93a386Sopenharmony_ci        if (ExpectSuccess::kNo == expectSuccess) {
562cb93a386Sopenharmony_ci                SkDebugf("%s %s unexpected success\n", __FUNCTION__, testName);
563cb93a386Sopenharmony_ci                REPORTER_ASSERT(reporter, 0);
564cb93a386Sopenharmony_ci        }
565cb93a386Sopenharmony_ci        if (PathOpsDebug::gJson) {
566cb93a386Sopenharmony_ci            json_status(expectSuccess, expectMatch, true);
567cb93a386Sopenharmony_ci            json_path_out(out, "out", "Out", true);
568cb93a386Sopenharmony_ci        }
569cb93a386Sopenharmony_ci    }
570cb93a386Sopenharmony_ci    if (!reporter->verbose()) {
571cb93a386Sopenharmony_ci        return true;
572cb93a386Sopenharmony_ci    }
573cb93a386Sopenharmony_ci    SkPath pathOut, scaledPathOut;
574cb93a386Sopenharmony_ci    SkRegion rgnA, rgnB, openClip, rgnOut;
575cb93a386Sopenharmony_ci    openClip.setRect({-16000, -16000, 16000, 16000});
576cb93a386Sopenharmony_ci    rgnA.setPath(a, openClip);
577cb93a386Sopenharmony_ci    rgnB.setPath(b, openClip);
578cb93a386Sopenharmony_ci    rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
579cb93a386Sopenharmony_ci    rgnOut.getBoundaryPath(&pathOut);
580cb93a386Sopenharmony_ci
581cb93a386Sopenharmony_ci    SkMatrix scale;
582cb93a386Sopenharmony_ci    scaleMatrix(a, b, scale);
583cb93a386Sopenharmony_ci    SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
584cb93a386Sopenharmony_ci    SkPath scaledA, scaledB;
585cb93a386Sopenharmony_ci    scaledA.addPath(a, scale);
586cb93a386Sopenharmony_ci    scaledA.setFillType(a.getFillType());
587cb93a386Sopenharmony_ci    scaledB.addPath(b, scale);
588cb93a386Sopenharmony_ci    scaledB.setFillType(b.getFillType());
589cb93a386Sopenharmony_ci    scaledRgnA.setPath(scaledA, openClip);
590cb93a386Sopenharmony_ci    scaledRgnB.setPath(scaledB, openClip);
591cb93a386Sopenharmony_ci    scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
592cb93a386Sopenharmony_ci    scaledRgnOut.getBoundaryPath(&scaledPathOut);
593cb93a386Sopenharmony_ci    SkBitmap bitmap;
594cb93a386Sopenharmony_ci    SkPath scaledOut;
595cb93a386Sopenharmony_ci    scaledOut.addPath(out, scale);
596cb93a386Sopenharmony_ci    scaledOut.setFillType(out.getFillType());
597cb93a386Sopenharmony_ci    int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
598cb93a386Sopenharmony_ci            a, b, shapeOp, scale, expectMatch);
599cb93a386Sopenharmony_ci    reporter->bumpTestCount();
600cb93a386Sopenharmony_ci    return result == 0;
601cb93a386Sopenharmony_ci}
602cb93a386Sopenharmony_ci
603cb93a386Sopenharmony_cibool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
604cb93a386Sopenharmony_ci        const SkPathOp shapeOp, const char* testName) {
605cb93a386Sopenharmony_ci    return innerPathOp(reporter, a, b, shapeOp, testName, ExpectSuccess::kYes, SkipAssert::kNo,
606cb93a386Sopenharmony_ci            ExpectMatch::kYes);
607cb93a386Sopenharmony_ci}
608cb93a386Sopenharmony_ci
609cb93a386Sopenharmony_cibool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
610cb93a386Sopenharmony_ci        const SkPathOp shapeOp, const char* testName, bool checkFail) {
611cb93a386Sopenharmony_ci    return innerPathOp(reporter, a, b, shapeOp, testName, checkFail ?
612cb93a386Sopenharmony_ci            ExpectSuccess::kYes : ExpectSuccess::kNo, SkipAssert::kNo, ExpectMatch::kNo);
613cb93a386Sopenharmony_ci}
614cb93a386Sopenharmony_ci
615cb93a386Sopenharmony_cibool testPathOpFuzz(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
616cb93a386Sopenharmony_ci        const SkPathOp shapeOp, const char* testName) {
617cb93a386Sopenharmony_ci    return innerPathOp(reporter, a, b, shapeOp, testName, ExpectSuccess::kFlaky, SkipAssert::kYes,
618cb93a386Sopenharmony_ci            ExpectMatch::kFlaky);
619cb93a386Sopenharmony_ci}
620cb93a386Sopenharmony_ci
621cb93a386Sopenharmony_cibool testPathOpFail(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
622cb93a386Sopenharmony_ci                 const SkPathOp shapeOp, const char* testName) {
623cb93a386Sopenharmony_ci    SkPath orig;
624cb93a386Sopenharmony_ci    orig.lineTo(54, 43);
625cb93a386Sopenharmony_ci    SkPath out = orig;
626cb93a386Sopenharmony_ci    if (Op(a, b, shapeOp, &out) ) {
627cb93a386Sopenharmony_ci        SkDebugf("%s test is expected to fail\n", __FUNCTION__);
628cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, 0);
629cb93a386Sopenharmony_ci        return false;
630cb93a386Sopenharmony_ci    }
631cb93a386Sopenharmony_ci    SkASSERT(out == orig);
632cb93a386Sopenharmony_ci    return true;
633cb93a386Sopenharmony_ci}
634cb93a386Sopenharmony_ci
635cb93a386Sopenharmony_civoid initializeTests(skiatest::Reporter* reporter, const char* test) {
636cb93a386Sopenharmony_ci    static SkMutex& mu = *(new SkMutex);
637cb93a386Sopenharmony_ci    if (reporter->verbose()) {
638cb93a386Sopenharmony_ci        SkAutoMutexExclusive lock(mu);
639cb93a386Sopenharmony_ci        sTestName = test;
640cb93a386Sopenharmony_ci        size_t testNameSize = strlen(test);
641cb93a386Sopenharmony_ci        SkFILEStream inFile("../../experimental/Intersection/op.htm");
642cb93a386Sopenharmony_ci        if (inFile.isValid()) {
643cb93a386Sopenharmony_ci            SkTDArray<char> inData;
644cb93a386Sopenharmony_ci            inData.setCount((int) inFile.getLength());
645cb93a386Sopenharmony_ci            size_t inLen = inData.count();
646cb93a386Sopenharmony_ci            inFile.read(inData.begin(), inLen);
647cb93a386Sopenharmony_ci            inFile.close();
648cb93a386Sopenharmony_ci            char* insert = strstr(inData.begin(), marker);
649cb93a386Sopenharmony_ci            if (insert) {
650cb93a386Sopenharmony_ci                insert += sizeof(marker) - 1;
651cb93a386Sopenharmony_ci                const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1;
652cb93a386Sopenharmony_ci                sTestNumber = atoi(numLoc) + 1;
653cb93a386Sopenharmony_ci            }
654cb93a386Sopenharmony_ci        }
655cb93a386Sopenharmony_ci    }
656cb93a386Sopenharmony_ci}
657cb93a386Sopenharmony_ci
658cb93a386Sopenharmony_civoid PathOpsThreadState::outputProgress(const char* pathStr, SkPathFillType pathFillType) {
659cb93a386Sopenharmony_ci    const char testFunction[] = "testSimplify(path);";
660cb93a386Sopenharmony_ci    const char* pathPrefix = nullptr;
661cb93a386Sopenharmony_ci    const char* nameSuffix = nullptr;
662cb93a386Sopenharmony_ci    if (pathFillType == SkPathFillType::kEvenOdd) {
663cb93a386Sopenharmony_ci        pathPrefix = "    path.setFillType(SkPathFillType::kEvenOdd);\n";
664cb93a386Sopenharmony_ci        nameSuffix = "x";
665cb93a386Sopenharmony_ci    }
666cb93a386Sopenharmony_ci    appendTest(pathStr, pathPrefix, nameSuffix, testFunction, false, fPathStr);
667cb93a386Sopenharmony_ci}
668cb93a386Sopenharmony_ci
669cb93a386Sopenharmony_civoid PathOpsThreadState::outputProgress(const char* pathStr, SkPathOp op) {
670cb93a386Sopenharmony_ci    const char testFunction[] = "testOp(path);";
671cb93a386Sopenharmony_ci    SkASSERT((size_t) op < SK_ARRAY_COUNT(opSuffixes));
672cb93a386Sopenharmony_ci    const char* nameSuffix = opSuffixes[op];
673cb93a386Sopenharmony_ci    appendTest(pathStr, nullptr, nameSuffix, testFunction, true, fPathStr);
674cb93a386Sopenharmony_ci}
675cb93a386Sopenharmony_ci
676cb93a386Sopenharmony_civoid RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
677cb93a386Sopenharmony_ci                void (*firstTest)(skiatest::Reporter* , const char* filename),
678cb93a386Sopenharmony_ci                void (*skipTest)(skiatest::Reporter* , const char* filename),
679cb93a386Sopenharmony_ci                void (*stopTest)(skiatest::Reporter* , const char* filename), bool reverse) {
680cb93a386Sopenharmony_ci    size_t index;
681cb93a386Sopenharmony_ci    if (firstTest) {
682cb93a386Sopenharmony_ci        index = count - 1;
683cb93a386Sopenharmony_ci        while (index > 0 && tests[index].fun != firstTest) {
684cb93a386Sopenharmony_ci            --index;
685cb93a386Sopenharmony_ci        }
686cb93a386Sopenharmony_ci        (*tests[index].fun)(reporter, tests[index].str);
687cb93a386Sopenharmony_ci        if (tests[index].fun == stopTest) {
688cb93a386Sopenharmony_ci            return;
689cb93a386Sopenharmony_ci        }
690cb93a386Sopenharmony_ci    }
691cb93a386Sopenharmony_ci    index = reverse ? count - 1 : 0;
692cb93a386Sopenharmony_ci    size_t last = reverse ? 0 : count - 1;
693cb93a386Sopenharmony_ci    bool foundSkip = !skipTest;
694cb93a386Sopenharmony_ci    do {
695cb93a386Sopenharmony_ci        if (tests[index].fun == skipTest) {
696cb93a386Sopenharmony_ci            foundSkip = true;
697cb93a386Sopenharmony_ci        }
698cb93a386Sopenharmony_ci        if (foundSkip && tests[index].fun != firstTest) {
699cb93a386Sopenharmony_ci             (*tests[index].fun)(reporter, tests[index].str);
700cb93a386Sopenharmony_ci        }
701cb93a386Sopenharmony_ci        if (tests[index].fun == stopTest || index == last) {
702cb93a386Sopenharmony_ci            break;
703cb93a386Sopenharmony_ci        }
704cb93a386Sopenharmony_ci        index += reverse ? -1 : 1;
705cb93a386Sopenharmony_ci    } while (true);
706cb93a386Sopenharmony_ci}
707