Index: src/pathops/SkOpEdgeBuilder.cpp |
diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp |
index 803a5f4739e238a5426cc7c4fec513cca1faf879..e3dc1398655273d6236da70e086433c5d82d0bc8 100644 |
--- a/src/pathops/SkOpEdgeBuilder.cpp |
+++ b/src/pathops/SkOpEdgeBuilder.cpp |
@@ -9,7 +9,7 @@ |
#include "SkReduceOrder.h" |
void SkOpEdgeBuilder::init() { |
- fCurrentContour = NULL; |
+ fCurrentContour = fContoursHead; |
fOperand = false; |
fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask |
: kWinding_PathOpsMask; |
@@ -19,32 +19,43 @@ void SkOpEdgeBuilder::init() { |
void SkOpEdgeBuilder::addOperand(const SkPath& path) { |
SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb); |
- fPathVerbs.pop_back(); |
+ fPathVerbs.pop(); |
fPath = &path; |
fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask |
: kWinding_PathOpsMask; |
preFetch(); |
} |
-bool SkOpEdgeBuilder::finish() { |
- if (fUnparseable || !walk()) { |
+int SkOpEdgeBuilder::count() const { |
+ SkOpContour* contour = fContoursHead; |
+ int count = 0; |
+ while (contour) { |
+ count += contour->count() > 0; |
+ contour = contour->next(); |
+ } |
+ return count; |
+} |
+ |
+bool SkOpEdgeBuilder::finish(SkChunkAlloc* allocator) { |
+ fOperand = false; |
+ if (fUnparseable || !walk(allocator)) { |
return false; |
} |
complete(); |
- if (fCurrentContour && !fCurrentContour->segments().count()) { |
- fContours.pop_back(); |
+ if (fCurrentContour && !fCurrentContour->count()) { |
+ fContoursHead->remove(fCurrentContour); |
} |
return true; |
} |
void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) { |
if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) { |
- fPathVerbs.push_back(SkPath::kLine_Verb); |
- fPathPts.push_back_n(1, &curveStart); |
+ *fPathVerbs.append() = SkPath::kLine_Verb; |
+ *fPathPts.append() = curveStart; |
} else { |
fPathPts[fPathPts.count() - 1] = curveStart; |
} |
- fPathVerbs.push_back(SkPath::kClose_Verb); |
+ *fPathVerbs.append() = SkPath::kClose_Verb; |
} |
// very tiny points cause numerical instability : don't allow them |
@@ -57,7 +68,6 @@ static void force_small_to_zero(SkPoint* pt) { |
} |
} |
- |
int SkOpEdgeBuilder::preFetch() { |
if (!fPath->isFinite()) { |
fUnparseable = true; |
@@ -78,18 +88,18 @@ int SkOpEdgeBuilder::preFetch() { |
if (!fAllowOpenContours && lastCurve) { |
closeContour(curve[0], curveStart); |
} |
- fPathVerbs.push_back(verb); |
+ *fPathVerbs.append() = verb; |
force_small_to_zero(&pts[0]); |
- fPathPts.push_back(pts[0]); |
+ *fPathPts.append() = pts[0]; |
curveStart = curve[0] = pts[0]; |
lastCurve = false; |
continue; |
case SkPath::kLine_Verb: |
force_small_to_zero(&pts[1]); |
if (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) { |
- uint8_t lastVerb = fPathVerbs.back(); |
+ uint8_t lastVerb = fPathVerbs.top(); |
if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) { |
- fPathPts.back() = pts[1]; |
+ fPathPts.top() = pts[1]; |
} |
continue; // skip degenerate points |
} |
@@ -109,9 +119,9 @@ int SkOpEdgeBuilder::preFetch() { |
quadderTol); |
const int nQuads = quadder.countQuads(); |
for (int i = 0; i < nQuads; ++i) { |
- fPathVerbs.push_back(SkPath::kQuad_Verb); |
+ *fPathVerbs.append() = SkPath::kQuad_Verb; |
} |
- fPathPts.push_back_n(nQuads * 2, &quadPts[1]); |
+ fPathPts.append(nQuads * 2, &quadPts[1]); |
curve[0] = pts[2]; |
lastCurve = true; |
} |
@@ -135,16 +145,16 @@ int SkOpEdgeBuilder::preFetch() { |
case SkPath::kDone_Verb: |
continue; |
} |
- fPathVerbs.push_back(verb); |
+ *fPathVerbs.append() = verb; |
int ptCount = SkPathOpsVerbToPoints(verb); |
- fPathPts.push_back_n(ptCount, &pts[1]); |
+ fPathPts.append(ptCount, &pts[1]); |
curve[0] = pts[ptCount]; |
lastCurve = true; |
} while (verb != SkPath::kDone_Verb); |
if (!fAllowOpenContours && lastCurve) { |
closeContour(curve[0], curveStart); |
} |
- fPathVerbs.push_back(SkPath::kDone_Verb); |
+ *fPathVerbs.append() = SkPath::kDone_Verb; |
return fPathVerbs.count() - 1; |
} |
@@ -153,10 +163,10 @@ bool SkOpEdgeBuilder::close() { |
return true; |
} |
-bool SkOpEdgeBuilder::walk() { |
+bool SkOpEdgeBuilder::walk(SkChunkAlloc* allocator) { |
uint8_t* verbPtr = fPathVerbs.begin(); |
uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; |
- const SkPoint* pointsPtr = fPathPts.begin() - 1; |
+ SkPoint* pointsPtr = fPathPts.begin() - 1; |
SkPath::Verb verb; |
while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { |
if (verbPtr == endOfFirstHalf) { |
@@ -165,7 +175,7 @@ bool SkOpEdgeBuilder::walk() { |
verbPtr++; |
switch (verb) { |
case SkPath::kMove_Verb: |
- if (fCurrentContour) { |
+ if (fCurrentContour && fCurrentContour->count()) { |
if (fAllowOpenContours) { |
complete(); |
} else if (!close()) { |
@@ -173,21 +183,46 @@ bool SkOpEdgeBuilder::walk() { |
} |
} |
if (!fCurrentContour) { |
- fCurrentContour = fContours.push_back_n(1); |
- fCurrentContour->setOperand(fOperand); |
- fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathOpsMask); |
+ fCurrentContour = fContoursHead->appendContour(allocator); |
} |
+ fCurrentContour->init(fGlobalState, fOperand, |
+ fXorMask[fOperand] == kEvenOdd_PathOpsMask); |
pointsPtr += 1; |
continue; |
case SkPath::kLine_Verb: |
- fCurrentContour->addLine(pointsPtr); |
+ fCurrentContour->addLine(pointsPtr, fAllocator); |
break; |
case SkPath::kQuad_Verb: |
- fCurrentContour->addQuad(pointsPtr); |
- break; |
- case SkPath::kCubic_Verb: |
- fCurrentContour->addCubic(pointsPtr); |
+ fCurrentContour->addQuad(pointsPtr, fAllocator); |
break; |
+ case SkPath::kCubic_Verb: { |
+ // split self-intersecting cubics in two before proceeding |
+ // if the cubic is convex, it doesn't self intersect. |
+ SkScalar loopT; |
+ if (SkDCubic::ComplexBreak(pointsPtr, &loopT)) { |
+ SkPoint cubicPair[7]; |
+ SkChopCubicAt(pointsPtr, cubicPair, loopT); |
+ SkPoint cStorage[2][4]; |
+ SkPath::Verb v1 = SkReduceOrder::Cubic(&cubicPair[0], cStorage[0]); |
+ SkPath::Verb v2 = SkReduceOrder::Cubic(&cubicPair[3], cStorage[1]); |
+ if (v1 != SkPath::kMove_Verb && v2 != SkPath::kMove_Verb) { |
+ SkPoint* curve1 = v1 == SkPath::kCubic_Verb ? &cubicPair[0] : cStorage[0]; |
+ SkPoint* curve2 = v2 == SkPath::kCubic_Verb ? &cubicPair[3] : cStorage[1]; |
+ for (int index = 0; index < SkPathOpsVerbToPoints(v1); ++index) { |
+ force_small_to_zero(&curve1[index]); |
+ } |
+ for (int index = 0; index < SkPathOpsVerbToPoints(v2); ++index) { |
+ force_small_to_zero(&curve2[index]); |
+ } |
+ fCurrentContour->addCurve(v1, curve1, fAllocator); |
+ fCurrentContour->addCurve(v2, curve2, fAllocator); |
+ } else { |
+ fCurrentContour->addCubic(pointsPtr, fAllocator); |
+ } |
+ } else { |
+ fCurrentContour->addCubic(pointsPtr, fAllocator); |
+ } |
+ } break; |
case SkPath::kClose_Verb: |
SkASSERT(fCurrentContour); |
if (!close()) { |
@@ -198,10 +233,11 @@ bool SkOpEdgeBuilder::walk() { |
SkDEBUGFAIL("bad verb"); |
return false; |
} |
- pointsPtr += SkPathOpsVerbToPoints(verb); |
SkASSERT(fCurrentContour); |
+ fCurrentContour->debugValidate(); |
+ pointsPtr += SkPathOpsVerbToPoints(verb); |
} |
- if (fCurrentContour && !fAllowOpenContours && !close()) { |
+ if (fCurrentContour && fCurrentContour->count() &&!fAllowOpenContours && !close()) { |
return false; |
} |
return true; |