diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/pathops/SkOpEdgeBuilder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/pathops/SkOpEdgeBuilder.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,194 @@ +/* + * Copyright 2012 Google Inc. + * + * 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" + +void SkOpEdgeBuilder::init() { + fCurrentContour = NULL; + fOperand = false; + fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask + : kWinding_PathOpsMask; +#ifdef SK_DEBUG + SkPathOpsDebug::gContourID = 0; + SkPathOpsDebug::gSegmentID = 0; +#endif + fUnparseable = false; + fSecondHalf = preFetch(); +} + +void SkOpEdgeBuilder::addOperand(const SkPath& path) { + SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb); + fPathVerbs.pop_back(); + fPath = &path; + fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask + : kWinding_PathOpsMask; + preFetch(); +} + +bool SkOpEdgeBuilder::finish() { + if (fUnparseable || !walk()) { + return false; + } + complete(); + if (fCurrentContour && !fCurrentContour->segments().count()) { + fContours.pop_back(); + } + 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); + } else { + fPathPts[fPathPts.count() - 1] = curveStart; + } + fPathVerbs.push_back(SkPath::kClose_Verb); +} + +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); + 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 (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) { + uint8_t lastVerb = fPathVerbs.back(); + if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) { + fPathPts.back() = pts[1]; + } + 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() { + complete(); + return true; +} + +bool SkOpEdgeBuilder::walk() { + uint8_t* verbPtr = fPathVerbs.begin(); + uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; + const SkPoint* pointsPtr = fPathPts.begin() - 1; + SkPath::Verb verb; + while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { + if (verbPtr == endOfFirstHalf) { + fOperand = true; + } + verbPtr++; + switch (verb) { + case SkPath::kMove_Verb: + if (fCurrentContour) { + if (fAllowOpenContours) { + complete(); + } else if (!close()) { + return false; + } + } + if (!fCurrentContour) { + fCurrentContour = fContours.push_back_n(1); + fCurrentContour->setOperand(fOperand); + fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathOpsMask); + } + pointsPtr += 1; + continue; + 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()) { + return false; + } + continue; + default: + SkDEBUGFAIL("bad verb"); + return false; + } + pointsPtr += SkPathOpsVerbToPoints(verb); + SkASSERT(fCurrentContour); + } + if (fCurrentContour && !fAllowOpenContours && !close()) { + return false; + } + return true; +}