Home | History | Annotate | Download | only in pathops
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #ifndef SkOpSegment_DEFINE
      8 #define SkOpSegment_DEFINE
      9 
     10 #include "SkOpAngle.h"
     11 #include "SkOpSpan.h"
     12 #include "SkPathOpsBounds.h"
     13 #include "SkPathOpsCurve.h"
     14 #include "SkTArray.h"
     15 #include "SkTDArray.h"
     16 
     17 class SkPathWriter;
     18 
     19 class SkOpSegment {
     20 public:
     21     SkOpSegment() {
     22 #if DEBUG_DUMP
     23         fID = ++gSegmentID;
     24 #endif
     25     }
     26 
     27     bool operator<(const SkOpSegment& rh) const {
     28         return fBounds.fTop < rh.fBounds.fTop;
     29     }
     30 
     31     const SkPathOpsBounds& bounds() const {
     32         return fBounds;
     33     }
     34 
     35     // OPTIMIZE
     36     // when the edges are initially walked, they don't automatically get the prior and next
     37     // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
     38     // and would additionally remove the need for similar checks in condition edges. It would
     39     // also allow intersection code to assume end of segment intersections (maybe?)
     40     bool complete() const {
     41         int count = fTs.count();
     42         return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
     43     }
     44 
     45     int count() const {
     46         return fTs.count();
     47     }
     48 
     49     bool done() const {
     50         SkASSERT(fDoneSpans <= fTs.count());
     51         return fDoneSpans == fTs.count();
     52     }
     53 
     54     bool done(int min) const {
     55         return fTs[min].fDone;
     56     }
     57 
     58     bool done(const SkOpAngle* angle) const {
     59         return done(SkMin32(angle->start(), angle->end()));
     60     }
     61 
     62     SkVector dxdy(int index) const {
     63         return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
     64     }
     65 
     66     SkScalar dy(int index) const {
     67         return dxdy(index).fY;
     68     }
     69 
     70     bool intersected() const {
     71         return fTs.count() > 0;
     72     }
     73 
     74     bool isCanceled(int tIndex) const {
     75         return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
     76     }
     77 
     78     bool isConnected(int startIndex, int endIndex) const {
     79         return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
     80     }
     81 
     82     bool isHorizontal() const {
     83         return fBounds.fTop == fBounds.fBottom;
     84     }
     85 
     86     bool isVertical() const {
     87         return fBounds.fLeft == fBounds.fRight;
     88     }
     89 
     90     bool isVertical(int start, int end) const {
     91         return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
     92     }
     93 
     94     bool operand() const {
     95         return fOperand;
     96     }
     97 
     98     int oppSign(const SkOpAngle* angle) const {
     99         SkASSERT(angle->segment() == this);
    100         return oppSign(angle->start(), angle->end());
    101     }
    102 
    103     int oppSign(int startIndex, int endIndex) const {
    104         int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
    105 #if DEBUG_WIND_BUMP
    106         SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
    107 #endif
    108         return result;
    109     }
    110 
    111     int oppSum(int tIndex) const {
    112         return fTs[tIndex].fOppSum;
    113     }
    114 
    115     int oppSum(const SkOpAngle* angle) const {
    116         int lesser = SkMin32(angle->start(), angle->end());
    117         return fTs[lesser].fOppSum;
    118     }
    119 
    120     int oppValue(int tIndex) const {
    121         return fTs[tIndex].fOppValue;
    122     }
    123 
    124     int oppValue(const SkOpAngle* angle) const {
    125         int lesser = SkMin32(angle->start(), angle->end());
    126         return fTs[lesser].fOppValue;
    127     }
    128 
    129     const SkOpSegment* other(int index) const {
    130         return fTs[index].fOther;
    131     }
    132 
    133     // was used only by right angle winding finding
    134     SkPoint ptAtT(double mid) const {
    135         return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
    136     }
    137 
    138     const SkPoint* pts() const {
    139         return fPts;
    140     }
    141 
    142     void reset() {
    143         init(NULL, (SkPath::Verb) -1, false, false);
    144         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
    145         fTs.reset();
    146     }
    147 
    148     void setOppXor(bool isOppXor) {
    149         fOppXor = isOppXor;
    150     }
    151 
    152     void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
    153         int deltaSum = spanSign(index, endIndex);
    154         *maxWinding = *sumWinding;
    155         *sumWinding -= deltaSum;
    156     }
    157 
    158     // OPTIMIZATION: mark as debugging only if used solely by tests
    159     const SkOpSpan& span(int tIndex) const {
    160         return fTs[tIndex];
    161     }
    162 
    163     // OPTIMIZATION: mark as debugging only if used solely by tests
    164     const SkTDArray<SkOpSpan>& spans() const {
    165         return fTs;
    166     }
    167 
    168     int spanSign(const SkOpAngle* angle) const {
    169         SkASSERT(angle->segment() == this);
    170         return spanSign(angle->start(), angle->end());
    171     }
    172 
    173     int spanSign(int startIndex, int endIndex) const {
    174         int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
    175 #if DEBUG_WIND_BUMP
    176         SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
    177 #endif
    178         return result;
    179     }
    180 
    181     // OPTIMIZATION: mark as debugging only if used solely by tests
    182     double t(int tIndex) const {
    183         return fTs[tIndex].fT;
    184     }
    185 
    186     double tAtMid(int start, int end, double mid) const {
    187         return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
    188     }
    189 
    190     bool unsortable(int index) const {
    191         return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd;
    192     }
    193 
    194     void updatePts(const SkPoint pts[]) {
    195         fPts = pts;
    196     }
    197 
    198     SkPath::Verb verb() const {
    199         return fVerb;
    200     }
    201 
    202     int windSum(int tIndex) const {
    203         return fTs[tIndex].fWindSum;
    204     }
    205 
    206     int windValue(int tIndex) const {
    207         return fTs[tIndex].fWindValue;
    208     }
    209 
    210     SkScalar xAtT(int index) const {
    211         return xAtT(&fTs[index]);
    212     }
    213 
    214     SkScalar xAtT(const SkOpSpan* span) const {
    215         return xyAtT(span).fX;
    216     }
    217 
    218     const SkPoint& xyAtT(const SkOpSpan* span) const {
    219         return span->fPt;
    220     }
    221 
    222     const SkPoint& xyAtT(int index) const {
    223         return xyAtT(&fTs[index]);
    224     }
    225 
    226     SkScalar yAtT(int index) const {
    227         return yAtT(&fTs[index]);
    228     }
    229 
    230     SkScalar yAtT(const SkOpSpan* span) const {
    231         return xyAtT(span).fY;
    232     }
    233 
    234     bool activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles);
    235     SkPoint activeLeftTop(bool onlySortable, int* firstT) const;
    236     bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
    237     bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
    238                   int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding,
    239                   int* oppMaxWinding, int* oppSumWinding);
    240     bool activeWinding(int index, int endIndex);
    241     bool activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding);
    242     void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
    243     void addCurveTo(int start, int end, SkPathWriter* path, bool active) const;
    244     void addLine(const SkPoint pts[2], bool operand, bool evenOdd);
    245     void addOtherT(int index, double otherT, int otherIndex);
    246     void addQuad(const SkPoint pts[3], bool operand, bool evenOdd);
    247     int addSelfT(SkOpSegment* other, const SkPoint& pt, double newT);
    248     int addT(SkOpSegment* other, const SkPoint& pt, double newT);
    249     void addTCancel(double startT, double endT, SkOpSegment* other, double oStartT, double oEndT);
    250     void addTCoincident(double startT, double endT, SkOpSegment* other, double oStartT,
    251                         double oEndT);
    252     void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt);
    253     void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt,
    254                   const SkPoint& oPt);
    255     int addUnsortableT(SkOpSegment* other, bool start, const SkPoint& pt, double newT);
    256     bool betweenTs(int lesser, double testT, int greater) const;
    257     void checkEnds();
    258     int computeSum(int startIndex, int endIndex, bool binary);
    259     int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething,
    260                      double mid, bool opp, bool current) const;
    261     SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
    262                             bool* unsortable, SkPathOp op, const int xorMiMask,
    263                             const int xorSuMask);
    264     SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
    265                                  bool* unsortable);
    266     SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable);
    267     void findTooCloseToCall();
    268     SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool onlySortable);
    269     void fixOtherTIndex();
    270     void initWinding(int start, int end);
    271     void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
    272             SkScalar hitOppDx);
    273     bool isLinear(int start, int end) const;
    274     bool isMissing(double startT) const;
    275     bool isSimple(int end) const;
    276     bool isTiny(const SkOpAngle* angle) const;
    277     bool isTiny(int index) const;
    278     SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
    279     SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
    280     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
    281     SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
    282                         bool activeAngle, const SkOpAngle* angle);
    283     void markDone(int index, int winding);
    284     void markDoneBinary(int index);
    285     void markDoneUnary(int index);
    286     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding);
    287     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
    288     void markWinding(int index, int winding);
    289     void markWinding(int index, int winding, int oppWinding);
    290     bool nextCandidate(int* start, int* end) const;
    291     int nextExactSpan(int from, int step) const;
    292     int nextSpan(int from, int step) const;
    293     void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
    294             int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding);
    295     enum SortAngleKind {
    296         kMustBeOrdered_SortAngleKind, // required for winding calc
    297         kMayBeUnordered_SortAngleKind // ok for find top
    298     };
    299     static bool SortAngles(const SkTArray<SkOpAngle, true>& angles,
    300                            SkTArray<SkOpAngle*, true>* angleList,
    301                            SortAngleKind );
    302     bool subDivide(int start, int end, SkPoint edge[4]) const;
    303     bool subDivide(int start, int end, SkDCubic* result) const;
    304     void undoneSpan(int* start, int* end);
    305     int updateOppWindingReverse(const SkOpAngle* angle) const;
    306     int updateWindingReverse(const SkOpAngle* angle) const;
    307     static bool UseInnerWinding(int outerWinding, int innerWinding);
    308     int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const;
    309     int windSum(const SkOpAngle* angle) const;
    310     int windValue(const SkOpAngle* angle) const;
    311 
    312 #if DEBUG_DUMP
    313     int debugID() const {
    314         return fID;
    315     }
    316 #endif
    317 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
    318     void debugShowActiveSpans() const;
    319 #endif
    320 #if DEBUG_SORT || DEBUG_SWAP_TOP
    321     void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first,
    322             const int contourWinding, const int oppContourWinding, bool sortable) const;
    323     void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first,
    324             bool sortable);
    325 #endif
    326 #if DEBUG_CONCIDENT
    327     void debugShowTs() const;
    328 #endif
    329 #if DEBUG_SHOW_WINDING
    330     int debugShowWindingValues(int slotCount, int ofInterest) const;
    331 #endif
    332 
    333 private:
    334     bool activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles);
    335     bool activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles);
    336     void addAngle(SkTArray<SkOpAngle, true>* angles, int start, int end) const;
    337     void addCancelOutsides(double tStart, double oStart, SkOpSegment* other, double oEnd);
    338     void addCoinOutsides(const SkTArray<double, true>& outsideTs, SkOpSegment* other, double oEnd);
    339     void addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const;
    340     int advanceCoincidentOther(const SkOpSpan* test, double oEndT, int oIndex);
    341     int advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int index);
    342     void buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const;
    343     void buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const;
    344     int bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index,
    345                            SkTArray<double, true>* outsideTs);
    346     int bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oIndex,
    347                             SkTArray<double, true>* oOutsideTs);
    348     bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
    349     bool clockwise(int tStart, int tEnd) const;
    350     void decrementSpan(SkOpSpan* span);
    351     bool equalPoints(int greaterTIndex, int lesserTIndex);
    352     int findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end);
    353     void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
    354     void matchWindingValue(int tIndex, double t, bool borrowWind);
    355     SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
    356     SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding);
    357     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, const int winding);
    358     SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding);
    359     SkOpSpan* markAngle(int maxWinding, int sumWinding, bool activeAngle, const SkOpAngle* angle);
    360     void markDoneBinary(int index, int winding, int oppWinding);
    361     SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding);
    362     void markOneDone(const char* funName, int tIndex, int winding);
    363     void markOneDoneBinary(const char* funName, int tIndex);
    364     void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding);
    365     void markOneDoneUnary(const char* funName, int tIndex);
    366     void markUnsortable(int start, int end);
    367     bool monotonicInY(int tStart, int tEnd) const;
    368     bool multipleSpans(int end) const;
    369     SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last);
    370     bool serpentine(int tStart, int tEnd) const;
    371     void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const;
    372     static void TrackOutside(SkTArray<double, true>* outsideTs, double end, double start);
    373     int updateOppWinding(int index, int endIndex) const;
    374     int updateOppWinding(const SkOpAngle* angle) const;
    375     int updateWinding(int index, int endIndex) const;
    376     int updateWinding(const SkOpAngle* angle) const;
    377     SkOpSpan* verifyOneWinding(const char* funName, int tIndex);
    378     SkOpSpan* verifyOneWindingU(const char* funName, int tIndex);
    379     int windValueAt(double t) const;
    380     void zeroSpan(SkOpSpan* span);
    381 
    382 #if DEBUG_SWAP_TOP
    383     bool controlsContainedByEnds(int tStart, int tEnd) const;
    384 #endif
    385 #if DEBUG_CONCIDENT
    386      void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
    387 #endif
    388 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
    389     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
    390     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
    391 #endif
    392 #if DEBUG_WINDING
    393     static char as_digit(int value) {
    394         return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
    395     }
    396 #endif
    397     void debugValidate() const;
    398 
    399     const SkPoint* fPts;
    400     SkPathOpsBounds fBounds;
    401     // FIXME: can't convert to SkTArray because it uses insert
    402     SkTDArray<SkOpSpan> fTs;  // two or more (always includes t=0 t=1)
    403     // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
    404     int fDoneSpans;  // quick check that segment is finished
    405     // OPTIMIZATION: force the following to be byte-sized
    406     SkPath::Verb fVerb;
    407     bool fOperand;
    408     bool fXor;  // set if original contour had even-odd fill
    409     bool fOppXor;  // set if opposite operand had even-odd fill
    410 #if DEBUG_DUMP
    411     int fID;
    412 #endif
    413 };
    414 
    415 #endif
    416