| Index: src/pathops/SkOpEdgeBuilder.cpp
|
| diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
|
| index 803a5f4739e238a5426cc7c4fec513cca1faf879..bd21d729b6ec1467c0c2b3fa2b9b445e2e1542fe 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,44 @@ 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 (size_t index = 0; index < SK_ARRAY_COUNT(curve1); ++index) {
|
| + force_small_to_zero(&curve1[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 +231,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;
|
|
|