diff options
-rw-r--r-- | gyp/pathops_unittest.gypi | 1 | ||||
-rw-r--r-- | src/pathops/SkOpAngle.cpp | 28 | ||||
-rw-r--r-- | src/pathops/SkOpAngle.h | 11 | ||||
-rw-r--r-- | src/pathops/SkOpContour.h | 5 | ||||
-rw-r--r-- | src/pathops/SkOpSegment.cpp | 7 | ||||
-rw-r--r-- | src/pathops/SkOpSegment.h | 2 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCommon.cpp | 11 | ||||
-rw-r--r-- | src/pathops/SkPathOpsDebug.h | 2 | ||||
-rw-r--r-- | tests/PathOpsChalkboardTest.cpp | 181 | ||||
-rw-r--r-- | tests/PathOpsSimplifyTest.cpp | 12 | ||||
-rw-r--r-- | tools/pathops_sorter.htm | 13 |
11 files changed, 247 insertions, 26 deletions
diff --git a/gyp/pathops_unittest.gypi b/gyp/pathops_unittest.gypi index baf0196d0b..0ff76fcb84 100644 --- a/gyp/pathops_unittest.gypi +++ b/gyp/pathops_unittest.gypi @@ -27,6 +27,7 @@ '../tests/PathOpsBuilderConicTest.cpp', '../tests/PathOpsBuilderTest.cpp', '../tests/PathOpsBuildUseTest.cpp', + '../tests/PathOpsChalkboardTest.cpp', '../tests/PathOpsConicIntersectionTest.cpp', '../tests/PathOpsConicLineIntersectionTest.cpp', '../tests/PathOpsConicQuadIntersectionTest.cpp', diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp index 820b5dceee..99f93dd544 100644 --- a/src/pathops/SkOpAngle.cpp +++ b/src/pathops/SkOpAngle.cpp @@ -320,7 +320,7 @@ recomputeSector: return !fUnorderable; } -int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) const { +int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) { const SkDVector* sweep = this->fPart.fSweep; const SkDVector* tweep = rh->fPart.fSweep; double s0xs1 = sweep[0].crossCheck(sweep[1]); @@ -593,20 +593,20 @@ SkOpGlobalState* SkOpAngle::globalState() const { // OPTIMIZE: if this loops to only one other angle, after first compare fails, insert on other side // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opposite side -void SkOpAngle::insert(SkOpAngle* angle) { +bool SkOpAngle::insert(SkOpAngle* angle) { if (angle->fNext) { if (loopCount() >= angle->loopCount()) { if (!merge(angle)) { - return; + return true; } } else if (fNext) { if (!angle->merge(this)) { - return; + return true; } } else { angle->insert(this); } - return; + return true; } bool singleton = nullptr == fNext; if (singleton) { @@ -622,20 +622,27 @@ void SkOpAngle::insert(SkOpAngle* angle) { angle->fNext = this; } debugValidateNext(); - return; + return true; } SkOpAngle* last = this; + bool flipAmbiguity = false; do { SkASSERT(last->fNext == next); - if (angle->after(last)) { + if (angle->after(last) ^ (angle->tangentsAmbiguous() & flipAmbiguity)) { last->fNext = angle; angle->fNext = next; debugValidateNext(); - return; + return true; } last = next; + if (last == this) { + FAIL_IF(flipAmbiguity); + // We're in a loop. If a sort was ambiguous, flip it to end the loop. + flipAmbiguity = true; + } next = next->fNext; } while (true); + return true; } SkOpSpanBase* SkOpAngle::lastMarked() const { @@ -815,7 +822,7 @@ void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) { fComputedEnd = fEnd = end; SkASSERT(start != end); fNext = nullptr; - fComputeSector = fComputedSector = fCheckCoincidence = false; + fComputeSector = fComputedSector = fCheckCoincidence = fTangentsAmbiguous = false; setSpans(); setSector(); SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1); @@ -966,7 +973,7 @@ SkOpSpan* SkOpAngle::starter() { return fStart->starter(fEnd); } -bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { +bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) { if (s0xt0 == 0) { return false; } @@ -991,5 +998,6 @@ bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { double tDist = tweep[0].length() * m; bool useS = fabs(sDist) < fabs(tDist); double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tDist)); + fTangentsAmbiguous = mFactor >= 50 && mFactor < 200; return mFactor < 50; // empirically found limit } diff --git a/src/pathops/SkOpAngle.h b/src/pathops/SkOpAngle.h index cbdadf1039..3cebfff717 100644 --- a/src/pathops/SkOpAngle.h +++ b/src/pathops/SkOpAngle.h @@ -64,7 +64,7 @@ public: return fEnd; } - void insert(SkOpAngle* ); + bool insert(SkOpAngle* ); SkOpSpanBase* lastMarked() const; bool loopContains(const SkOpAngle* ) const; int loopCount() const; @@ -87,6 +87,10 @@ public: SkOpSpan* starter(); + bool tangentsAmbiguous() const { + return fTangentsAmbiguous; + } + bool unorderable() const { return fUnorderable; } @@ -97,7 +101,7 @@ private: bool checkCrossesZero() const; bool checkParallel(SkOpAngle* ); bool computeSector(); - int convexHullOverlaps(const SkOpAngle* ) const; + int convexHullOverlaps(const SkOpAngle* ); bool endToSide(const SkOpAngle* rh, bool* inside) const; bool endsIntersect(SkOpAngle* ); int findSector(SkPath::Verb verb, double x, double y) const; @@ -109,7 +113,7 @@ private: bool orderable(SkOpAngle* rh); // false == this < rh ; true == this > rh void setSector(); void setSpans(); - bool tangentsDiverge(const SkOpAngle* rh, double s0xt0) const; + bool tangentsDiverge(const SkOpAngle* rh, double s0xt0); SkDCurve fOriginalCurvePart; // the curve from start to end SkDCurveSweep fPart; // the curve from start to end offset as needed @@ -127,6 +131,7 @@ private: bool fComputeSector; bool fComputedSector; bool fCheckCoincidence; + bool fTangentsAmbiguous; SkDEBUGCODE(int fID); friend class PathOpsAngleTester; diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h index dc07c53045..f6c879f16f 100644 --- a/src/pathops/SkOpContour.h +++ b/src/pathops/SkOpContour.h @@ -341,12 +341,13 @@ public: fXor = isXor; } - void sortAngles() { + bool sortAngles() { SkASSERT(fCount > 0); SkOpSegment* segment = &fHead; do { - segment->sortAngles(); + FAIL_IF(!segment->sortAngles()); } while ((segment = segment->next())); + return true; } const SkPoint& start() const { diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp index 2246f36ff2..6012d832bf 100644 --- a/src/pathops/SkOpSegment.cpp +++ b/src/pathops/SkOpSegment.cpp @@ -855,7 +855,7 @@ bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, in SkOpSegment* other = this; while ((other = other->nextChase(&start, &step, &spanStart, &last))) { if (spanStart->windSum() != SK_MinS32) { - SkASSERT(spanStart->windSum() == winding); +// SkASSERT(spanStart->windSum() == winding); // FIXME: is this assert too aggressive? SkASSERT(!last); break; } @@ -1459,7 +1459,7 @@ void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); } -void SkOpSegment::sortAngles() { +bool SkOpSegment::sortAngles() { SkOpSpanBase* span = &this->fHead; do { SkOpAngle* fromAngle = span->fromAngle(); @@ -1477,7 +1477,7 @@ void SkOpSegment::sortAngles() { span->debugID()); wroteAfterHeader = true; #endif - fromAngle->insert(toAngle); + FAIL_IF(!fromAngle->insert(toAngle)); } else if (!fromAngle) { baseAngle = toAngle; } @@ -1527,6 +1527,7 @@ void SkOpSegment::sortAngles() { SkASSERT(!baseAngle || baseAngle->loopCount() > 1); #endif } while (!span->final() && (span = span->upCast()->next())); + return true; } bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h index b6e7714018..e9618ceeb2 100644 --- a/src/pathops/SkOpSegment.h +++ b/src/pathops/SkOpSegment.h @@ -371,7 +371,7 @@ public: int* maxWinding, int* sumWinding); void setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding); - void sortAngles(); + bool sortAngles(); bool spansNearby(const SkOpSpanBase* ref, const SkOpSpanBase* check) const; static int SpanSign(const SkOpSpanBase* start, const SkOpSpanBase* end) { diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp index b4049bc5d9..a1cd7bbd63 100644 --- a/src/pathops/SkPathOpsCommon.cpp +++ b/src/pathops/SkPathOpsCommon.cpp @@ -235,11 +235,14 @@ static void move_nearby(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS( } while ((contour = contour->next())); } -static void sort_angles(SkOpContourHead* contourList) { +static bool sort_angles(SkOpContourHead* contourList) { SkOpContour* contour = contourList; do { - contour->sortAngles(); + if (!contour->sortAngles()) { + return false; + } } while ((contour = contour->next())); + return true; } bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) { @@ -327,7 +330,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc } } while (!overlaps.isEmpty()); calc_angles(contourList DEBUG_COIN_PARAMS()); - sort_angles(contourList); + if (!sort_angles(contourList)) { + return false; + } #if DEBUG_COINCIDENCE_VERBOSE coincidence->debugShowCoincidence(); #endif diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h index f07d7d0524..4dc52721e6 100644 --- a/src/pathops/SkPathOpsDebug.h +++ b/src/pathops/SkPathOpsDebug.h @@ -22,7 +22,7 @@ class SkOpContourHead; #define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging #endif -#define DEBUG_UNDER_DEVELOPMENT 1 +#define DEBUG_UNDER_DEVELOPMENT 0 #define ONE_OFF_DEBUG 0 #define ONE_OFF_DEBUG_MATHEMATICA 0 diff --git a/tests/PathOpsChalkboardTest.cpp b/tests/PathOpsChalkboardTest.cpp new file mode 100644 index 0000000000..134da6b89f --- /dev/null +++ b/tests/PathOpsChalkboardTest.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "PathOpsExtendedTest.h" +#include "PathOpsThreadedCommon.h" + +#define TEST(name) { name, #name } + +static void chalkboard(skiatest::Reporter* reporter, uint64_t testlines) { + SkPath path; + path.setFillType((SkPath::FillType) 0); +uint64_t i = 0; +path.moveTo(SkBits2Float(0x4470eed9), SkBits2Float(0x439c1ac1)); // 963.732f, 312.209f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4470dde3), SkBits2Float(0x439c63d8)); // 963.467f, 312.78f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470dbd7), SkBits2Float(0x439c3e57), SkBits2Float(0x4470c893), SkBits2Float(0x439c69fd), SkBits2Float(0x4470cfcf), SkBits2Float(0x439c297a)); // 963.435f, 312.487f, 963.134f, 312.828f, 963.247f, 312.324f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470c46b), SkBits2Float(0x439c8149), SkBits2Float(0x4470b137), SkBits2Float(0x439c2938), SkBits2Float(0x4470b5f4), SkBits2Float(0x439ca99b)); // 963.069f, 313.01f, 962.769f, 312.322f, 962.843f, 313.325f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470e842), SkBits2Float(0x439c8335), SkBits2Float(0x447125a2), SkBits2Float(0x439cce78), SkBits2Float(0x44715a2d), SkBits2Float(0x439c61ed)); // 963.629f, 313.025f, 964.588f, 313.613f, 965.409f, 312.765f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447150d5), SkBits2Float(0x439c945c)); // 965.263f, 313.159f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4471546b), SkBits2Float(0x439c87f2), SkBits2Float(0x4471579e), SkBits2Float(0x439c8085), SkBits2Float(0x44715a8f), SkBits2Float(0x439c7c4c)); // 965.319f, 313.062f, 965.369f, 313.004f, 965.415f, 312.971f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715cbc), SkBits2Float(0x439c79dd)); // 965.449f, 312.952f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715dd3), SkBits2Float(0x439c7918)); // 965.466f, 312.946f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715e56), SkBits2Float(0x439c78d6)); // 965.474f, 312.944f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715e77), SkBits2Float(0x439c78b5)); // 965.476f, 312.943f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715e77), SkBits2Float(0x439c78b5)); // 965.476f, 312.943f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715e87), SkBits2Float(0x439c78b5)); // 965.477f, 312.943f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4471a50e), SkBits2Float(0x439d05c3), SkBits2Float(0x4470fe77), SkBits2Float(0x439bb894), SkBits2Float(0x44710f9e), SkBits2Float(0x439bdb03)); // 966.579f, 314.045f, 963.976f, 311.442f, 964.244f, 311.711f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44710fae), SkBits2Float(0x439bdb24)); // 964.245f, 311.712f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44710fbe), SkBits2Float(0x439bdba7)); // 964.246f, 311.716f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44710fce), SkBits2Float(0x439be397)); // 964.247f, 311.778f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44710eb7), SkBits2Float(0x439bedf5), SkBits2Float(0x44710978), SkBits2Float(0x439bf74d), SkBits2Float(0x447105e2), SkBits2Float(0x439c0064)); // 964.23f, 311.859f, 964.148f, 311.932f, 964.092f, 312.003f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470fe86), SkBits2Float(0x439c1270), SkBits2Float(0x4470fd4f), SkBits2Float(0x439c2250), SkBits2Float(0x44712fde), SkBits2Float(0x439c33d9)); // 963.977f, 312.144f, 963.958f, 312.268f, 964.748f, 312.405f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4470fc48), SkBits2Float(0x439c3271)); // 963.942f, 312.394f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470ee13), SkBits2Float(0x439c4c2b), SkBits2Float(0x4471476b), SkBits2Float(0x439c5c0b), SkBits2Float(0x44711177), SkBits2Float(0x439c7a40)); // 963.72f, 312.595f, 965.116f, 312.719f, 964.273f, 312.955f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44712685), SkBits2Float(0x439c7648)); // 964.602f, 312.924f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x447126a6), SkBits2Float(0x439c7d31), SkBits2Float(0x44711d2d), SkBits2Float(0x439c8085), SkBits2Float(0x44711d1d), SkBits2Float(0x439c8790)); // 964.604f, 312.978f, 964.456f, 313.004f, 964.455f, 313.059f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44712675), SkBits2Float(0x439c843c)); // 964.601f, 313.033f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44713bd5), SkBits2Float(0x439c94e0), SkBits2Float(0x44713956), SkBits2Float(0x439ca065), SkBits2Float(0x44712b63), SkBits2Float(0x439cb357)); // 964.935f, 313.163f, 964.896f, 313.253f, 964.678f, 313.401f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44711af0), SkBits2Float(0x439cb5a5), SkBits2Float(0x44712459), SkBits2Float(0x439cab47), SkBits2Float(0x44711fad), SkBits2Float(0x439ca607)); // 964.421f, 313.419f, 964.568f, 313.338f, 964.495f, 313.297f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44710f1a), SkBits2Float(0x439caf3e), SkBits2Float(0x4471325d), SkBits2Float(0x439cbb26), SkBits2Float(0x4471326e), SkBits2Float(0x439cc93a)); // 964.236f, 313.369f, 964.787f, 313.462f, 964.788f, 313.572f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44712428), SkBits2Float(0x439cd501), SkBits2Float(0x44711ad0), SkBits2Float(0x439cca82), SkBits2Float(0x447113b6), SkBits2Float(0x439cc95b)); // 964.565f, 313.664f, 964.419f, 313.582f, 964.308f, 313.573f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44712b95), SkBits2Float(0x439cf20f), SkBits2Float(0x4470f550), SkBits2Float(0x439d0790), SkBits2Float(0x4471426e), SkBits2Float(0x439d21ce)); // 964.681f, 313.891f, 963.833f, 314.059f, 965.038f, 314.264f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44715072), SkBits2Float(0x439d241c), SkBits2Float(0x44715c6a), SkBits2Float(0x439d15a5), SkBits2Float(0x44716364), SkBits2Float(0x439d24c0)); // 965.257f, 314.282f, 965.444f, 314.169f, 965.553f, 314.287f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44717b22), SkBits2Float(0x439d0791), SkBits2Float(0x44715cbc), SkBits2Float(0x439cf231), SkBits2Float(0x4471475c), SkBits2Float(0x439cda20)); // 965.924f, 314.059f, 965.449f, 313.892f, 965.115f, 313.704f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4471477d), SkBits2Float(0x439ce12a)); // 965.117f, 313.759f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470fc4a), SkBits2Float(0x439cd14b), SkBits2Float(0x44715810), SkBits2Float(0x439cd0e8), SkBits2Float(0x4471372b), SkBits2Float(0x439cb272)); // 963.942f, 313.635f, 965.376f, 313.632f, 964.862f, 313.394f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x447155b2), SkBits2Float(0x439cb91a), SkBits2Float(0x44715581), SkBits2Float(0x439cc72e), SkBits2Float(0x447165f4), SkBits2Float(0x439ccbeb)); // 965.339f, 313.446f, 965.336f, 313.556f, 965.593f, 313.593f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44719e77), SkBits2Float(0x439ca2b4), SkBits2Float(0x44713979), SkBits2Float(0x439c993b), SkBits2Float(0x4471821d), SkBits2Float(0x439c7b47)); // 966.476f, 313.271f, 964.898f, 313.197f, 966.033f, 312.963f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4471847b), SkBits2Float(0x439c7dd6)); // 966.07f, 312.983f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44718b96), SkBits2Float(0x439c77b1), SkBits2Float(0x44717d81), SkBits2Float(0x439c6ebb), SkBits2Float(0x44717667), SkBits2Float(0x439c66ab)); // 966.181f, 312.935f, 965.961f, 312.865f, 965.85f, 312.802f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44716cff), SkBits2Float(0x439c6a41), SkBits2Float(0x44716842), SkBits2Float(0x439c7315), SkBits2Float(0x44716159), SkBits2Float(0x439c793a)); // 965.703f, 312.83f, 965.629f, 312.899f, 965.521f, 312.947f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44715a0d), SkBits2Float(0x439c712a), SkBits2Float(0x44713938), SkBits2Float(0x439c6f3e), SkBits2Float(0x44712b34), SkBits2Float(0x439c6d73)); // 965.407f, 312.884f, 964.894f, 312.869f, 964.675f, 312.855f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44714c19), SkBits2Float(0x439c614a), SkBits2Float(0x44711af2), SkBits2Float(0x439c61ee), SkBits2Float(0x44712b34), SkBits2Float(0x439c518c)); // 965.189f, 312.76f, 964.421f, 312.765f, 964.675f, 312.637f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x447149ab), SkBits2Float(0x439c499c), SkBits2Float(0x4471474d), SkBits2Float(0x439c5c0b), SkBits2Float(0x447157d0), SkBits2Float(0x439c6065)); // 965.151f, 312.575f, 965.114f, 312.719f, 965.372f, 312.753f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447142b1), SkBits2Float(0x439c4fa0)); // 965.042f, 312.622f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44714053), SkBits2Float(0x439c3f1d), SkBits2Float(0x44716396), SkBits2Float(0x439c3c6d), SkBits2Float(0x447173f9), SkBits2Float(0x439c3292)); // 965.005f, 312.493f, 965.556f, 312.472f, 965.812f, 312.395f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44715c7c), SkBits2Float(0x439c2628), SkBits2Float(0x44716397), SkBits2Float(0x439c3c4c), SkBits2Float(0x447142b1), SkBits2Float(0x439c3398)); // 965.445f, 312.298f, 965.556f, 312.471f, 965.042f, 312.403f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44715572), SkBits2Float(0x439c2919), SkBits2Float(0x44715bd8), SkBits2Float(0x439c10a6), SkBits2Float(0x447159bb), SkBits2Float(0x439bf68a)); // 965.335f, 312.321f, 965.435f, 312.13f, 965.402f, 311.926f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715698), SkBits2Float(0x439be2f4)); // 965.353f, 311.773f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447153f8), SkBits2Float(0x439bd95a)); // 965.312f, 311.698f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4471526f), SkBits2Float(0x439bd49e)); // 965.288f, 311.661f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4471524e), SkBits2Float(0x439bd45c)); // 965.286f, 311.659f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4471523e), SkBits2Float(0x439bd41a)); // 965.285f, 311.657f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44717148), SkBits2Float(0x439c124f), SkBits2Float(0x44715ae2), SkBits2Float(0x439be562), SkBits2Float(0x447161cb), SkBits2Float(0x439bf335)); // 965.77f, 312.143f, 965.42f, 311.792f, 965.528f, 311.9f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447161bb), SkBits2Float(0x439bf356)); // 965.527f, 311.901f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447161bb), SkBits2Float(0x439bf356)); // 965.527f, 311.901f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44716169), SkBits2Float(0x439bf3b8)); // 965.522f, 311.904f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x447160c5), SkBits2Float(0x439bf47d)); // 965.512f, 311.91f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44715f7d), SkBits2Float(0x439bf627)); // 965.492f, 311.923f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x447158f6), SkBits2Float(0x439bfeba), SkBits2Float(0x447152e1), SkBits2Float(0x439c0ac3), SkBits2Float(0x44714e15), SkBits2Float(0x439c1919)); // 965.39f, 311.99f, 965.295f, 312.084f, 965.22f, 312.196f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4471548c), SkBits2Float(0x439c10c7), SkBits2Float(0x447151bb), SkBits2Float(0x439bd7f2), SkBits2Float(0x44715927), SkBits2Float(0x439be271)); // 965.321f, 312.131f, 965.277f, 311.687f, 965.393f, 311.769f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x447156b8), SkBits2Float(0x439bd41b), SkBits2Float(0x44714c19), SkBits2Float(0x439bf356), SkBits2Float(0x44714b13), SkBits2Float(0x439c222f)); // 965.355f, 311.657f, 965.189f, 311.901f, 965.173f, 312.267f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44713dd4), SkBits2Float(0x439c4aa2), SkBits2Float(0x44712ea9), SkBits2Float(0x439c2be9), SkBits2Float(0x44712344), SkBits2Float(0x439c0085)); // 964.966f, 312.583f, 964.729f, 312.343f, 964.551f, 312.004f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x44712605), SkBits2Float(0x439c2fa0)); // 964.594f, 312.372f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x44711af3), SkBits2Float(0x439c7e9a), SkBits2Float(0x44710de4), SkBits2Float(0x439bf41b), SkBits2Float(0x4470fb65), SkBits2Float(0x439c20c7)); // 964.421f, 312.989f, 964.217f, 311.907f, 963.928f, 312.256f +if (testlines & (1LL << i++)) path.lineTo(SkBits2Float(0x4470fbb7), SkBits2Float(0x439c220f)); // 963.933f, 312.266f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470f5e4), SkBits2Float(0x439c2bc9), SkBits2Float(0x4470ef5d), SkBits2Float(0x439c9e59), SkBits2Float(0x4470e50f), SkBits2Float(0x439c85e6)); // 963.842f, 312.342f, 963.74f, 313.237f, 963.579f, 313.046f +if (testlines & (1LL << i++)) path.cubicTo(SkBits2Float(0x4470e8f6), SkBits2Float(0x439c4e35), SkBits2Float(0x4470ee98), SkBits2Float(0x439c5333), SkBits2Float(0x4470eed9), SkBits2Float(0x439c1ac1)); // 963.64f, 312.611f, 963.728f, 312.65f, 963.732f, 312.209f +SkASSERT(64 == i); +path.close(); + +testSimplify(reporter, path, "chalkboard"); +} + +static void testChalkboard(PathOpsThreadState* data) { + uint64_t testlines = ((uint64_t) data->fB << 32) | (unsigned int) data->fA; + chalkboard(data->fReporter, testlines); +} + +static void chalkboard_threaded(skiatest::Reporter* reporter, const char* filename) { +#if DEBUG_UNDER_DEVELOPMENT + return; +#endif + initializeTests(reporter, "chalkboard"); + PathOpsThreadedTestRunner testRunner(reporter); + SkRandom r; + for (int samples = 0; samples <= 64; ++samples) { + int testCount; + int bitCount = samples < 32 ? samples : 64 - samples; + int index1 = 63; + int index2 = 62; + switch (bitCount) { + case 0: + testCount = 1; + break; + case 1: + testCount = 64; + break; + case 2: + testCount = reporter->allowExtendedTest() ? 63 * 62 / 2 : 100; + break; + default: + testCount = reporter->allowExtendedTest() ? 10000 : 100; + break; + } + for (int test = 0; test < testCount; ++test) { + uint64_t testlines; + switch (bitCount) { + case 0: + testlines = 0; + break; + case 1: + testlines = 1LL << test; + break; + case 2: + if (reporter->allowExtendedTest()) { + SkASSERT(index1 >= 1); + SkASSERT(index2 >= 0); + testlines = 1LL << index1; + testlines |= 1LL << index2; + if (--index2 < 0) { + --index1; + index2 = index1 - 1; + } + break; + } + default: + testlines = 0; + for (int i = 0; i < bitCount; ++i) { + int bit; + do { + bit = r.nextRangeU(0, 64); + } while (testlines & (1LL << bit)); + testlines |= 1LL << bit; + } + } + if (samples >= 32) { + testlines ^= 0xFFFFFFFFFFFFFFFFLL; + } + *testRunner.fRunnables.append() = + new PathOpsThreadedRunnable(&testChalkboard, + (int) (unsigned) (testlines & 0xFFFFFFFF), + (int) (unsigned) (testlines >> 32), + 0, 0, &testRunner); + } + } + testRunner.render(); +} + +static void chalkboard_1(skiatest::Reporter* reporter, const char* filename) { + uint64_t testlines = 0xFFFFFFFFFFFFFFFFLL; + chalkboard(reporter, testlines); +} + +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(chalkboard_1), + TEST(chalkboard_threaded), +}; + +static const size_t testCount = SK_ARRAY_COUNT(tests); +static bool runReverse = false; + +DEF_TEST(PathOpsChalkboard, reporter) { + RunTestSet(reporter, tests, testCount, firstTest, skipTest, stopTest, runReverse); +} diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp index 56b11ae6c1..52699ca6bf 100644 --- a/tests/PathOpsSimplifyTest.cpp +++ b/tests/PathOpsSimplifyTest.cpp @@ -5547,11 +5547,23 @@ path.cubicTo(SkBits2Float(0xc29e0000), SkBits2Float(0xc25c71c7), SkBits2Float(0x testSimplify(reporter, path, filename); } +static void tiger8_393(skiatest::Reporter* reporter, const char* filename) { + SkPath path; + path.setFillType((SkPath::FillType) 0); +path.moveTo(SkBits2Float(0x42b93333), SkBits2Float(0x43d5a666)); // 92.6f, 427.3f +path.cubicTo(SkBits2Float(0x42b93333), SkBits2Float(0x43d5a666), SkBits2Float(0x42b5cccd), SkBits2Float(0x43da1999), SkBits2Float(0x42b80000), SkBits2Float(0x43ddf333)); // 92.6f, 427.3f, 90.9f, 436.2f, 92, 443.9f +path.cubicTo(SkBits2Float(0x42b80000), SkBits2Float(0x43ddf333), SkBits2Float(0x42b30000), SkBits2Float(0x43e17333), SkBits2Float(0x42cf999a), SkBits2Float(0x43e1b333)); // 92, 443.9f, 89.5f, 450.9f, 103.8f, 451.4f +path.cubicTo(SkBits2Float(0x42ec3334), SkBits2Float(0x43e14ccd), SkBits2Float(0x42e73334), SkBits2Float(0x43ddf333), SkBits2Float(0x42e73334), SkBits2Float(0x43ddf333)); // 118.1f, 450.6f, 115.6f, 443.9f, 115.6f, 443.9f +path.cubicTo(SkBits2Float(0x42e7999a), SkBits2Float(0x43de8000), SkBits2Float(0x42ea6667), SkBits2Float(0x43db4000), SkBits2Float(0x42e60001), SkBits2Float(0x43d5a666)); // 115.8f, 445, 117.2f, 438.5f, 115, 427.3f + 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(tiger8_393), TEST(bug5169), TEST(testQuads73), TEST(testQuads72), diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm index d2d90da8bc..612a68492e 100644 --- a/tools/pathops_sorter.htm +++ b/tools/pathops_sorter.htm @@ -7,17 +7,24 @@ <div style="height:0"> <div id="cubics"> -{{{317, 711}, {322.522857666015625, 711}, {327, 715.4771728515625}, {327, 721}}}, -{{{324.071075439453125, 713.928955078125}, {324.4051513671875, 714.26300048828125}, {324.715667724609375, 714.62060546875}, {325, 714.9990234375}}}, +{{{103.800003f, 451.399994f}, {118.100006f, 450.600006f}, {115.600006f, 443.899994f}, {115.600006f, 443.899994f}}} id=3 +{{{115.600006f, 443.899994f}, {115.800003f, 445}, {117.200005f, 438.5f}, {115.000008f, 427.299988f}}} id=4 </div> +<div id="cubics2"> +{{{115.6316070556640625, 443.999237060546875}, {115.9124092648639675, 444.4395003767372145}, {117.1065847217176383, 438.0244068281508589}, {115.0000076293945313, 427.29998779296875}}} id=44 +{{{115.6316070556640625, 443.999237060546875}, {115.619154389193497, 443.9797128116054523}, {115.6084986998821762, 443.9467041484157335}, {115.600006103515625, 443.899993896484375}}} id=43 +{{{115.6316070556640625, 443.999237060546875}, {115.8726462570580225, 444.8329011683850354}, {117.0719462895199854, 450.6575499937891891}, {103.8000106811523438, 451.4000244140625}}} id=31 +{{{115.6316070556640625, 443.999237060546875}, {115.6129357357566789, 443.9346599744848163}, {115.6000137329101563, 443.9000244140625}, {115.6000137329101563, 443.9000244140625}}} id=32 +</div> </div> <script type="text/javascript"> var testDivs = [ + cubics2, cubics -]; + ]; var decimal_places = 3; |