diff options
Diffstat (limited to 'src/pathops')
-rw-r--r-- | src/pathops/SkAddIntersections.cpp | 12 | ||||
-rw-r--r-- | src/pathops/SkDConicLineIntersection.cpp | 4 | ||||
-rw-r--r-- | src/pathops/SkDCubicLineIntersection.cpp | 1 | ||||
-rw-r--r-- | src/pathops/SkDLineIntersection.cpp | 2 | ||||
-rw-r--r-- | src/pathops/SkIntersections.h | 6 | ||||
-rw-r--r-- | src/pathops/SkOpAngle.cpp | 2 | ||||
-rwxr-xr-x | src/pathops/SkOpCoincidence.cpp | 35 | ||||
-rw-r--r-- | src/pathops/SkOpCoincidence.h | 6 | ||||
-rw-r--r-- | src/pathops/SkOpSegment.cpp | 11 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCommon.cpp | 4 | ||||
-rw-r--r-- | src/pathops/SkPathOpsConic.cpp | 3 | ||||
-rw-r--r-- | src/pathops/SkPathOpsConic.h | 15 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCubic.cpp | 2 | ||||
-rw-r--r-- | src/pathops/SkPathOpsCubic.h | 14 | ||||
-rw-r--r-- | src/pathops/SkPathOpsDebug.cpp | 28 | ||||
-rw-r--r-- | src/pathops/SkPathOpsQuad.h | 15 | ||||
-rw-r--r-- | src/pathops/SkPathOpsRect.h | 4 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTSect.cpp | 24 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTSect.h | 54 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTypes.h | 4 | ||||
-rw-r--r-- | src/pathops/SkPathWriter.cpp | 11 | ||||
-rw-r--r-- | src/pathops/SkPathWriter.h | 2 |
22 files changed, 172 insertions, 87 deletions
diff --git a/src/pathops/SkAddIntersections.cpp b/src/pathops/SkAddIntersections.cpp index b3a82cdeca..17bc9e2ecb 100644 --- a/src/pathops/SkAddIntersections.cpp +++ b/src/pathops/SkAddIntersections.cpp @@ -450,8 +450,10 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc } case SkIntersectionHelper::kCubic_Segment: { swap = true; - pts = ts.intersect(cubic2.set(wn.pts()), - conic1.set(wt.pts(), wt.weight())); + pts = ts.intersect(cubic2.set(wn.pts() + SkDEBUGPARAMS(ts.globalState())), + conic1.set(wt.pts(), wt.weight() + SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wn, wt, ts); break; } @@ -479,8 +481,10 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc break; } case SkIntersectionHelper::kConic_Segment: { - pts = ts.intersect(cubic1.set(wt.pts()), - conic2.set(wn.pts(), wn.weight())); + pts = ts.intersect(cubic1.set(wt.pts() + SkDEBUGPARAMS(ts.globalState())), + conic2.set(wn.pts(), wn.weight() + SkDEBUGPARAMS(ts.globalState()))); debugShowCubicConicIntersection(pts, wt, wn, ts); break; } diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp index eb32068d0e..102a4c3c90 100644 --- a/src/pathops/SkDConicLineIntersection.cpp +++ b/src/pathops/SkDConicLineIntersection.cpp @@ -105,8 +105,8 @@ public: double conicT = rootVals[index]; double lineT = this->findLineT(conicT); #ifdef SK_DEBUG - if (!fIntersections->debugGlobalState() - || !fIntersections->debugGlobalState()->debugSkipAssert()) { + if (!fIntersections->globalState() + || !fIntersections->globalState()->debugSkipAssert()) { SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT)); SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT)); SkASSERT(conicPt.approximatelyDEqual(linePt)); diff --git a/src/pathops/SkDCubicLineIntersection.cpp b/src/pathops/SkDCubicLineIntersection.cpp index fd060de646..ceedce18e9 100644 --- a/src/pathops/SkDCubicLineIntersection.cpp +++ b/src/pathops/SkDCubicLineIntersection.cpp @@ -122,6 +122,7 @@ public: double adj = fLine[1].fX - fLine[0].fX; double opp = fLine[1].fY - fLine[0].fY; SkDCubic c; + SkDEBUGCODE(c.fDebugGlobalState = fIntersections->globalState()); for (int n = 0; n < 4; ++n) { c[n].fX = (fCubic[n].fY - fLine[0].fY) * adj - (fCubic[n].fX - fLine[0].fX) * opp; } diff --git a/src/pathops/SkDLineIntersection.cpp b/src/pathops/SkDLineIntersection.cpp index 71e2a064d5..082e2987b9 100644 --- a/src/pathops/SkDLineIntersection.cpp +++ b/src/pathops/SkDLineIntersection.cpp @@ -152,7 +152,7 @@ int SkIntersections::intersect(const SkDLine& a, const SkDLine& b) { continue; } SkASSERT(a[iA] != b[nearer]); - SkASSERT(iA == (bNearA[nearer] > 0.5)); + SkOPASSERT(iA == (bNearA[nearer] > 0.5)); insertNear(iA, nearer, a[iA], b[nearer]); aNearB[iA] = -1; bNearA[nearer] = -1; diff --git a/src/pathops/SkIntersections.h b/src/pathops/SkIntersections.h index abc10e19dd..d5d217cc80 100644 --- a/src/pathops/SkIntersections.h +++ b/src/pathops/SkIntersections.h @@ -104,7 +104,7 @@ public: } #ifdef SK_DEBUG - SkOpGlobalState* debugGlobalState() { return fDebugGlobalState; } + SkOpGlobalState* globalState() const { return fDebugGlobalState; } #endif bool hasT(double t) const { @@ -308,9 +308,9 @@ private: void cleanUpParallelLines(bool parallel); void computePoints(const SkDLine& line, int used); - SkDPoint fPt[12]; // FIXME: since scans store points as SkPoint, this should also + SkDPoint fPt[13]; // FIXME: since scans store points as SkPoint, this should also SkDPoint fPt2[2]; // used by nearly same to store alternate intersection point - double fT[2][12]; + double fT[2][13]; uint16_t fIsCoincident[2]; // bit set for each curve's coincident T bool fNearlySame[2]; // true if end points nearly match unsigned char fUsed; diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp index 99f93dd544..1223ac106e 100644 --- a/src/pathops/SkOpAngle.cpp +++ b/src/pathops/SkOpAngle.cpp @@ -152,7 +152,7 @@ bool SkOpAngle::after(SkOpAngle* test) { // FIXME : once this is verified to work, remove one opposite angle call SkDEBUGCODE(bool lrOpposite = lh->oppositePlanes(rh)); bool ltOpposite = lh->oppositePlanes(this); - SkASSERT(lrOpposite != ltOpposite); + SkOPASSERT(lrOpposite != ltOpposite); return COMPARE_RESULT(8, ltOpposite); } else if (ltOrder == 1 && trOrder == 0) { SkASSERT(lrOrder < 0); diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp index aa5f5bfba7..d16f6f8642 100755 --- a/src/pathops/SkOpCoincidence.cpp +++ b/src/pathops/SkOpCoincidence.cpp @@ -128,11 +128,12 @@ bool SkCoincidentSpans::contains(const SkOpPtT* s, const SkOpPtT* e) const { // A coincident span is unordered if the pairs of points in the main and opposite curves' // t values do not ascend or descend. For instance, if a tightly arced quadratic is // coincident with another curve, it may intersect it out of order. -bool SkCoincidentSpans::ordered() const { +bool SkCoincidentSpans::ordered(bool* result) const { const SkOpSpanBase* start = this->coinPtTStart()->span(); const SkOpSpanBase* end = this->coinPtTEnd()->span(); const SkOpSpanBase* next = start->upCast()->next(); if (next == end) { + *result = true; return true; } bool flipped = this->flipped(); @@ -141,21 +142,24 @@ bool SkCoincidentSpans::ordered() const { do { const SkOpPtT* opp = next->contains(oppSeg); if (!opp) { - SkASSERT(0); // may assert if coincident span isn't fully processed - continue; + SkOPOBJASSERT(start, 0); // may assert if coincident span isn't fully processed + return false; } if ((oppLastT > opp->fT) != flipped) { - return false; + *result = false; + return true; } oppLastT = opp->fT; if (next == end) { break; } if (!next->upCastable()) { - return false; + *result = false; + return true; } next = next->upCast()->next(); } while (true); + *result = true; return true; } @@ -234,7 +238,7 @@ void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o coinPtTEnd = coinPtTEnd->span()->ptT(); oppPtTStart = oppPtTStart->span()->ptT(); oppPtTEnd = oppPtTEnd->span()->ptT(); - SkASSERT(coinPtTStart->fT < coinPtTEnd->fT); + SkOPASSERT(coinPtTStart->fT < coinPtTEnd->fT); SkASSERT(oppPtTStart->fT != oppPtTEnd->fT); SkOPASSERT(!coinPtTStart->deleted()); SkOPASSERT(!coinPtTEnd->deleted()); @@ -754,7 +758,7 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { // save head so that walker can iterate over old data unperturbed // addifmissing adds to head freely then add saved head in the end const SkOpPtT* ocs = outer->coinPtTStart(); - SkASSERT(!ocs->deleted()); + FAIL_IF(ocs->deleted()); const SkOpSegment* outerCoin = ocs->segment(); SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list const SkOpPtT* oos = outer->oppPtTStart(); @@ -772,9 +776,9 @@ bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) { const SkOpPtT* ics = inner->coinPtTStart(); FAIL_IF(ics->deleted()); const SkOpSegment* innerCoin = ics->segment(); - SkASSERT(!innerCoin->done()); + FAIL_IF(innerCoin->done()); const SkOpPtT* ios = inner->oppPtTStart(); - SkASSERT(!ios->deleted()); + FAIL_IF(ios->deleted()); const SkOpSegment* innerOpp = ios->segment(); SkASSERT(!innerOpp->done()); SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin); @@ -855,9 +859,11 @@ bool SkOpCoincidence::addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg } const SkOpPtT* s2 = overS->find(seg2); const SkOpPtT* e2 = overE->find(seg2); + FAIL_IF(!e2); if (!s2->starter(e2)->span()->upCast()->windValue()) { s2 = overS->find(seg2o); e2 = overE->find(seg2o); + FAIL_IF(!s2); if (!s2->starter(e2)->span()->upCast()->windValue()) { return true; } @@ -956,11 +962,11 @@ void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { } // walk span sets in parallel, moving winding from one to the other -void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { +bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { DEBUG_SET_PHASE(); SkCoincidentSpans* coin = fHead; if (!coin) { - return; + return true; } do { SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); @@ -1055,6 +1061,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { #endif start->setWindValue(windValue); start->setOppValue(oppValue); + FAIL_IF(oWindValue == -1); oStart->setWindValue(oWindValue); oStart->setOppValue(oOppValue); if (!windValue && !oppValue) { @@ -1076,6 +1083,7 @@ void SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { oStart = oNext->upCast(); } while (true); } while ((coin = coin->next())); + return true; } // Please keep this in sync with debugRelease() @@ -1272,7 +1280,7 @@ bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { SkOpSpanBase* startBase = coin->coinPtTStartWritable()->span(); FAIL_IF(!startBase->upCastable()); SkOpSpan* start = startBase->upCast(); - SkASSERT(!start->deleted()); + FAIL_IF(start->deleted()); SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); SkOPASSERT(!end->deleted()); SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); @@ -1291,7 +1299,8 @@ bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) { const SkOpSegment* oSegment = oStart->segment(); SkOpSpanBase* next = start; SkOpSpanBase* oNext = oStart; - bool ordered = coin->ordered(); + bool ordered; + FAIL_IF(!coin->ordered(&ordered)); while ((next = next->upCast()->next()) != end) { FAIL_IF(!next->upCastable()); SkAssertResult(next->upCast()->insertCoincidence(oSegment, flipped, ordered)); diff --git a/src/pathops/SkOpCoincidence.h b/src/pathops/SkOpCoincidence.h index e2188bebbd..af84870253 100644 --- a/src/pathops/SkOpCoincidence.h +++ b/src/pathops/SkOpCoincidence.h @@ -73,7 +73,7 @@ public: // to a new span pair SkOpPtT* oppPtTStartWritable() const { return const_cast<SkOpPtT*>(fOppPtTStart); } SkOpPtT* oppPtTEndWritable() const { return const_cast<SkOpPtT*>(fOppPtTEnd); } - bool ordered() const; + bool ordered(bool* result) const; void set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); @@ -108,7 +108,7 @@ public: } void setOppPtTStart(const SkOpPtT* ptT) { - SkASSERT(ptT == ptT->span()->ptT()); + SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fOppPtTEnd || ptT->fT != fOppPtTEnd->fT); SkASSERT(!fOppPtTEnd || fOppPtTEnd->segment() == ptT->segment()); fOppPtTStart = ptT; @@ -150,7 +150,7 @@ public: bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()); - void apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()); + bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const; void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()); diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp index 6012d832bf..439392fc4f 100644 --- a/src/pathops/SkOpSegment.cpp +++ b/src/pathops/SkOpSegment.cpp @@ -169,18 +169,18 @@ bool SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end, path->deferredMove(start->ptT()); switch (verb) { case SkPath::kLine_Verb: - path->deferredLine(end->ptT()); + FAIL_IF(!path->deferredLine(end->ptT())); break; case SkPath::kQuad_Verb: - path->quadTo(curvePart.fCurve.fQuad.fPts[1].asSkPoint(), end->ptT()); + path->quadTo(curvePart.fCurve.fQuad[1].asSkPoint(), end->ptT()); break; case SkPath::kConic_Verb: - path->conicTo(curvePart.fCurve.fConic.fPts[1].asSkPoint(), end->ptT(), + path->conicTo(curvePart.fCurve.fConic[1].asSkPoint(), end->ptT(), curvePart.fCurve.fConic.fWeight); break; case SkPath::kCubic_Verb: - path->cubicTo(curvePart.fCurve.fCubic.fPts[1].asSkPoint(), - curvePart.fCurve.fCubic.fPts[2].asSkPoint(), end->ptT()); + path->cubicTo(curvePart.fCurve.fCubic[1].asSkPoint(), + curvePart.fCurve.fCubic[2].asSkPoint(), end->ptT()); break; default: SkASSERT(0); @@ -225,6 +225,7 @@ bool SkOpSegment::addExpanded(double newT, const SkOpSpanBase* test, bool* start return true; } this->globalState()->resetAllocatedOpSpan(); + FAIL_IF(!between(0, newT, 1)); SkOpPtT* newPtT = this->addT(newT); *startOver |= this->globalState()->allocatedOpSpan(); if (!newPtT) { diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp index a1cd7bbd63..7387249904 100644 --- a/src/pathops/SkPathOpsCommon.cpp +++ b/src/pathops/SkPathOpsCommon.cpp @@ -318,7 +318,9 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc do { SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps; // adjust the winding value to account for coincident edges - pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch)); + if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) { + return false; + } // For each coincident pair that overlaps another, when the receivers (the 1st of the pair) // are different, construct a new pair to resolve their mutual span if (!pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) { diff --git a/src/pathops/SkPathOpsConic.cpp b/src/pathops/SkPathOpsConic.cpp index dd523211de..82f3a7b0cc 100644 --- a/src/pathops/SkPathOpsConic.cpp +++ b/src/pathops/SkPathOpsConic.cpp @@ -156,7 +156,8 @@ SkDConic SkDConic::subDivide(double t1, double t2) const { double bx = 2 * dx - (ax + cx) / 2; double by = 2 * dy - (ay + cy) / 2; double bz = 2 * dz - (az + cz) / 2; - SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}}}, + SkDConic dst = {{{{ax / az, ay / az}, {bx / bz, by / bz}, {cx / cz, cy / cz}} + SkDEBUGPARAMS(fPts.fDebugGlobalState) }, SkDoubleToScalar(bz / sqrt(az * cz)) }; return dst; } diff --git a/src/pathops/SkPathOpsConic.h b/src/pathops/SkPathOpsConic.h index 4cbe147b49..42362797a2 100644 --- a/src/pathops/SkPathOpsConic.h +++ b/src/pathops/SkPathOpsConic.h @@ -31,15 +31,23 @@ struct SkDConic { fPts.debugInit(); } + void debugSet(const SkDPoint* pts, SkScalar weight); + SkDConic flip() const { - SkDConic result = {{{fPts[2], fPts[1], fPts[0]}}, fWeight}; + SkDConic result = {{{fPts[2], fPts[1], fPts[0]} + SkDEBUGPARAMS(fPts.fDebugGlobalState) }, fWeight}; return result; } +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fPts.globalState(); } +#endif + static bool IsConic() { return true; } - const SkDConic& set(const SkPoint pts[kPointCount], SkScalar weight) { - fPts.set(pts); + const SkDConic& set(const SkPoint pts[kPointCount], SkScalar weight + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { + fPts.set(pts SkDEBUGPARAMS(state)); fWeight = weight; return *this; } @@ -117,6 +125,7 @@ struct SkDConic { void dump() const; void dumpID(int id) const; void dumpInner() const; + }; diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp index bdae492de0..eaf9062476 100644 --- a/src/pathops/SkPathOpsCubic.cpp +++ b/src/pathops/SkPathOpsCubic.cpp @@ -36,7 +36,7 @@ double SkDCubic::binarySearch(double min, double max, double axisIntercept, double calcDist = calcPos - axisIntercept; do { double priorT = t - step; - SkASSERT(priorT >= min); + SkOPASSERT(priorT >= min); SkDPoint lessPt = ptAtT(priorT); if (approximately_equal_half(lessPt.fX, cubicAtT.fX) && approximately_equal_half(lessPt.fY, cubicAtT.fY)) { diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h index 16bca79533..f868fbe2c7 100644 --- a/src/pathops/SkPathOpsCubic.h +++ b/src/pathops/SkPathOpsCubic.h @@ -58,6 +58,8 @@ struct SkDCubic { sk_bzero(fPts, sizeof(fPts)); } + void debugSet(const SkDPoint* pts); + void dump() const; // callable from the debugger when the implementation code is linked in void dumpID(int id) const; void dumpInner() const; @@ -72,6 +74,11 @@ struct SkDCubic { } int findMaxCurvature(double tValues[]) const; + +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fDebugGlobalState; } +#endif + bool hullIntersects(const SkDCubic& c2, bool* isLinear) const; bool hullIntersects(const SkDConic& c, bool* isLinear) const; bool hullIntersects(const SkDQuad& c2, bool* isLinear) const; @@ -98,11 +105,14 @@ struct SkDCubic { */ int verticalIntersect(double xIntercept, double roots[3]) const; - const SkDCubic& set(const SkPoint pts[kPointCount]) { +// add debug only global pointer so asserts can be skipped by fuzzers + const SkDCubic& set(const SkPoint pts[kPointCount] + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { fPts[0] = pts[0]; fPts[1] = pts[1]; fPts[2] = pts[2]; fPts[3] = pts[3]; + SkDEBUGCODE(fDebugGlobalState = state); return *this; } @@ -125,8 +135,8 @@ struct SkDCubic { SkDQuad toQuad() const; static const int gPrecisionUnit; - SkDPoint fPts[kPointCount]; + SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); }; /* Given the set [0, 1, 2, 3], and two of the four members, compute an XOR mask diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp index a0fcff58e0..476fafb425 100644 --- a/src/pathops/SkPathOpsDebug.cpp +++ b/src/pathops/SkPathOpsDebug.cpp @@ -691,8 +691,8 @@ void SkIntersections::debugResetLoopCount() { } #endif +#include "SkPathOpsConic.h" #include "SkPathOpsCubic.h" -#include "SkPathOpsQuad.h" SkDCubic SkDQuad::debugToCubic() const { SkDCubic cubic; @@ -706,6 +706,21 @@ SkDCubic SkDQuad::debugToCubic() const { return cubic; } +void SkDQuad::debugSet(const SkDPoint* pts) { + memcpy(fPts, pts, sizeof(fPts)); + SkDEBUGCODE(fDebugGlobalState = nullptr); +} + +void SkDCubic::debugSet(const SkDPoint* pts) { + memcpy(fPts, pts, sizeof(fPts)); + SkDEBUGCODE(fDebugGlobalState = nullptr); +} + +void SkDConic::debugSet(const SkDPoint* pts, SkScalar weight) { + fPts.debugSet(pts); + fWeight = weight; +} + void SkDRect::debugInit() { fLeft = fTop = fRight = fBottom = SK_ScalarNaN; } @@ -1595,6 +1610,7 @@ void SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) cons // for each coincident pair, match the spans // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { +// DEBUG_SET_PHASE(); const SkCoincidentSpans* coin = this->fHead; if (!coin) { return; @@ -1639,14 +1655,15 @@ void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { walk = walk->upCast()->next(); } while (!(walkOpp = walk->ptT()->contains(oSeg)) && walk != coin->coinPtTEnd()->span()); + FAIL_IF(!walkOpp, coin); nextT = walk->t(); oNextT = walkOpp->fT; } // use t ranges to guess which one is missing - double startRange = coin->coinPtTEnd()->fT - startPtT->fT; + double startRange = nextT - priorT; FAIL_IF(!startRange, coin); - double startPart = (test->t() - startPtT->fT) / startRange; - double oStartRange = coin->oppPtTEnd()->fT - oStartPtT->fT; + double startPart = (test->t() - priorT) / startRange; + double oStartRange = oNextT - oPriorT; FAIL_IF(!oStartRange, coin); double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; FAIL_IF(startPart == oStartPart, coin); @@ -2029,7 +2046,8 @@ void SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog* log) const { const SkOpSegment* oSegment = oStart->segment(); const SkOpSpanBase* next = start; const SkOpSpanBase* oNext = oStart; - bool ordered = coin->ordered(); + bool ordered; + FAIL_IF(!coin->ordered(&ordered), coin); while ((next = next->upCast()->next()) != end) { FAIL_IF(!next->upCastable(), coin); if (next->upCast()->debugInsertCoincidence(log, oSegment, flipped, ordered), false) { diff --git a/src/pathops/SkPathOpsQuad.h b/src/pathops/SkPathOpsQuad.h index 32cfe58ecf..34740d6b1d 100644 --- a/src/pathops/SkPathOpsQuad.h +++ b/src/pathops/SkPathOpsQuad.h @@ -40,17 +40,21 @@ struct SkDQuad { sk_bzero(fPts, sizeof(fPts)); } + void debugSet(const SkDPoint* pts); + SkDQuad flip() const { - SkDQuad result = {{fPts[2], fPts[1], fPts[0]}}; + SkDQuad result = {{fPts[2], fPts[1], fPts[0]} SkDEBUGPARAMS(fDebugGlobalState) }; return result; } static bool IsConic() { return false; } - const SkDQuad& set(const SkPoint pts[kPointCount]) { + const SkDQuad& set(const SkPoint pts[kPointCount] + SkDEBUGPARAMS(SkOpGlobalState* state = nullptr)) { fPts[0] = pts[0]; fPts[1] = pts[1]; fPts[2] = pts[2]; + SkDEBUGCODE(fDebugGlobalState = state); return *this; } @@ -63,6 +67,10 @@ struct SkDQuad { SkDVector dxdyAtT(double t) const; static int FindExtrema(const double src[], double tValue[1]); +#ifdef SK_DEBUG + SkOpGlobalState* globalState() const { return fDebugGlobalState; } +#endif + /** * Return the number of valid roots (0 < root < 1) for this cubic intersecting the * specified horizontal line. @@ -106,8 +114,7 @@ struct SkDQuad { void dumpID(int id) const; void dumpInner() const; -private: -// static double Tangent(const double* quadratic, double t); // uncalled + SkDEBUGCODE(SkOpGlobalState* fDebugGlobalState); }; #endif diff --git a/src/pathops/SkPathOpsRect.h b/src/pathops/SkPathOpsRect.h index d4e5f5489a..1efbb8c6ea 100644 --- a/src/pathops/SkPathOpsRect.h +++ b/src/pathops/SkPathOpsRect.h @@ -64,6 +64,10 @@ struct SkDRect { } void setBounds(const SkDQuad& curve, const SkDQuad& sub, double tStart, double tEnd); + + bool valid() const { + return fLeft <= fRight && fTop <= fBottom; + } }; #endif diff --git a/src/pathops/SkPathOpsTSect.cpp b/src/pathops/SkPathOpsTSect.cpp index 3e7817ca9e..9bff5af4f0 100644 --- a/src/pathops/SkPathOpsTSect.cpp +++ b/src/pathops/SkPathOpsTSect.cpp @@ -9,54 +9,54 @@ int SkIntersections::intersect(const SkDQuad& quad1, const SkDQuad& quad2) { SkTSect<SkDQuad, SkDQuad> sect1(quad1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDQuad, SkDQuad> sect2(quad2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDQuad, SkDQuad>::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDConic& conic, const SkDQuad& quad) { SkTSect<SkDConic, SkDQuad> sect1(conic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDQuad, SkDConic> sect2(quad - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDConic, SkDQuad>::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDConic& conic1, const SkDConic& conic2) { SkTSect<SkDConic, SkDConic> sect1(conic1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDConic, SkDConic> sect2(conic2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDConic, SkDConic>::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic, const SkDQuad& quad) { SkTSect<SkDCubic, SkDQuad> sect1(cubic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDQuad, SkDCubic> sect2(quad - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDCubic, SkDQuad>::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic, const SkDConic& conic) { SkTSect<SkDCubic, SkDConic> sect1(cubic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDConic, SkDCubic> sect2(conic - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDCubic, SkDConic>::BinarySearch(§1, §2, this); return used(); } int SkIntersections::intersect(const SkDCubic& cubic1, const SkDCubic& cubic2) { SkTSect<SkDCubic, SkDCubic> sect1(cubic1 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(1)); SkTSect<SkDCubic, SkDCubic> sect2(cubic2 - SkDEBUGPARAMS(debugGlobalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); + SkDEBUGPARAMS(globalState()) PATH_OPS_DEBUG_T_SECT_PARAMS(2)); SkTSect<SkDCubic, SkDCubic>::BinarySearch(§1, §2, this); return used(); } diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h index f22322bbe1..51ea44a26c 100644 --- a/src/pathops/SkPathOpsTSect.h +++ b/src/pathops/SkPathOpsTSect.h @@ -137,7 +137,7 @@ public: int hullsIntersect(SkTSpan<OppCurve, TCurve>* span, bool* start, bool* oppStart); void init(const TCurve& ); - void initBounds(const TCurve& ); + bool initBounds(const TCurve& ); bool isBounded() const { return fBounded != nullptr; @@ -317,7 +317,7 @@ private: void removeSpans(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); SkTSpan<TCurve, OppCurve>* spanAtT(double t, SkTSpan<TCurve, OppCurve>** priorSpan); SkTSpan<TCurve, OppCurve>* tail(); - void trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); + bool trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); void unlinkSpan(SkTSpan<TCurve, OppCurve>* span); bool updateBounded(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, SkTSpan<OppCurve, TCurve>* oppFirst); @@ -351,7 +351,7 @@ void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& c2) { SkDVector dxdy = c1.dxdyAtT(t); SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; - SkIntersections i; + SkIntersections i SkDEBUGCODE((c1.globalState())); int used = i.intersectRay(c2, perp); // only keep closest if (used == 0 || used == 3) { @@ -565,7 +565,7 @@ void SkTSpan<TCurve, OppCurve>::init(const TCurve& c) { } template<typename TCurve, typename OppCurve> -void SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { +bool SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { fPart = c.subDivide(fStartT, fEndT); fBounds.setBounds(fPart); fCoinStart.init(); @@ -579,6 +579,7 @@ void SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { SkDebugf(""); // for convenient breakpoints } #endif + return fBounds.valid(); } template<typename TCurve, typename OppCurve> @@ -1206,6 +1207,7 @@ bool SkTSect<TCurve, OppCurve>::extractCoincident( } } else { SkDEBUGCODE(coinStart = first->fStartT); + FAIL_IF(!oppFirst); SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT); } // FIXME: incomplete : if we're not at the end, find end of coin @@ -1286,7 +1288,7 @@ SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun( work->validatePerpT(work->fCoinStart.perpT()); work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt()); #endif - SkASSERT(work->hasOppT(work->fCoinStart.perpT())); + SkOPASSERT(work->hasOppT(work->fCoinStart.perpT())); if (!work->fCoinEnd.isMatch()) { break; } @@ -1400,7 +1402,8 @@ template<typename TCurve, typename OppCurve> int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { - SkIntersections thisRayI, oppRayI; + SkIntersections thisRayI SkDEBUGCODE((span->fDebugGlobalState)); + SkIntersections oppRayI SkDEBUGCODE((span->fDebugGlobalState)); SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }}; int loopCount = 0; @@ -1810,9 +1813,9 @@ SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::tail() { /* Each span has a range of opposite spans it intersects. After the span is split in two, adjust the range to its new size */ template<typename TCurve, typename OppCurve> -void SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, +bool SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp) { - span->initBounds(fCurve); + FAIL_IF(!span->initBounds(fCurve)); const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; while (testBounded) { SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; @@ -1826,7 +1829,7 @@ void SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, if (sects == 2) { span->initBounds(fCurve); this->removeAllBut(test, span, opp); - return; + return true; } } else { if (span->removeBounded(test)) { @@ -1838,6 +1841,7 @@ void SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, } testBounded = next; } + return true; } template<typename TCurve, typename OppCurve> @@ -2112,7 +2116,7 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, SkDEBUGCODE(sect1->fOppSect = sect2); SkDEBUGCODE(sect2->fOppSect = sect1); intersections->reset(); - intersections->setMax(TCurve::kMaxIntersections + 3); // give extra for slop + intersections->setMax(TCurve::kMaxIntersections + 4); // give extra for slop SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead; SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead; int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); @@ -2151,8 +2155,14 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, if (!half1->split(largest1, §1->fHeap)) { break; } - sect1->trim(largest1, sect2); - sect1->trim(half1, sect2); + if (!sect1->trim(largest1, sect2)) { + SkOPOBJASSERT(intersections, 0); + return; + } + if (!sect1->trim(half1, sect2)) { + SkOPOBJASSERT(intersections, 0); + return; + } } else { if (largest2->fCollapsed) { break; @@ -2163,8 +2173,14 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, if (!half2->split(largest2, §2->fHeap)) { break; } - sect2->trim(largest2, sect1); - sect2->trim(half2, sect1); + if (!sect2->trim(largest2, sect1)) { + SkOPOBJASSERT(intersections, 0); + return; + } + if (!sect2->trim(half2, sect1)) { + SkOPOBJASSERT(intersections, 0); + return; + } } sect1->validate(); sect2->validate(); @@ -2250,28 +2266,28 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, // if the final iteration contains an end (0 or 1), if (sect1->fRemovedStartT && !(zeroOneSet & kZeroS1Set)) { SkTCoincident<TCurve, OppCurve> perp; // intersect perpendicular with opposite curve - perp.setPerp(sect1->fCurve, 0, sect1->fCurve.fPts[0], sect2->fCurve); + perp.setPerp(sect1->fCurve, 0, sect1->fCurve[0], sect2->fCurve); if (perp.isMatch()) { intersections->insert(0, perp.perpT(), perp.perpPt()); } } if (sect1->fRemovedEndT && !(zeroOneSet & kOneS1Set)) { SkTCoincident<TCurve, OppCurve> perp; - perp.setPerp(sect1->fCurve, 1, sect1->fCurve.fPts[TCurve::kPointLast], sect2->fCurve); + perp.setPerp(sect1->fCurve, 1, sect1->fCurve[TCurve::kPointLast], sect2->fCurve); if (perp.isMatch()) { intersections->insert(1, perp.perpT(), perp.perpPt()); } } if (sect2->fRemovedStartT && !(zeroOneSet & kZeroS2Set)) { SkTCoincident<OppCurve, TCurve> perp; - perp.setPerp(sect2->fCurve, 0, sect2->fCurve.fPts[0], sect1->fCurve); + perp.setPerp(sect2->fCurve, 0, sect2->fCurve[0], sect1->fCurve); if (perp.isMatch()) { intersections->insert(perp.perpT(), 0, perp.perpPt()); } } if (sect2->fRemovedEndT && !(zeroOneSet & kOneS2Set)) { SkTCoincident<OppCurve, TCurve> perp; - perp.setPerp(sect2->fCurve, 1, sect2->fCurve.fPts[OppCurve::kPointLast], sect1->fCurve); + perp.setPerp(sect2->fCurve, 1, sect2->fCurve[OppCurve::kPointLast], sect1->fCurve); if (perp.isMatch()) { intersections->insert(perp.perpT(), 1, perp.perpPt()); } @@ -2365,7 +2381,7 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, } intersections->setCoincident(index); } - SkASSERT(intersections->used() <= TCurve::kMaxIntersections); + SkOPOBJASSERT(intersections, intersections->used() <= TCurve::kMaxIntersections); } #endif diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h index 786eb2288e..e390b4b2b1 100644 --- a/src/pathops/SkPathOpsTypes.h +++ b/src/pathops/SkPathOpsTypes.h @@ -221,8 +221,8 @@ private: #define SkOPASSERT(cond) SkASSERT((this->globalState() && \ this->globalState()->debugSkipAssert()) || (cond)) #endif -#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->debugGlobalState() && \ - obj->debugGlobalState()->debugSkipAssert()) || (cond)) +#define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \ + obj->globalState()->debugSkipAssert()) || (cond)) #else #define SkOPASSERT(cond) #define SkOPOBJASSERT(obj, cond) diff --git a/src/pathops/SkPathWriter.cpp b/src/pathops/SkPathWriter.cpp index 1f6dddd137..c94809e8ec 100644 --- a/src/pathops/SkPathWriter.cpp +++ b/src/pathops/SkPathWriter.cpp @@ -48,23 +48,26 @@ void SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkOpPtT fCurrent.cubicTo(pt1, pt2, pt3->fPt); } -void SkPathWriter::deferredLine(const SkOpPtT* pt) { +bool SkPathWriter::deferredLine(const SkOpPtT* pt) { SkASSERT(fFirstPtT); SkASSERT(fDefer[0]); if (fDefer[0] == pt) { // FIXME: why we're adding a degenerate line? Caller should have preflighted this. - return; + return true; } if (pt->contains(fDefer[0])) { // FIXME: why we're adding a degenerate line? - return; + return true; + } + if (this->matchedLast(pt)) { + return false; } - SkASSERT(!this->matchedLast(pt)); if (fDefer[1] && this->changedSlopes(pt)) { this->lineTo(); fDefer[0] = fDefer[1]; } fDefer[1] = pt; + return true; } void SkPathWriter::deferredMove(const SkOpPtT* pt) { diff --git a/src/pathops/SkPathWriter.h b/src/pathops/SkPathWriter.h index bd13c718a9..5dd1bf6f60 100644 --- a/src/pathops/SkPathWriter.h +++ b/src/pathops/SkPathWriter.h @@ -23,7 +23,7 @@ public: void assemble(); void conicTo(const SkPoint& pt1, const SkOpPtT* pt2, SkScalar weight); void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkOpPtT* pt3); - void deferredLine(const SkOpPtT* pt); + bool deferredLine(const SkOpPtT* pt); void deferredMove(const SkOpPtT* pt); void finishContour(); bool hasMove() const { return !fFirstPtT; } |