diff options
author | caryclark <caryclark@google.com> | 2015-10-16 09:03:38 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-16 09:03:38 -0700 |
commit | 26ad22ab61539e3d3b6bc5e0da8dcebbd52a53de (patch) | |
tree | c2deb3596ffaa9aa5d8ebaf975ae71ef8e97e86a /tests | |
parent | 1a1d0b8d07d1d1cc2e56bb4790ff62179ba0c74c (diff) |
Enabling clip stack flattening exercises path ops.
Iterating through the 903K skps that represent the
imagable 1M top web pages triggers a number of
bugs, some of which are addressed here.
Some web pages trigger intersecting cubic
representations of arc with their conic
counterparts. This exposed a flaw in coincident
detection that caused an infinite loop. The loop
alternatively extended the coincident section and,
determining the that the bounds of the curve pairs
did not overlap, deleted the extension.
Track the number of times the coincident detection
is called, and if it exceeds an empirically found
limit, assume that the curves are coincident and
force it to be so.
The loop count limit can be determined by enabling
DEBUG_T_SECT_LOOP_COUNT and running all tests. The
largest count is reported on completion.
Another class of bugs was caused by concident
detection duplicating nearly identical points that
had been merged earlier. To track these bugs, the
'handle coincidence' code was duplicated as a
const debug variety that reported if one of a
dozen or so irregularities are present; then it is
easier to see when a block of code that fixes one
irregularity regresses another.
Creating the debug const code version exposed some
non-debug code that could be const, and some that
was experimental and could be removed. Set
DEBUG_COINCIDENCE to track coincidence health and
handling.
For running on Chrome, DEBUG_VERIFY checks the
result of pathops against the same operation
using SkRegion to verify that the results are
nearly the same.
When visualizing the pathops work using
tools/pathops_visualizer.htm, set
DEBUG_DUMP_ALIGNMENT to see the curves after
they've been aligned for coincidence.
Other bugs fixed include detecting when a
section of a pair of curves have devolved into
lines and are coincident.
TBR=reed@google.com
Review URL: https://codereview.chromium.org/1394503003
Diffstat (limited to 'tests')
-rw-r--r-- | tests/PathOpsCubicConicIntersectionTest.cpp | 73 | ||||
-rw-r--r-- | tests/PathOpsCubicIntersectionTest.cpp | 17 | ||||
-rwxr-xr-x | tests/PathOpsDebug.cpp | 95 | ||||
-rw-r--r-- | tests/PathOpsExtendedTest.cpp | 11 | ||||
-rw-r--r-- | tests/PathOpsOpTest.cpp | 4 | ||||
-rw-r--r-- | tests/PathOpsSimplifyTest.cpp | 31 | ||||
-rwxr-xr-x | tests/PathOpsSkpTest.cpp | 221 | ||||
-rw-r--r-- | tests/PathOpsTSectDebug.h | 20 | ||||
-rw-r--r-- | tests/PathOpsTestCommon.h | 2 | ||||
-rw-r--r-- | tests/skia_test.cpp | 4 |
10 files changed, 448 insertions, 30 deletions
diff --git a/tests/PathOpsCubicConicIntersectionTest.cpp b/tests/PathOpsCubicConicIntersectionTest.cpp new file mode 100644 index 0000000000..fae1233a55 --- /dev/null +++ b/tests/PathOpsCubicConicIntersectionTest.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "PathOpsTestCommon.h" +#include "SkIntersections.h" +#include "SkPathOpsConic.h" +#include "SkPathOpsCubic.h" +#include "SkReduceOrder.h" +#include "Test.h" + +static struct cubicConic { + SkDCubic cubic; + SkDConic conic; +} cubicConicTests[] = { + {{{{188.60000610351562, 2041.5999755859375}, {188.60000610351562, 2065.39990234375}, + {208, 2084.800048828125}, {231.80000305175781, 2084.800048828125}}}, + {{{{231.80000305175781, 2084.800048828125}, {188.60000610351562, 2084.800048828125}, + {188.60000610351562, 2041.5999755859375}}}, 0.707107008f}}, + + {{{{231.80000305175781, 2084.800048828125}, {255.60000610351562, 2084.800048828125}, + {275, 2065.39990234375}, {275, 2041.5999755859375}}}, + {{{{275, 2041.5999755859375}, {275, 2084.800048828125}, + {231.80000305175781, 2084.800048828125}}}, 0.707107008f}}, +}; + +static const int cubicConicTests_count = (int) SK_ARRAY_COUNT(cubicConicTests); + +static void cubicConicIntersection(skiatest::Reporter* reporter, int index) { + const SkDCubic& cubic = cubicConicTests[index].cubic; + SkASSERT(ValidCubic(cubic)); + const SkDConic& conic = cubicConicTests[index].conic; + SkASSERT(ValidConic(conic)); + SkReduceOrder reduce1; + SkReduceOrder reduce2; + int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics); + int order2 = reduce2.reduce(conic.fPts); + if (order1 != 4) { + SkDebugf("[%d] cubic order=%d\n", index, order1); + REPORTER_ASSERT(reporter, 0); + } + if (order2 != 3) { + SkDebugf("[%d] conic order=%d\n", index, order2); + REPORTER_ASSERT(reporter, 0); + } + SkIntersections i; + int roots = i.intersect(cubic, conic); + for (int pt = 0; pt < roots; ++pt) { + double tt1 = i[0][pt]; + SkDPoint xy1 = cubic.ptAtT(tt1); + double tt2 = i[1][pt]; + SkDPoint xy2 = conic.ptAtT(tt2); + if (!xy1.approximatelyEqual(xy2)) { + SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n", + __FUNCTION__, index, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY); + } + REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2)); + } + reporter->bumpTestCount(); +} + +DEF_TEST(PathOpsCubicConicIntersection, reporter) { + for (int index = 0; index < cubicConicTests_count; ++index) { + cubicConicIntersection(reporter, index); + reporter->bumpTestCount(); + } +} + +DEF_TEST(PathOpsCubicConicIntersectionOneOff, reporter) { + cubicConicIntersection(reporter, 1); +} diff --git a/tests/PathOpsCubicIntersectionTest.cpp b/tests/PathOpsCubicIntersectionTest.cpp index 6186ec8170..dd7a7f7e2f 100644 --- a/tests/PathOpsCubicIntersectionTest.cpp +++ b/tests/PathOpsCubicIntersectionTest.cpp @@ -437,6 +437,12 @@ static void newOneOff(skiatest::Reporter* reporter, int outer, int inner) { oneOff(reporter, cubic1, cubic2, false); } +static void testsOneOff(skiatest::Reporter* reporter, int index) { + const SkDCubic& cubic1 = tests[index][0]; + const SkDCubic& cubic2 = tests[index][1]; + oneOff(reporter, cubic1, cubic2, false); +} + static void oneOffTests(skiatest::Reporter* reporter) { for (int outer = 0; outer < testSetCount - 1; ++outer) { for (int inner = outer + 1; inner < testSetCount; ++inner) { @@ -654,6 +660,11 @@ static void cubicIntersectionSelfTest(skiatest::Reporter* reporter) { } static const SkDCubic coinSet[] = { + {{{72.350448608398438, 27.966041564941406}, {72.58441162109375, 27.861515045166016}, + {72.818222045898437, 27.756658554077148}, {73.394996643066406, 27.49799919128418}}}, + {{{73.394996643066406, 27.49799919128418}, {72.818222045898437, 27.756658554077148}, + {72.58441162109375, 27.861515045166016}, {72.350448608398438, 27.966041564941406}}}, + {{{297.04998779296875, 43.928997039794922}, {297.04998779296875, 43.928997039794922}, {300.69699096679688, 45.391998291015625}, {306.92498779296875, 43.08599853515625}}}, {{{297.04998779296875, 43.928997039794922}, {297.04998779296875, 43.928997039794922}, @@ -687,7 +698,11 @@ DEF_TEST(PathOpsCubicCoinOneOff, reporter) { } DEF_TEST(PathOpsCubicIntersectionOneOff, reporter) { - newOneOff(reporter, 0, 1); + newOneOff(reporter, 66, 70); +} + +DEF_TEST(PathOpsCubicIntersectionTestsOneOff, reporter) { + testsOneOff(reporter, 10); } DEF_TEST(PathOpsCubicSelfOneOff, reporter) { diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp index 263c37b120..0f96ef4f88 100755 --- a/tests/PathOpsDebug.cpp +++ b/tests/PathOpsDebug.cpp @@ -61,14 +61,9 @@ void SkDConic::dumpID(int id) const { } void SkDConic::dumpInner() const { - SkDebugf("{{"); - int index = 0; - do { - fPts[index].dump(); - SkDebugf(", "); - } while (++index < 2); - fPts[index].dump(); - SkDebugf("}, %1.9g", fWeight); + SkDebugf("{"); + fPts.dumpInner(); + SkDebugf("}}, %1.9gf", fWeight); } void SkDCubic::dump() const { @@ -674,6 +669,60 @@ void DontCallDumpTSpan() { // exists to instantiate the templates } template <typename TCurve, typename OppCurve> +void DumpAll(const SkTSpan<TCurve, OppCurve>* span) { + span->dumpAll(); +} + +void DontCallDumpSpanAll(); +void DontCallDumpSpanAll() { // exists to instantiate the templates + SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit(); + SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit(); + SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit(); + SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit(); + SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit(); + SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit(); + SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit(); + SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit(); + SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit(); + DumpAll(&q1q2); + DumpAll(&q1k2); + DumpAll(&q1c2); + DumpAll(&k1q2); + DumpAll(&k1k2); + DumpAll(&k1c2); + DumpAll(&c1q2); + DumpAll(&c1k2); + DumpAll(&c1c2); +} + +template <typename TCurve, typename OppCurve> +void DumpBounded(const SkTSpan<TCurve, OppCurve>* span) { + span->dumpBounded(0); +} + +void DontCallDumpSpanBounded(); +void DontCallDumpSpanBounded() { // exists to instantiate the templates + SkTSpan<SkDQuad, SkDQuad> q1q2; q1q2.debugInit(); + SkTSpan<SkDQuad, SkDConic> q1k2; q1k2.debugInit(); + SkTSpan<SkDQuad, SkDCubic> q1c2; q1c2.debugInit(); + SkTSpan<SkDConic, SkDQuad> k1q2; k1q2.debugInit(); + SkTSpan<SkDConic, SkDConic> k1k2; k1k2.debugInit(); + SkTSpan<SkDConic, SkDCubic> k1c2; k1c2.debugInit(); + SkTSpan<SkDCubic, SkDQuad> c1q2; c1q2.debugInit(); + SkTSpan<SkDCubic, SkDConic> c1k2; c1k2.debugInit(); + SkTSpan<SkDCubic, SkDCubic> c1c2; c1c2.debugInit(); + DumpBounded(&q1q2); + DumpBounded(&q1k2); + DumpBounded(&q1c2); + DumpBounded(&k1q2); + DumpBounded(&k1k2); + DumpBounded(&k1c2); + DumpBounded(&c1q2); + DumpBounded(&c1k2); + DumpBounded(&c1c2); +} + +template <typename TCurve, typename OppCurve> void DumpCoin(const SkTSpan<TCurve, OppCurve>* span) { span->dumpCoin(); } @@ -1085,9 +1134,9 @@ void SkOpSegment::dumpCoin() const { } while ((span = span->next()->upCastable())); } -void SkOpSegment::dumpPtsInner() const { +void SkOpSegment::dumpPtsInner(const char* prefix) const { int last = SkPathOpsVerbToPoints(fVerb); - SkDebugf("seg=%d {{", this->debugID()); + SkDebugf("%s=%d {{", prefix, this->debugID()); if (fVerb == SkPath::kConic_Verb) { SkDebugf("{"); } @@ -1103,8 +1152,8 @@ void SkOpSegment::dumpPtsInner() const { } } -void SkOpSegment::dumpPts() const { - dumpPtsInner(); +void SkOpSegment::dumpPts(const char* prefix) const { + dumpPtsInner(prefix); SkDebugf("\n"); } @@ -1141,11 +1190,15 @@ void SkOpCoincidence::dump() const { span->dump(); span = span->fNext; } - if (!fTop) { + if (!fTop || fHead == fTop) { return; } SkDebugf("top:\n"); span = fTop; + if (fHead) { + span->dump(); + return; + } while (span) { span->dump(); span = span->fNext; @@ -1199,23 +1252,23 @@ void SkOpContour::dumpPt(int index) const { } while ((segment = segment->next())); } -void SkOpContour::dumpPts() const { +void SkOpContour::dumpPts(const char* prefix) const { SkDebugf("contour=%d\n", this->debugID()); const SkOpSegment* segment = &fHead; do { - SkDebugf(" seg=%d ", segment->debugID()); - segment->dumpPts(); + SkDebugf(" %s=%d ", prefix, segment->debugID()); + segment->dumpPts(prefix); } while ((segment = segment->next())); } -void SkOpContour::dumpPtsX() const { +void SkOpContour::dumpPtsX(const char* prefix) const { if (!this->fCount) { SkDebugf("<empty>\n"); return; } const SkOpSegment* segment = &fHead; do { - segment->dumpPts(); + segment->dumpPts(prefix); } while ((segment = segment->next())); } @@ -1223,17 +1276,17 @@ void SkOpContour::dumpSegment(int index) const { debugSegment(index)->dump(); } -void SkOpContour::dumpSegments(SkPathOp op) const { +void SkOpContour::dumpSegments(const char* prefix, SkPathOp op) const { bool firstOp = false; const SkOpContour* c = this; do { - if (!firstOp && c->operand()) { + if (!firstOp && c->operand() && op >= 0) { #if DEBUG_ACTIVE_OP SkDebugf("op %s\n", SkPathOpsDebug::kPathOpStr[op]); #endif firstOp = true; } - c->dumpPtsX(); + c->dumpPtsX(prefix); } while ((c = c->next())); } diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp index 7209617985..c96cbcdae5 100644 --- a/tests/PathOpsExtendedTest.cpp +++ b/tests/PathOpsExtendedTest.cpp @@ -182,6 +182,15 @@ static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) { SkScalar vScale = (bitHeight - 2) / largerHeight; scale.reset(); scale.preScale(hScale, vScale); + larger.fLeft *= hScale; + larger.fRight *= hScale; + larger.fTop *= vScale; + larger.fBottom *= vScale; + SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft + : 16000 < larger.fRight ? 16000 - larger.fRight : 0; + SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop + : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0; + scale.postTranslate(dx, dy); } static int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPath& scaledTwo, @@ -310,7 +319,7 @@ static void showPathOpPath(const char* testName, const SkPath& one, const SkPath SkPathOpsDebug::ShowOnePath(b, "pathB", false); SkDebugf(" testPathOp(reporter, path, pathB, %s, filename);\n", opStrs[shapeOp]); SkDebugf("}\n"); - drawAsciiPaths(scaledOne, scaledTwo, false); + drawAsciiPaths(scaledOne, scaledTwo, true); } void ShowTestArray(const char* testName) { diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp index a28bae8b15..2f230936ff 100644 --- a/tests/PathOpsOpTest.cpp +++ b/tests/PathOpsOpTest.cpp @@ -5658,7 +5658,7 @@ path.lineTo(SkBits2Float(0x432c8000), SkBits2Float(0x42c00000)); path.close(); SkPath path2(path); - testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail); + testPathOpFailCheck(reporter, path1, path2, (SkPathOp) 2, filename); } static void fuzz487b(skiatest::Reporter* reporter, const char* filename) { @@ -5756,10 +5756,10 @@ path.close(); } static struct TestDesc failTests[] = { + TEST(fuzz714), TEST(fuzz487a), TEST(fuzz433), TEST(fuzz1), - TEST(fuzz714), TEST(fuzz487b), TEST(fuzz433b), TEST(bufferOverflow), diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp index ea1ffd92f3..622118248d 100644 --- a/tests/PathOpsSimplifyTest.cpp +++ b/tests/PathOpsSimplifyTest.cpp @@ -4994,11 +4994,42 @@ path.close(); testSimplify(reporter, path, filename); } +static void fuzz_twister(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 0); +path.moveTo(0, 600); +path.lineTo(3.35544e+07f, 600); +path.lineTo(3.35544e+07f, 0); +path.lineTo(0, 0); +path.lineTo(0, 600); +path.close(); +path.moveTo(63, 600); +path.lineTo(3.35545e+07f, 600); +path.lineTo(3.35545e+07f, 0); +path.lineTo(63, 0); +path.lineTo(63, 600); +path.close(); +path.moveTo(93, 600); +path.lineTo(3.35545e+07f, 600); +path.lineTo(3.35545e+07f, 0); +path.lineTo(93, 0); +path.lineTo(93, 600); +path.close(); +path.moveTo(123, 600); +path.lineTo(3.35546e+07f, 600); +path.lineTo(3.35546e+07f, 0); +path.lineTo(123, 0); +path.lineTo(123, 600); +path.close(); + testSimplify(reporter, path, filename); +} + static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0; static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0; static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0; static TestDesc tests[] = { + TEST(fuzz_twister), TEST(fuzz994s_3414), TEST(fuzz994s_11), TEST(cr514118), diff --git a/tests/PathOpsSkpTest.cpp b/tests/PathOpsSkpTest.cpp index bbf3453b6d..2c5bbfaa3c 100755 --- a/tests/PathOpsSkpTest.cpp +++ b/tests/PathOpsSkpTest.cpp @@ -1087,9 +1087,6 @@ static void skpcyclist_friends_gr52(skiatest::Reporter* reporter, const char* fi pathB.cubicTo(52.238575f, 207, 50, 204.761429f, 50, 202); pathB.lineTo(50, 183); pathB.close(); - // FIXME: this generates quads and cubics that are (correctly) not coincident unlike the old code - // however, somewhere the angles are sorted incorrectly and the winding is computed to be -1/-2 - // but I can't find the error testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename); } @@ -3768,11 +3765,227 @@ pathB.cubicTo(980.018494f, 1481.22131f, 979.602478f, 1478.38831f, 984.546021f, 1 } +static void skpwww_woothemes_com_1(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); +path.moveTo(SkBits2Float(0x44472795), SkBits2Float(0x455cdb8d)); // 796.618f, 3533.72f +path.lineTo(SkBits2Float(0x44467c27), SkBits2Float(0x455cdb8d)); // 793.94f, 3533.72f +path.lineTo(SkBits2Float(0x44467c27), SkBits2Float(0x455d055d)); // 793.94f, 3536.34f +path.lineTo(SkBits2Float(0x44472795), SkBits2Float(0x455d055d)); // 796.618f, 3536.34f +path.lineTo(SkBits2Float(0x44472795), SkBits2Float(0x455cdb8d)); // 796.618f, 3533.72f + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x4446861c), SkBits2Float(0x455cdb8d)); // 794.095f, 3533.72f +path.cubicTo(SkBits2Float(0x4446a0d8), SkBits2Float(0x455cefbb), SkBits2Float(0x444727a5), SkBits2Float(0x455d055d), SkBits2Float(0x444727a5), SkBits2Float(0x455d055d)); // 794.513f, 3534.98f, 796.619f, 3536.34f, 796.619f, 3536.34f +path.cubicTo(SkBits2Float(0x4446c5b0), SkBits2Float(0x455cf8a4), SkBits2Float(0x444693af), SkBits2Float(0x455cedad), SkBits2Float(0x44467c1b), SkBits2Float(0x455ce4b8)); // 795.089f, 3535.54f, 794.308f, 3534.85f, 793.939f, 3534.29f +path.lineTo(SkBits2Float(0x44467d70), SkBits2Float(0x455ce016)); // 793.96f, 3534.01f +path.cubicTo(SkBits2Float(0x44467fa9), SkBits2Float(0x455cde82), SkBits2Float(0x444682b5), SkBits2Float(0x455cdd03), SkBits2Float(0x4446861c), SkBits2Float(0x455cdb8d)); // 793.995f, 3533.91f, 794.042f, 3533.81f, 794.095f, 3533.72f + SkPath path2(path); + testPathOp(reporter, path1, path2, (SkPathOp) 1, filename); +} + +static void skpwww_gorcraft_ru_1(skiatest::Reporter* reporter, const char* filename) { + return; // FIXME : triggers conic/conic sort error + SkPath path; + path.setFillType((SkPath::FillType) 1); +path.moveTo(SkBits2Float(0x44924000), SkBits2Float(0x458e7800)); // 1170, 4559 +path.conicTo(SkBits2Float(0x44930000), SkBits2Float(0x458e7800), SkBits2Float(0x44930000), SkBits2Float(0x458ea800), SkBits2Float(0x3f3504f3)); // 1176, 4559, 1176, 4565, 0.707107f +path.lineTo(SkBits2Float(0x44930000), SkBits2Float(0x458f7000)); // 1176, 4590 +path.conicTo(SkBits2Float(0x44930000), SkBits2Float(0x458f9800), SkBits2Float(0x44926000), SkBits2Float(0x458f9800), SkBits2Float(0x3f3504f3)); // 1176, 4595, 1171, 4595, 0.707107f +path.lineTo(SkBits2Float(0x42a60000), SkBits2Float(0x458f9800)); // 83, 4595 +path.conicTo(SkBits2Float(0x429c0471), SkBits2Float(0x458f9800), SkBits2Float(0x429c0000), SkBits2Float(0x458f700c), SkBits2Float(0x3f352d2d)); // 78.0087f, 4595, 78, 4590.01f, 0.707721f +path.lineTo(SkBits2Float(0x429c0000), SkBits2Float(0x458ea800)); // 78, 4565 +path.conicTo(SkBits2Float(0x429c0000), SkBits2Float(0x458e7800), SkBits2Float(0x42a80000), SkBits2Float(0x458e7800), SkBits2Float(0x3f3504f3)); // 78, 4559, 84, 4559, 0.707107f +path.lineTo(SkBits2Float(0x44924000), SkBits2Float(0x458e7800)); // 1170, 4559 +path.close(); + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x429c0000), SkBits2Float(0x458f7000)); // 78, 4590 +path.lineTo(SkBits2Float(0x429c0000), SkBits2Float(0x458ea800)); // 78, 4565 +path.conicTo(SkBits2Float(0x429c0000), SkBits2Float(0x458e7800), SkBits2Float(0x42a80000), SkBits2Float(0x458e7800), SkBits2Float(0x3f3504f3)); // 78, 4559, 84, 4559, 0.707107f +path.lineTo(SkBits2Float(0x431e0000), SkBits2Float(0x458e7800)); // 158, 4559 +path.conicTo(SkBits2Float(0x431e0000), SkBits2Float(0x458e7800), SkBits2Float(0x431e0000), SkBits2Float(0x458e7800), SkBits2Float(0x3f3504f3)); // 158, 4559, 158, 4559, 0.707107f +path.lineTo(SkBits2Float(0x431e0000), SkBits2Float(0x458fa000)); // 158, 4596 +path.conicTo(SkBits2Float(0x431e0000), SkBits2Float(0x458fa000), SkBits2Float(0x431e0000), SkBits2Float(0x458fa000), SkBits2Float(0x3f3504f3)); // 158, 4596, 158, 4596, 0.707107f +path.lineTo(SkBits2Float(0x42a80000), SkBits2Float(0x458fa000)); // 84, 4596 +path.conicTo(SkBits2Float(0x429c0000), SkBits2Float(0x458fa000), SkBits2Float(0x429c0000), SkBits2Float(0x458f7000), SkBits2Float(0x3f3504f3)); // 78, 4596, 78, 4590, 0.707107f +path.close(); + + SkPath path2(path); + testPathOp(reporter, path1, path2, (SkPathOp) 2, filename); +} + +static void skpwww_neda_net_1(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); +path.moveTo(SkBits2Float(0x447a0000), SkBits2Float(0x00000000)); // 1000, 0 +path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0 +path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x44b6e000)); // 0, 1463 +path.lineTo(SkBits2Float(0x447a0000), SkBits2Float(0x44b6e000)); // 1000, 1463 +path.lineTo(SkBits2Float(0x447a0000), SkBits2Float(0x00000000)); // 1000, 0 +path.close(); + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x366a410f), SkBits2Float(0x43a38000)); // 3.49066e-06f, 327 +path.lineTo(SkBits2Float(0x447a0000), SkBits2Float(0x43a38001)); // 1000, 327 +path.lineTo(SkBits2Float(0x447a0000), SkBits2Float(0x4435c000)); // 1000, 727 +path.lineTo(SkBits2Float(0xb66a410d), SkBits2Float(0x4435c000)); // -3.49066e-06f, 727 +path.lineTo(SkBits2Float(0x366a410f), SkBits2Float(0x43a38000)); // 3.49066e-06f, 327 +path.close(); + SkPath path2(path); + testPathOp(reporter, path1, path2, (SkPathOp) 1, filename); +} + +// "http___www_neda_net.skp" dir=87 +static void skpwww_neda_net_2(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 1); +path.moveTo(SkBits2Float(0x442fc000), SkBits2Float(0x4546a000)); // 703, 3178 +path.lineTo(SkBits2Float(0x441f4000), SkBits2Float(0x4546a000)); // 637, 3178 +path.lineTo(SkBits2Float(0x441f4000), SkBits2Float(0x454ab000)); // 637, 3243 +path.lineTo(SkBits2Float(0x442fc000), SkBits2Float(0x454ab000)); // 703, 3243 +path.lineTo(SkBits2Float(0x442fc000), SkBits2Float(0x4546a000)); // 703, 3178 +path.close(); + SkPath path1(path); + path.reset(); + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x44220e6e), SkBits2Float(0x45469c4c)); // 648.225f, 3177.77f +path.lineTo(SkBits2Float(0x442fc01c), SkBits2Float(0x45475696)); // 703.002f, 3189.41f +path.lineTo(SkBits2Float(0x442cf191), SkBits2Float(0x454aa3b5)); // 691.774f, 3242.23f +path.lineTo(SkBits2Float(0x441f3fe3), SkBits2Float(0x4549e96b)); // 636.998f, 3230.59f +path.lineTo(SkBits2Float(0x44220e6e), SkBits2Float(0x45469c4c)); // 648.225f, 3177.77f +path.close(); + SkPath path2(path); + testPathOp(reporter, path1, path2, (SkPathOp) 1, filename); +} + +static void skpwww_mybuilder_com_1(skiatest::Reporter* reporter, const char* filename) { + SkPath path; +path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(1000, 659); +path.lineTo(1000, 377); +path.lineTo(455, 377); +path.lineTo(455, 659); +path.lineTo(1000, 659); +path.close(); + SkPath path1(path); + path.reset(); + path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(921.472f, 414.086f); +path.lineTo(968.815f, 386.754f); +path.lineTo(993.069f, 428.761f); +path.lineTo(945.726f, 456.096f); +path.lineTo(921.471f, 414.086f); +path.lineTo(921.472f, 414.086f); +path.close(); +path.moveTo(971.151f, 422.889f); +path.cubicTo(966.509f, 414.848f, 957.649f, 411.727f, 950.181f, 416.038f); +path.lineTo(947.224f, 417.746f); +path.lineTo(946.979f, 417.887f); +path.lineTo(947.838f, 419.371f); +path.lineTo(947.844f, 419.367f); +path.lineTo(947.868f, 419.353f); +path.lineTo(947.945f, 419.309f); +path.cubicTo(947.988f, 419.285f, 947.988f, 419.285f, 948.023f, 419.263f); +path.cubicTo(948.039f, 419.255f, 948.039f, 419.255f, 948.047f, 419.25f); +path.lineTo(948.052f, 419.247f); +path.lineTo(947.196f, 417.762f); +path.lineTo(947.195f, 417.762f); +path.lineTo(946.888f, 417.939f); +path.lineTo(943.39f, 419.959f); +path.lineTo(944.249f, 421.443f); +path.lineTo(947.745f, 419.424f); +path.lineTo(948.05f, 419.247f); +path.lineTo(948.052f, 419.247f); +path.lineTo(947.195f, 417.763f); +path.cubicTo(947.193f, 417.763f, 947.193f, 417.763f, 947.19f, 417.766f); +path.lineTo(947.166f, 417.779f); +path.lineTo(947.087f, 417.825f); +path.lineTo(947.011f, 417.868f); +path.lineTo(946.987f, 417.883f); +path.lineTo(946.982f, 417.886f); +path.lineTo(946.98f, 417.886f); +path.lineTo(947.839f, 419.37f); +path.lineTo(948.083f, 419.229f); +path.lineTo(951.039f, 417.522f); +path.cubicTo(957.631f, 413.716f, 965.471f, 416.477f, 969.669f, 423.746f); +path.lineTo(971.153f, 422.889f); +path.lineTo(971.151f, 422.889f); +path.close(); + SkPath path2(path); + testPathOp(reporter, path1, path2, kIntersect_SkPathOp, filename); +} + +static void skpwww_nimble_com_au_1(skiatest::Reporter* reporter, const char* filename) { + SkPath path; +path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(188.6f, 1988.8f); +path.lineTo(188.6f, 2041.6f); +path.cubicTo(188.6f, 2065.4f, 208, 2084.8f, 231.8f, 2084.8f); +path.cubicTo(255.6f, 2084.8f, 275, 2065.4f, 275, 2041.6f); +path.lineTo(275.2f, 2041.6f); +path.lineTo(275.2f, 1988.8f); +path.lineTo(188.6f, 1988.8f); +path.close(); + SkPath path1(path); + path.reset(); +path.setFillType(SkPath::kWinding_FillType); +path.moveTo(275, 2041.6f); +path.conicTo(275, 2084.8f, 231.8f, 2084.8f, 0.707107f); +path.conicTo(188.6f, 2084.8f, 188.6f, 2041.6f, 0.707107f); +path.conicTo(188.6f, 1998.4f, 231.8f, 1998.4f, 0.707107f); +path.conicTo(275, 1998.4f, 275, 2041.6f, 0.707107f); +path.close(); + SkPath path2(path); + testPathOp(reporter, path1, path2, kIntersect_SkPathOp, filename); +} + +static void skpwww_tinytots_com_1(skiatest::Reporter* reporter, const char* filename) { + SkPath path; +path.setFillType(SkPath::kEvenOdd_FillType); +path.moveTo(75.96f, 26.318f); +path.lineTo(70.337f, 26.318f); +path.lineTo(70.337f, 32.376f); +path.lineTo(75.96f, 32.376f); +path.lineTo(75.96f, 26.318f); +path.close(); + SkPath path1(path); + path.reset(); +path.setFillType(SkPath::kWinding_FillType); +path.moveTo(75.88f, 27.873f); +path.cubicTo(75.929f, 28.138f, 75.956f, 29.196f, 75.96f, 31.046f); +path.lineTo(72.766f, 32.376f); +path.cubicTo(72.763f, 30.525f, 72.735f, 29.468f, 72.686f, 29.203f); +path.cubicTo(72.636f, 28.94f, 72.519f, 28.722f, 72.335f, 28.552f); +path.cubicTo(72.248f, 28.472f, 72.058f, 28.364f, 71.763f, 28.228f); +path.cubicTo(72.425f, 27.933f, 72.425f, 27.933f, 73.395f, 27.498f); +path.cubicTo(72.425f, 27.933f, 72.425f, 27.933f, 71.763f, 28.228f); +path.cubicTo(71.425f, 28.072f, 70.95f, 27.878f, 70.337f, 27.647f); +path.lineTo(73.531f, 26.317f); +path.cubicTo(74.144f, 26.547f, 74.619f, 26.741f, 74.957f, 26.898f); +path.cubicTo(74.475f, 27.113f, 73.993f, 27.329f, 73.511f, 27.544f); +path.cubicTo(73.993f, 27.329f, 74.475f, 27.114f, 74.957f, 26.898f); +path.cubicTo(75.252f, 27.034f, 75.442f, 27.142f, 75.529f, 27.222f); +path.cubicTo(75.713f, 27.393f, 75.83f, 27.61f, 75.88f, 27.873f); + SkPath path2(path); + testPathOp(reporter, path1, path2, kIntersect_SkPathOp, filename); +} + static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0; -static void (*firstTest)(skiatest::Reporter* , const char* filename) = skpwww_cooksnaps_com_32; +static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0; static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0; static struct TestDesc tests[] = { + TEST(skpwww_gorcraft_ru_1), + TEST(skpwww_nimble_com_au_1), + TEST(skpwww_mybuilder_com_1), + TEST(skpwww_neda_net_2), // small coincident line segments (fixed) + TEST(skpwww_woothemes_com_1), + TEST(skpwww_neda_net_1), + TEST(skpwww_tinytots_com_1), // completely coincident reversed cubics (dup) TEST(skpwww_educationalcraft_com_4a), TEST(skpwww_lptemp_com_3), TEST(skpwww_shinydemos_com_5), diff --git a/tests/PathOpsTSectDebug.h b/tests/PathOpsTSectDebug.h index 51532f8476..9db904d06b 100644 --- a/tests/PathOpsTSectDebug.h +++ b/tests/PathOpsTSectDebug.h @@ -83,8 +83,10 @@ void SkTSect<TCurve, OppCurve>::dumpBounded(int id) const { do { if (test->findOppSpan(bounded)) { test->dump(); + SkDebugf(" "); } } while ((test = test->next())); + SkDebugf("\n"); } template<typename TCurve, typename OppCurve> @@ -141,6 +143,24 @@ const SkTSpan<TCurve, OppCurve>* SkTSpan<TCurve, OppCurve>::debugT(double t) con } template<typename TCurve, typename OppCurve> +void SkTSpan<TCurve, OppCurve>::dumpAll() const { + dumpID(); + SkDebugf("=(%g,%g) [", fStartT, fEndT); + const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; + while (testBounded) { + const SkTSpan<OppCurve, TCurve>* span = testBounded->fBounded; + const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; + span->dumpID(); + SkDebugf("=(%g,%g)", span->fStartT, span->fEndT); + if (next) { + SkDebugf(" "); + } + testBounded = next; + } + SkDebugf("]\n"); +} + +template<typename TCurve, typename OppCurve> void SkTSpan<TCurve, OppCurve>::dump() const { dumpID(); SkDebugf("=(%g,%g) [", fStartT, fEndT); diff --git a/tests/PathOpsTestCommon.h b/tests/PathOpsTestCommon.h index 3fd79e1a5a..c5ebbd1027 100644 --- a/tests/PathOpsTestCommon.h +++ b/tests/PathOpsTestCommon.h @@ -7,7 +7,7 @@ #ifndef PathOpsTestCommon_DEFINED #define PathOpsTestCommon_DEFINED -#include "SkPathOpsConic.h" +#include "SkPathOpsQuad.h" #include "SkTArray.h" struct SkPathOpsBounds; diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp index dc5ae97c3f..38237e4c02 100644 --- a/tests/skia_test.cpp +++ b/tests/skia_test.cpp @@ -30,6 +30,7 @@ DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps."); // need to explicitly declare this, or we get some weird infinite loop llist template TestRegistry* TestRegistry::gHead; +void (*gVerboseFinalize)() = nullptr; // The threads report back to this object when they are done. class Status { @@ -214,6 +215,9 @@ int test_main() { "\nFinished %d tests, %d failures, %d skipped. " "(%d internal tests)", toRun, status.failCount(), skipCount, status.testCount()); + if (gVerboseFinalize) { + (*gVerboseFinalize)(); + } } SkDebugf("\n"); |