aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2015-10-16 09:03:38 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-16 09:03:38 -0700
commit26ad22ab61539e3d3b6bc5e0da8dcebbd52a53de (patch)
treec2deb3596ffaa9aa5d8ebaf975ae71ef8e97e86a /tests
parent1a1d0b8d07d1d1cc2e56bb4790ff62179ba0c74c (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.cpp73
-rw-r--r--tests/PathOpsCubicIntersectionTest.cpp17
-rwxr-xr-xtests/PathOpsDebug.cpp95
-rw-r--r--tests/PathOpsExtendedTest.cpp11
-rw-r--r--tests/PathOpsOpTest.cpp4
-rw-r--r--tests/PathOpsSimplifyTest.cpp31
-rwxr-xr-xtests/PathOpsSkpTest.cpp221
-rw-r--r--tests/PathOpsTSectDebug.h20
-rw-r--r--tests/PathOpsTestCommon.h2
-rw-r--r--tests/skia_test.cpp4
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");