| Index: src/pathops/SkOpSegment.h
|
| ===================================================================
|
| --- src/pathops/SkOpSegment.h (revision 0)
|
| +++ src/pathops/SkOpSegment.h (revision 0)
|
| @@ -0,0 +1,410 @@
|
| +/*
|
| + * Copyright 2012 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +#ifndef SkOpSegment_DEFINE
|
| +#define SkOpSegment_DEFINE
|
| +
|
| +#include "SkOpAngle.h"
|
| +#include "SkPathOpsBounds.h"
|
| +#include "SkPathOpsCurve.h"
|
| +#include "SkTDArray.h"
|
| +
|
| +class SkPathWriter;
|
| +
|
| +class SkOpSegment {
|
| +public:
|
| + SkOpSegment() {
|
| +#if DEBUG_DUMP
|
| + fID = ++gSegmentID;
|
| +#endif
|
| + }
|
| +
|
| + bool operator<(const SkOpSegment& rh) const {
|
| + return fBounds.fTop < rh.fBounds.fTop;
|
| + }
|
| +
|
| + const SkPathOpsBounds& bounds() const {
|
| + return fBounds;
|
| + }
|
| +
|
| + // OPTIMIZE
|
| + // when the edges are initially walked, they don't automatically get the prior and next
|
| + // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
|
| + // and would additionally remove the need for similar checks in condition edges. It would
|
| + // also allow intersection code to assume end of segment intersections (maybe?)
|
| + bool complete() const {
|
| + int count = fTs.count();
|
| + return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
|
| + }
|
| +
|
| + bool done() const {
|
| + SkASSERT(fDoneSpans <= fTs.count());
|
| + return fDoneSpans == fTs.count();
|
| + }
|
| +
|
| + bool done(int min) const {
|
| + return fTs[min].fDone;
|
| + }
|
| +
|
| + bool done(const SkOpAngle* angle) const {
|
| + return done(SkMin32(angle->start(), angle->end()));
|
| + }
|
| +
|
| + SkVector dxdy(int index) const {
|
| + return (*CurveSlopeAtT[fVerb])(fPts, fTs[index].fT);
|
| + }
|
| +
|
| + SkScalar dy(int index) const {
|
| + return dxdy(index).fY;
|
| + }
|
| +
|
| + bool intersected() const {
|
| + return fTs.count() > 0;
|
| + }
|
| +
|
| + bool isCanceled(int tIndex) const {
|
| + return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
|
| + }
|
| +
|
| + bool isConnected(int startIndex, int endIndex) const {
|
| + return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
|
| + }
|
| +
|
| + bool isHorizontal() const {
|
| + return fBounds.fTop == fBounds.fBottom;
|
| + }
|
| +
|
| + bool isVertical() const {
|
| + return fBounds.fLeft == fBounds.fRight;
|
| + }
|
| +
|
| + bool isVertical(int start, int end) const {
|
| + return (*CurveIsVertical[fVerb])(fPts, start, end);
|
| + }
|
| +
|
| + bool operand() const {
|
| + return fOperand;
|
| + }
|
| +
|
| + int oppSign(const SkOpAngle* angle) const {
|
| + SkASSERT(angle->segment() == this);
|
| + return oppSign(angle->start(), angle->end());
|
| + }
|
| +
|
| + int oppSign(int startIndex, int endIndex) const {
|
| + int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
|
| +#if DEBUG_WIND_BUMP
|
| + SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
|
| +#endif
|
| + return result;
|
| + }
|
| +
|
| + int oppSum(int tIndex) const {
|
| + return fTs[tIndex].fOppSum;
|
| + }
|
| +
|
| + int oppSum(const SkOpAngle* angle) const {
|
| + int lesser = SkMin32(angle->start(), angle->end());
|
| + return fTs[lesser].fOppSum;
|
| + }
|
| +
|
| + int oppValue(int tIndex) const {
|
| + return fTs[tIndex].fOppValue;
|
| + }
|
| +
|
| + int oppValue(const SkOpAngle* angle) const {
|
| + int lesser = SkMin32(angle->start(), angle->end());
|
| + return fTs[lesser].fOppValue;
|
| + }
|
| +
|
| + const SkPoint* pts() const {
|
| + return fPts;
|
| + }
|
| +
|
| + void reset() {
|
| + init(NULL, (SkPath::Verb) -1, false, false);
|
| + fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
|
| + fTs.reset();
|
| + }
|
| +
|
| + void setOppXor(bool isOppXor) {
|
| + fOppXor = isOppXor;
|
| + }
|
| +
|
| + void setSpanT(int index, double t) {
|
| + SkOpSpan& span = fTs[index];
|
| + span.fT = t;
|
| + span.fOther->fTs[span.fOtherIndex].fOtherT = t;
|
| + }
|
| +
|
| + void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) {
|
| + int deltaSum = spanSign(index, endIndex);
|
| + maxWinding = sumWinding;
|
| + sumWinding = sumWinding -= deltaSum;
|
| + }
|
| +
|
| + // OPTIMIZATION: mark as debugging only if used solely by tests
|
| + const SkOpSpan& span(int tIndex) const {
|
| + return fTs[tIndex];
|
| + }
|
| +
|
| + int spanSign(const SkOpAngle* angle) const {
|
| + SkASSERT(angle->segment() == this);
|
| + return spanSign(angle->start(), angle->end());
|
| + }
|
| +
|
| + int spanSign(int startIndex, int endIndex) const {
|
| + int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
|
| +#if DEBUG_WIND_BUMP
|
| + SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
|
| +#endif
|
| + return result;
|
| + }
|
| +
|
| + // OPTIMIZATION: mark as debugging only if used solely by tests
|
| + double t(int tIndex) const {
|
| + return fTs[tIndex].fT;
|
| + }
|
| +
|
| + double tAtMid(int start, int end, double mid) const {
|
| + return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
|
| + }
|
| +
|
| + bool unsortable(int index) const {
|
| + return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
|
| + }
|
| +
|
| + void updatePts(const SkPoint pts[]) {
|
| + fPts = pts;
|
| + }
|
| +
|
| + SkPath::Verb verb() const {
|
| + return fVerb;
|
| + }
|
| +
|
| + int windSum(int tIndex) const {
|
| + return fTs[tIndex].fWindSum;
|
| + }
|
| +
|
| + int windValue(int tIndex) const {
|
| + return fTs[tIndex].fWindValue;
|
| + }
|
| +
|
| + SkScalar xAtT(int index) const {
|
| + return xAtT(&fTs[index]);
|
| + }
|
| +
|
| + SkScalar xAtT(const SkOpSpan* span) const {
|
| + return xyAtT(span).fX;
|
| + }
|
| +
|
| + const SkPoint& xyAtT(const SkOpSpan* span) const {
|
| + return span->fPt;
|
| + }
|
| +
|
| + // used only by right angle winding finding
|
| + SkPoint xyAtT(double mid) const {
|
| + return (*CurvePointAtT[fVerb])(fPts, mid);
|
| + }
|
| +
|
| + const SkPoint& xyAtT(int index) const {
|
| + return xyAtT(&fTs[index]);
|
| + }
|
| +
|
| + SkScalar yAtT(int index) const {
|
| + return yAtT(&fTs[index]);
|
| + }
|
| +
|
| + SkScalar yAtT(const SkOpSpan* span) const {
|
| + return xyAtT(span).fY;
|
| + }
|
| +
|
| + bool activeAngle(int index, int& done, SkTDArray<SkOpAngle>& angles);
|
| + bool activeAngleOther(int index, int& done, SkTDArray<SkOpAngle>& angles);
|
| + bool activeAngleInner(int index, int& done, SkTDArray<SkOpAngle>& angles);
|
| + SkPoint activeLeftTop(bool onlySortable, int* firstT) const;
|
| + bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
|
| + bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
|
| + int& sumMiWinding, int& sumSuWinding, int& maxWinding, int& sumWinding,
|
| + int& oppMaxWinding, int& oppSumWinding);
|
| + bool activeWinding(int index, int endIndex);
|
| + bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding);
|
| + void addAngle(SkTDArray<SkOpAngle>& angles, int start, int end) const;
|
| + void addCancelOutsides(double tStart, double oStart, SkOpSegment& other, double oEnd);
|
| + void addCoinOutsides(const SkTDArray<double>& outsideTs, SkOpSegment& other, double oEnd);
|
| + void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
|
| + void addCurveTo(int start, int end, SkPathWriter& path, bool active) const;
|
| + void addLine(const SkPoint pts[2], bool operand, bool evenOdd);
|
| + void addOtherT(int index, double otherT, int otherIndex);
|
| + void addQuad(const SkPoint pts[3], bool operand, bool evenOdd);
|
| + int addSelfT(SkOpSegment* other, const SkPoint& pt, double newT);
|
| + int addT(SkOpSegment* other, const SkPoint& pt, double newT);
|
| + void addTCancel(double startT, double endT, SkOpSegment& other, double oStartT, double oEndT);
|
| + void addTCoincident(double startT, double endT, SkOpSegment& other, double oStartT,
|
| + double oEndT);
|
| + void addTPair(double t, SkOpSegment& other, double otherT, bool borrowWind, const SkPoint& pt);
|
| + void addTwoAngles(int start, int end, SkTDArray<SkOpAngle>& angles) const;
|
| +
|
| + int addUnsortableT(SkOpSegment* other, bool start, const SkPoint& pt, double newT);
|
| + int advanceCoincidentOther(const SkOpSpan* test, double oEndT, int& oIndex);
|
| + int advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int index);
|
| + bool betweenTs(int lesser, double testT, int greater);
|
| + void buildAngles(int index, SkTDArray<SkOpAngle>& angles, bool includeOpp) const;
|
| + void buildAnglesInner(int index, SkTDArray<SkOpAngle>& angles) const;
|
| + int bumpCoincidentThis(const SkOpSpan* oTest, bool opp, int index,
|
| + SkTDArray<double>& outsideTs);
|
| + int bumpCoincidentOther(const SkOpSpan* test, double oEndT, int& oIndex,
|
| + SkTDArray<double>& oOutsideTs);
|
| + bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
|
| + bool clockwise(int tStart, int tEnd) const;
|
| + int computeSum(int startIndex, int endIndex, bool binary);
|
| + int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
|
| + double mid, bool opp, bool current) const;
|
| + void decrementSpan(SkOpSpan* span);
|
| + bool equalPoints(int greaterTIndex, int lesserTIndex);
|
| + SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int& nextEnd,
|
| + bool& unsortable, SkPathOp op, const int xorMiMask,
|
| + const int xorSuMask);
|
| + int findStartingEdge(SkTDArray<SkOpAngle*>& sorted, int start, int end);
|
| + SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>& chase, int& nextStart, int& nextEnd,
|
| + bool& unsortable);
|
| + SkOpSegment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable);
|
| + void findTooCloseToCall();
|
| + SkOpSegment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable);
|
| + void fixOtherTIndex();
|
| + void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
|
| + void initWinding(int start, int end);
|
| + void initWinding(int start, int end, int winding, int oppWinding);
|
| + void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
|
| + SkScalar hitOppDx);
|
| + bool isLinear(int start, int end) const;
|
| + bool isMissing(double startT) const;
|
| + bool isSimple(int end) const;
|
| + SkOpSpan* markAndChaseDone(const SkOpAngle* angle, int winding);
|
| + SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
|
| + SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding);
|
| + SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
|
| + SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
|
| + SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding);
|
| + SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, const int winding);
|
| + SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding);
|
| + SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
|
| + SkOpSpan* markAngle(int maxWinding, int sumWinding, bool activeAngle, const SkOpAngle* angle);
|
| + SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
|
| + bool activeAngle, const SkOpAngle* angle);
|
| + void markDone(int index, int winding);
|
| + void markDoneBinary(int index, int winding, int oppWinding);
|
| + void markDoneBinary(int index);
|
| + void markDoneUnary(int index, int winding);
|
| + void markDoneUnary(int index);
|
| + void markOneDone(const char* funName, int tIndex, int winding);
|
| + void markOneDoneBinary(const char* funName, int tIndex);
|
| + void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding);
|
| + void markOneDoneUnary(const char* funName, int tIndex);
|
| + void markOneDoneUnary(const char* funName, int tIndex, int winding);
|
| + SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding);
|
| + SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
|
| + void markUnsortable(int start, int end);
|
| + void markWinding(int index, int winding);
|
| + void markWinding(int index, int winding, int oppWinding);
|
| + void matchWindingValue(int tIndex, double t, bool borrowWind);
|
| +
|
| + bool monotonicInY(int tStart, int tEnd) const;
|
| + bool moreHorizontal(int index, int endIndex, bool& unsortable) const;
|
| + bool multipleSpans(int end) const;
|
| + bool nextCandidate(int& start, int& end) const;
|
| + SkOpSegment* nextChase(int& index, const int step, int& min, SkOpSpan*& last);
|
| + int nextExactSpan(int from, int step) const;
|
| + int nextSpan(int from, int step) const;
|
| + bool serpentine(int tStart, int tEnd) const;
|
| + void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding,
|
| + int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding);
|
| + static bool SortAngles(SkTDArray<SkOpAngle>& angles, SkTDArray<SkOpAngle*>& angleList);
|
| + void subDivide(int start, int end, SkPoint edge[4]) const;
|
| + void subDivideBounds(int start, int end, SkPathOpsBounds& bounds) const;
|
| + bool tiny(const SkOpAngle* angle) const;
|
| + static void TrackOutside(SkTDArray<double>& outsideTs, double end, double start);
|
| + void undoneSpan(int& start, int& end);
|
| + int updateOppWinding(int index, int endIndex) const;
|
| + int updateOppWinding(const SkOpAngle* angle) const;
|
| + int updateOppWindingReverse(const SkOpAngle* angle) const;
|
| + int updateWinding(int index, int endIndex) const;
|
| + int updateWinding(const SkOpAngle* angle) const;
|
| + int updateWindingReverse(const SkOpAngle* angle) const;
|
| + static bool UseInnerWinding(int outerWinding, int innerWinding);
|
| + SkOpSpan* verifyOneWinding(const char* funName, int tIndex);
|
| + SkOpSpan* verifyOneWindingU(const char* funName, int tIndex);
|
| + int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const;
|
| + int windSum(const SkOpAngle* angle) const;
|
| + int windValue(const SkOpAngle* angle) const;
|
| + int windValueAt(double t) const;
|
| + void zeroCoincidentOpp(SkOpSpan* oTest, int index);
|
| + void zeroCoincidentOther(SkOpSpan* test, const double tRatio, const double oEndT, int oIndex);
|
| + void zeroSpan(SkOpSpan* span);
|
| +
|
| +#if DEBUG_WINDING
|
| + static char as_digit(int value) {
|
| + return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
|
| + }
|
| +#endif
|
| +
|
| +#if DEBUG_DUMP
|
| + int debugID() const {
|
| + return fID;
|
| + }
|
| +#endif
|
| +
|
| +#if DEBUG_SWAP_TOP
|
| + bool controlsContainedByEnds(int tStart, int tEnd) const;
|
| +#endif
|
| +#if DEBUG_CONCIDENT
|
| + void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
|
| +#endif
|
| +#if DEBUG_ACTIVE_SPANS
|
| + void debugShowActiveSpans() const;
|
| +#endif
|
| +#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
|
| + void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
|
| + void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
|
| +#endif
|
| +#if DEBUG_SORT || DEBUG_SWAP_TOP
|
| + void debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first,
|
| + const int contourWinding, const int oppContourWinding) const;
|
| + void debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& angles, int first);
|
| +#endif
|
| +#if DEBUG_WINDING
|
| + void debugShowSums() const;
|
| +#endif
|
| +#if DEBUG_CONCIDENT
|
| + void debugShowTs() const;
|
| +#endif
|
| +#if DEBUG_SHOW_WINDING
|
| + int debugShowWindingValues(int slotCount, int ofInterest) const;
|
| +#endif
|
| +#if DEBUG_DUMP
|
| + void dump() const;
|
| +#endif
|
| +#if DEBUG_ACTIVE_SPANS
|
| + void validateActiveSpans() const;
|
| +#endif
|
| +
|
| +private:
|
| + const SkPoint* fPts;
|
| + SkPathOpsBounds fBounds;
|
| + SkTDArray<SkOpSpan> fTs; // two or more (always includes t=0 t=1)
|
| + // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
|
| + int fDoneSpans; // quick check that segment is finished
|
| + // OPTIMIZATION: force the following to be byte-sized
|
| + SkPath::Verb fVerb;
|
| + bool fOperand;
|
| + bool fXor; // set if original contour had even-odd fill
|
| + bool fOppXor; // set if opposite operand had even-odd fill
|
| +#if DEBUG_DUMP
|
| + int fID;
|
| +#endif
|
| +};
|
| +
|
| +#endif
|
|
|