Flutter Engine
The Flutter Engine
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);
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
373 }
374}
375
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\"",
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;
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) {
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)
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) {
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) {
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
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
static const int points[]
static void(* stopTest)(skiatest::Reporter *, const char *filename)
static void(* firstTest)(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
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
@ kNo
Don't pre-clip the geometry before applying the (perspective) matrix.
#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
int find(T *array, int N, T item)
static FILE * gOut
Definition: PathOpsDebug.h:20
static bool gCheckForDuplicateNames
Definition: PathOpsDebug.h:18
static bool gOutputSVG
Definition: PathOpsDebug.h:19
static bool gJson
Definition: PathOpsDebug.h:15
static bool gMarkJsonFlaky
Definition: PathOpsDebug.h:16
static bool gOutFirst
Definition: PathOpsDebug.h:17
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition: SkCanvas.h:1182
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
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
void close()
Definition: SkStream.cpp:198
static SkString ToSVGString(const SkPath &, PathEncoding=PathEncoding::Absolute)
static void ShowOnePath(const SkPath &path, const char *name, bool includeDeclaration)
Definition: SkPath.h:59
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
SkPath & addPath(const SkPath &src, SkScalar dx, SkScalar dy, AddPathMode mode=kAppend_AddPathMode)
Definition: SkPath.cpp:1506
const SkRect & getBounds() const
Definition: SkPath.cpp:430
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkPath.cpp:1711
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
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
AtkStateType state
uint8_t value
GAsyncResult * result
double y
double x
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
Definition: bitmap.py:1
static int testFunction(int x)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkScalar w
#define T
Definition: precompiler.cc:65
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