aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pathops
diff options
context:
space:
mode:
Diffstat (limited to 'src/pathops')
-rw-r--r--src/pathops/SkAddIntersections.cpp12
-rw-r--r--src/pathops/SkDConicLineIntersection.cpp4
-rw-r--r--src/pathops/SkDCubicLineIntersection.cpp1
-rw-r--r--src/pathops/SkDLineIntersection.cpp2
-rw-r--r--src/pathops/SkIntersections.h6
-rw-r--r--src/pathops/SkOpAngle.cpp2
-rwxr-xr-xsrc/pathops/SkOpCoincidence.cpp35
-rw-r--r--src/pathops/SkOpCoincidence.h6
-rw-r--r--src/pathops/SkOpSegment.cpp11
-rw-r--r--src/pathops/SkPathOpsCommon.cpp4
-rw-r--r--src/pathops/SkPathOpsConic.cpp3
-rw-r--r--src/pathops/SkPathOpsConic.h15
-rw-r--r--src/pathops/SkPathOpsCubic.cpp2
-rw-r--r--src/pathops/SkPathOpsCubic.h14
-rw-r--r--src/pathops/SkPathOpsDebug.cpp28
-rw-r--r--src/pathops/SkPathOpsQuad.h15
-rw-r--r--src/pathops/SkPathOpsRect.h4
-rw-r--r--src/pathops/SkPathOpsTSect.cpp24
-rw-r--r--src/pathops/SkPathOpsTSect.h54
-rw-r--r--src/pathops/SkPathOpsTypes.h4
-rw-r--r--src/pathops/SkPathWriter.cpp11
-rw-r--r--src/pathops/SkPathWriter.h2
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(&sect1, &sect2, 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(&sect1, &sect2, 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(&sect1, &sect2, 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(&sect1, &sect2, 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(&sect1, &sect2, 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(&sect1, &sect2, 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, &sect1->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, &sect2->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; }