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