| Index: src/pathops/SkOpEdgeBuilder.cpp
|
| diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
|
| index d7f52752bf07f00cb4e5b5a52851eb7213f8ff81..5187b5f1e66f69045039a223fe0bc8100d5e03da 100644
|
| --- a/src/pathops/SkOpEdgeBuilder.cpp
|
| +++ b/src/pathops/SkOpEdgeBuilder.cpp
|
| @@ -4,6 +4,7 @@
|
| * Use of this source code is governed by a BSD-style license that can be
|
| * found in the LICENSE file.
|
| */
|
| +#include "SkGeometry.h"
|
| #include "SkOpEdgeBuilder.h"
|
| #include "SkReduceOrder.h"
|
|
|
| @@ -37,70 +38,114 @@ bool SkOpEdgeBuilder::finish() {
|
| if (fCurrentContour && !fCurrentContour->segments().count()) {
|
| fContours.pop_back();
|
| }
|
| - // correct pointers in contours since fReducePts may have moved as it grew
|
| - int cIndex = 0;
|
| - int extraCount = fExtra.count();
|
| - SkASSERT(extraCount == 0 || fExtra[0] == -1);
|
| - int eIndex = 0;
|
| - int rIndex = 0;
|
| - while (++eIndex < extraCount) {
|
| - int offset = fExtra[eIndex];
|
| - if (offset < 0) {
|
| - ++cIndex;
|
| - continue;
|
| + return true;
|
| +}
|
| +
|
| +void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) {
|
| + if ((!AlmostEqualUlps(curveEnd.fX, curveStart.fX)
|
| + || !AlmostEqualUlps(curveEnd.fY, curveStart.fY))) {
|
| + fPathVerbs.push_back(SkPath::kLine_Verb);
|
| + fPathPts.push_back_n(1, &curveStart);
|
| + } else {
|
| + if (curveEnd.fX != curveStart.fX || curveEnd.fY != curveStart.fY) {
|
| + fPathPts[fPathPts.count() - 1] = curveStart;
|
| + } else {
|
| + fPathPts[fPathPts.count() - 1] = curveStart;
|
| }
|
| - fCurrentContour = &fContours[cIndex];
|
| - rIndex += fCurrentContour->updateSegment(offset - 1,
|
| - &fReducePts[rIndex]);
|
| }
|
| - fExtra.reset(); // we're done with this
|
| - return true;
|
| + fPathVerbs.push_back(SkPath::kClose_Verb);
|
| }
|
|
|
| -// Note that copying the points here avoids copying the resulting path later.
|
| -// To allow Op() to take one of the input paths as an output parameter, either the source data
|
| -// must be copied (as implemented below) or the result must be copied.
|
| -// OPTIMIZATION: This copies both sets of input points every time. If the input data was read
|
| -// directly, the output path would only need to be copied if it was also one of the input paths.
|
| int SkOpEdgeBuilder::preFetch() {
|
| if (!fPath->isFinite()) {
|
| fUnparseable = true;
|
| return 0;
|
| }
|
| + SkAutoConicToQuads quadder;
|
| + const SkScalar quadderTol = SK_Scalar1 / 16;
|
| SkPath::RawIter iter(*fPath);
|
| + SkPoint curveStart;
|
| + SkPoint curve[4];
|
| SkPoint pts[4];
|
| SkPath::Verb verb;
|
| + bool lastCurve = false;
|
| do {
|
| verb = iter.next(pts);
|
| - fPathVerbs.push_back(verb);
|
| - if (verb == SkPath::kMove_Verb) {
|
| - fPathPts.push_back(pts[0]);
|
| - } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
|
| - fPathPts.push_back_n(SkPathOpsVerbToPoints(verb), &pts[1]);
|
| + switch (verb) {
|
| + case SkPath::kMove_Verb:
|
| + if (!fAllowOpenContours && lastCurve) {
|
| + closeContour(curve[0], curveStart);
|
| + }
|
| + fPathVerbs.push_back(verb);
|
| + fPathPts.push_back(pts[0]);
|
| + curveStart = curve[0] = pts[0];
|
| + lastCurve = false;
|
| + continue;
|
| + case SkPath::kLine_Verb:
|
| + if (AlmostEqualUlps(curve[0].fX, pts[1].fX)
|
| + && AlmostEqualUlps(curve[0].fY, pts[1].fY)) {
|
| + continue; // skip degenerate points
|
| + }
|
| + break;
|
| + case SkPath::kQuad_Verb:
|
| + curve[1] = pts[1];
|
| + curve[2] = pts[2];
|
| + verb = SkReduceOrder::Quad(curve, pts);
|
| + if (verb == SkPath::kMove_Verb) {
|
| + continue; // skip degenerate points
|
| + }
|
| + break;
|
| + case SkPath::kConic_Verb: {
|
| + const SkPoint* quadPts = quadder.computeQuads(pts, iter.conicWeight(),
|
| + quadderTol);
|
| + const int nQuads = quadder.countQuads();
|
| + for (int i = 0; i < nQuads; ++i) {
|
| + fPathVerbs.push_back(SkPath::kQuad_Verb);
|
| + }
|
| + fPathPts.push_back_n(nQuads * 2, quadPts);
|
| + curve[0] = quadPts[nQuads * 2 - 1];
|
| + lastCurve = true;
|
| + }
|
| + continue;
|
| + case SkPath::kCubic_Verb:
|
| + curve[1] = pts[1];
|
| + curve[2] = pts[2];
|
| + curve[3] = pts[3];
|
| + verb = SkReduceOrder::Cubic(curve, pts);
|
| + if (verb == SkPath::kMove_Verb) {
|
| + continue; // skip degenerate points
|
| + }
|
| + break;
|
| + case SkPath::kClose_Verb:
|
| + closeContour(curve[0], curveStart);
|
| + lastCurve = false;
|
| + continue;
|
| + case SkPath::kDone_Verb:
|
| + continue;
|
| }
|
| + fPathVerbs.push_back(verb);
|
| + int ptCount = SkPathOpsVerbToPoints(verb);
|
| + fPathPts.push_back_n(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);
|
| return fPathVerbs.count() - 1;
|
| }
|
|
|
| bool SkOpEdgeBuilder::close() {
|
| - if (fFinalCurveStart && fFinalCurveEnd && *fFinalCurveStart != *fFinalCurveEnd) {
|
| - fReducePts.push_back(*fFinalCurveStart);
|
| - fReducePts.push_back(*fFinalCurveEnd);
|
| - const SkPoint* lineStart = fReducePts.end() - 2;
|
| - fExtra.push_back(fCurrentContour->addLine(lineStart));
|
| - }
|
| complete();
|
| return true;
|
| }
|
|
|
| bool SkOpEdgeBuilder::walk() {
|
| - SkPath::Verb reducedVerb;
|
| uint8_t* verbPtr = fPathVerbs.begin();
|
| uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
|
| - const SkPoint* pointsPtr = fPathPts.begin();
|
| + const SkPoint* pointsPtr = fPathPts.begin() - 1;
|
| SkPath::Verb verb;
|
| - fFinalCurveStart = NULL;
|
| - fFinalCurveEnd = NULL;
|
| while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
|
| if (verbPtr == endOfFirstHalf) {
|
| fOperand = true;
|
| @@ -119,49 +164,18 @@ bool SkOpEdgeBuilder::walk() {
|
| fCurrentContour = fContours.push_back_n(1);
|
| fCurrentContour->setOperand(fOperand);
|
| fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathOpsMask);
|
| - fExtra.push_back(-1); // start new contour
|
| }
|
| - fFinalCurveEnd = pointsPtr++;
|
| + pointsPtr += 1;
|
| continue;
|
| - case SkPath::kLine_Verb: {
|
| - const SkPoint& lineEnd = pointsPtr[0];
|
| - const SkPoint& lineStart = pointsPtr[-1];
|
| - // skip degenerate points
|
| - if (lineStart.fX != lineEnd.fX || lineStart.fY != lineEnd.fY) {
|
| - fCurrentContour->addLine(&lineStart);
|
| - }
|
| - } break;
|
| - case SkPath::kQuad_Verb: {
|
| - const SkPoint* quadStart = &pointsPtr[-1];
|
| - reducedVerb = SkReduceOrder::Quad(quadStart, &fReducePts);
|
| - if (reducedVerb == 0) {
|
| - break; // skip degenerate points
|
| - }
|
| - if (reducedVerb == SkPath::kLine_Verb) {
|
| - const SkPoint* lineStart = fReducePts.end() - 2;
|
| - fExtra.push_back(fCurrentContour->addLine(lineStart));
|
| - break;
|
| - }
|
| - fCurrentContour->addQuad(quadStart);
|
| - } break;
|
| - case SkPath::kCubic_Verb: {
|
| - const SkPoint* cubicStart = &pointsPtr[-1];
|
| - reducedVerb = SkReduceOrder::Cubic(cubicStart, &fReducePts);
|
| - if (reducedVerb == 0) {
|
| - break; // skip degenerate points
|
| - }
|
| - if (reducedVerb == SkPath::kLine_Verb) {
|
| - const SkPoint* lineStart = fReducePts.end() - 2;
|
| - fExtra.push_back(fCurrentContour->addLine(lineStart));
|
| - break;
|
| - }
|
| - if (reducedVerb == SkPath::kQuad_Verb) {
|
| - const SkPoint* quadStart = fReducePts.end() - 3;
|
| - fExtra.push_back(fCurrentContour->addQuad(quadStart));
|
| - break;
|
| - }
|
| - fCurrentContour->addCubic(cubicStart);
|
| - } break;
|
| + case SkPath::kLine_Verb:
|
| + fCurrentContour->addLine(pointsPtr);
|
| + break;
|
| + case SkPath::kQuad_Verb:
|
| + fCurrentContour->addQuad(pointsPtr);
|
| + break;
|
| + case SkPath::kCubic_Verb:
|
| + fCurrentContour->addCubic(pointsPtr);
|
| + break;
|
| case SkPath::kClose_Verb:
|
| SkASSERT(fCurrentContour);
|
| if (!close()) {
|
| @@ -172,7 +186,6 @@ bool SkOpEdgeBuilder::walk() {
|
| SkDEBUGFAIL("bad verb");
|
| return false;
|
| }
|
| - fFinalCurveStart = &pointsPtr[SkPathOpsVerbToPoints(verb) - 1];
|
| pointsPtr += SkPathOpsVerbToPoints(verb);
|
| SkASSERT(fCurrentContour);
|
| }
|
|
|