Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / pathops / SkOpSegment.h
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 #if defined(SK_DEBUG) || !FORCE_RELEASE
18 #include "SkThread.h"
19 #endif
20
21 class SkPathWriter;
22
23 class SkOpSegment {
24 public:
25     SkOpSegment() {
26 #if defined(SK_DEBUG) || !FORCE_RELEASE
27         fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID);
28 #endif
29     }
30
31     bool operator<(const SkOpSegment& rh) const {
32         return fBounds.fTop < rh.fBounds.fTop;
33     }
34
35     // FIXME: add some template or macro to avoid casting
36     SkOpAngle& angle(int index) {
37         const SkOpAngle& cAngle = (const_cast<const SkOpSegment*>(this))->angle(index);
38         return const_cast<SkOpAngle&>(cAngle);
39     }
40
41     const SkPathOpsBounds& bounds() const {
42         return fBounds;
43     }
44
45     // OPTIMIZE
46     // when the edges are initially walked, they don't automatically get the prior and next
47     // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
48     // and would additionally remove the need for similar checks in condition edges. It would
49     // also allow intersection code to assume end of segment intersections (maybe?)
50     bool complete() const {
51         int count = fTs.count();
52         return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
53     }
54
55     int count() const {
56         return fTs.count();
57     }
58
59     bool done() const {
60         SkASSERT(fDoneSpans <= fTs.count());
61         return fDoneSpans == fTs.count();
62     }
63
64     bool done(int min) const {
65         return fTs[min].fDone;
66     }
67
68     bool done(const SkOpAngle* angle) const {
69         return done(SkMin32(angle->start(), angle->end()));
70     }
71
72     SkDPoint dPtAtT(double mid) const {
73         return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
74     }
75
76     SkVector dxdy(int index) const {
77         return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
78     }
79
80     SkScalar dy(int index) const {
81         return dxdy(index).fY;
82     }
83
84     bool hasSmall() const {
85         return fSmall;
86     }
87
88     bool hasTiny() const {
89         return fTiny;
90     }
91
92     bool intersected() const {
93         return fTs.count() > 0;
94     }
95
96     bool isCanceled(int tIndex) const {
97         return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
98     }
99
100     bool isConnected(int startIndex, int endIndex) const {
101         return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
102     }
103
104     bool isHorizontal() const {
105         return fBounds.fTop == fBounds.fBottom;
106     }
107
108     bool isVertical() const {
109         return fBounds.fLeft == fBounds.fRight;
110     }
111
112     bool isVertical(int start, int end) const {
113         return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
114     }
115
116     bool operand() const {
117         return fOperand;
118     }
119
120     int oppSign(const SkOpAngle* angle) const {
121         SkASSERT(angle->segment() == this);
122         return oppSign(angle->start(), angle->end());
123     }
124
125     int oppSign(int startIndex, int endIndex) const {
126         int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
127 #if DEBUG_WIND_BUMP
128         SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
129 #endif
130         return result;
131     }
132
133     int oppSum(int tIndex) const {
134         return fTs[tIndex].fOppSum;
135     }
136
137     int oppSum(const SkOpAngle* angle) const {
138         int lesser = SkMin32(angle->start(), angle->end());
139         return fTs[lesser].fOppSum;
140     }
141
142     int oppValue(int tIndex) const {
143         return fTs[tIndex].fOppValue;
144     }
145
146     int oppValue(const SkOpAngle* angle) const {
147         int lesser = SkMin32(angle->start(), angle->end());
148         return fTs[lesser].fOppValue;
149     }
150
151 #if DEBUG_VALIDATE
152     bool oppXor() const {
153         return fOppXor;
154     }
155 #endif
156
157     SkPoint ptAtT(double mid) const {
158         return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
159     }
160
161     const SkPoint* pts() const {
162         return fPts;
163     }
164
165     void reset() {
166         init(NULL, (SkPath::Verb) -1, false, false);
167         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
168         fTs.reset();
169     }
170
171     void setOppXor(bool isOppXor) {
172         fOppXor = isOppXor;
173     }
174
175     void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
176         int deltaSum = spanSign(index, endIndex);
177         *maxWinding = *sumWinding;
178         *sumWinding -= deltaSum;
179     }
180
181     const SkOpSpan& span(int tIndex) const {
182         return fTs[tIndex];
183     }
184
185     const SkOpAngle* spanToAngle(int tStart, int tEnd) const {
186         SkASSERT(tStart != tEnd);
187         const SkOpSpan& span = fTs[tStart];
188         int index = tStart < tEnd ? span.fToAngleIndex : span.fFromAngleIndex;
189         return index >= 0 ? &angle(index) : NULL;
190     }
191
192     // FIXME: create some sort of macro or template that avoids casting
193     SkOpAngle* spanToAngle(int tStart, int tEnd) {
194         const SkOpAngle* cAngle = (const_cast<const SkOpSegment*>(this))->spanToAngle(tStart, tEnd);
195         return const_cast<SkOpAngle*>(cAngle);
196     }
197
198     int spanSign(const SkOpAngle* angle) const {
199         SkASSERT(angle->segment() == this);
200         return spanSign(angle->start(), angle->end());
201     }
202
203     int spanSign(int startIndex, int endIndex) const {
204         int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
205 #if DEBUG_WIND_BUMP
206         SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
207 #endif
208         return result;
209     }
210
211     double t(int tIndex) const {
212         return fTs[tIndex].fT;
213     }
214
215     double tAtMid(int start, int end, double mid) const {
216         return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
217     }
218
219     void updatePts(const SkPoint pts[]) {
220         fPts = pts;
221     }
222
223     SkPath::Verb verb() const {
224         return fVerb;
225     }
226
227     int windSum(int tIndex) const {
228         return fTs[tIndex].fWindSum;
229     }
230
231     int windValue(int tIndex) const {
232         return fTs[tIndex].fWindValue;
233     }
234
235 #if defined(SK_DEBUG) || DEBUG_WINDING
236     SkScalar xAtT(int index) const {
237         return xAtT(&fTs[index]);
238     }
239 #endif
240
241 #if DEBUG_VALIDATE
242     bool _xor() const {  // FIXME: used only by SkOpAngle::debugValidateLoop()
243         return fXor;
244     }
245 #endif
246
247     const SkPoint& xyAtT(const SkOpSpan* span) const {
248         return span->fPt;
249     }
250
251     const SkPoint& xyAtT(int index) const {
252         return xyAtT(&fTs[index]);
253     }
254
255 #if defined(SK_DEBUG) || DEBUG_WINDING
256     SkScalar yAtT(int index) const {
257         return yAtT(&fTs[index]);
258     }
259 #endif
260
261     const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done,
262                                  bool* sortable) const;
263     SkPoint activeLeftTop(int* firstT) const;
264     bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
265     bool activeWinding(int index, int endIndex);
266     void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
267     void addCurveTo(int start, int end, SkPathWriter* path, bool active) const;
268     void addEndSpan(int endIndex);
269     void addLine(const SkPoint pts[2], bool operand, bool evenOdd);
270     void addOtherT(int index, double otherT, int otherIndex);
271     void addQuad(const SkPoint pts[3], bool operand, bool evenOdd);
272     void addSimpleAngle(int endIndex);
273     int addSelfT(const SkPoint& pt, double newT);
274     void addStartSpan(int endIndex);
275     int addT(SkOpSegment* other, const SkPoint& pt, double newT);
276     void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
277     void addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
278                         SkOpSegment* other);
279     const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
280                              const SkPoint& pt);
281     bool alignSpan(int index, double thisT, const SkPoint& thisPt);
282     void alignSpanState(int start, int end);
283     const SkOpAngle& angle(int index) const;
284     bool betweenTs(int lesser, double testT, int greater) const;
285     bool calcAngles();
286     void checkDuplicates();
287     void checkEnds();
288     void checkMultiples();
289     void checkSmall();
290     bool checkSmall(int index) const;
291     void checkTiny();
292     int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType);
293     bool containsPt(const SkPoint& , int index, int endIndex) const;
294     int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething,
295                      double mid, bool opp, bool current) const;
296     bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd,
297                              int step, SkPoint* startPt, SkPoint* endPt, double* endT) const;
298     SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
299                             bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask);
300     SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
301                                  bool* unsortable);
302     SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable);
303     int findExactT(double t, const SkOpSegment* ) const;
304     int findT(double t, const SkPoint& , const SkOpSegment* ) const;
305     SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firstPass);
306     void fixOtherTIndex();
307     void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType);
308     void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
309                      SkScalar hitOppDx);
310     bool isMissing(double startT, const SkPoint& pt) const;
311     bool isTiny(const SkOpAngle* angle) const;
312     bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, int step,
313                          bool cancel);
314     SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
315     SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
316     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
317     SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
318                         const SkOpAngle* angle);
319     void markDone(int index, int winding);
320     void markDoneBinary(int index);
321     void markDoneUnary(int index);
322     bool nextCandidate(int* start, int* end) const;
323     int nextSpan(int from, int step) const;
324     void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
325             int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding);
326     void sortAngles();
327     bool subDivide(int start, int end, SkPoint edge[4]) const;
328     bool subDivide(int start, int end, SkDCubic* result) const;
329     void undoneSpan(int* start, int* end);
330     int updateOppWindingReverse(const SkOpAngle* angle) const;
331     int updateWindingReverse(const SkOpAngle* angle) const;
332     static bool UseInnerWinding(int outerWinding, int innerWinding);
333     static bool UseInnerWindingReverse(int outerWinding, int innerWinding);
334     int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const;
335     int windSum(const SkOpAngle* angle) const;
336 // available for testing only
337 #if DEBUG_VALIDATE
338     bool debugContains(const SkOpAngle* ) const;
339 #endif
340 #if defined(SK_DEBUG) || !FORCE_RELEASE
341     int debugID() const {
342         return fID;
343     }
344 #else
345     int debugID() const {
346         return -1;
347     }
348 #endif
349 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
350     void debugShowActiveSpans() const;
351 #endif
352 #if DEBUG_CONCIDENT
353     void debugShowTs(const char* prefix) const;
354 #endif
355 #if DEBUG_SHOW_WINDING
356     int debugShowWindingValues(int slotCount, int ofInterest) const;
357 #endif
358     const SkTDArray<SkOpSpan>& debugSpans() const;
359     void debugValidate() const;
360     // available to testing only
361     void dumpAngles() const;
362     void dumpContour(int firstID, int lastID) const;
363     void dumpPts() const;
364     void dumpSpans() const;
365
366 private:
367     struct MissingSpan  {
368         double fT;
369         double fEndT;
370         SkOpSegment* fSegment;
371         SkOpSegment* fOther;
372         double fOtherT;
373         SkPoint fPt;
374     };
375
376     const SkOpAngle* activeAngleInner(int index, int* start, int* end, bool* done,
377                                       bool* sortable) const;
378     const SkOpAngle* activeAngleOther(int index, int* start, int* end, bool* done,
379                                       bool* sortable) const;
380     bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
381                   int* sumMiWinding, int* sumSuWinding);
382     bool activeWinding(int index, int endIndex, int* sumWinding);
383     void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
384     void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
385     int addSingletonAngleDown(int start, SkOpSegment** otherPtr);
386     int addSingletonAngleUp(int start, SkOpSegment** otherPtr);
387     SkOpAngle* addSingletonAngles(int start, int step);
388     void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt,
389                   const SkPoint& oPt);
390     bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const;
391     void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index,
392                            SkTArray<SkPoint, true>* outsideTs);
393     void bumpCoincidentOther(const SkOpSpan& oTest, int* index,
394                            SkTArray<SkPoint, true>* outsideTs);
395     bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
396     bool calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts);
397     void checkLinks(const SkOpSpan* ,
398                     SkTArray<MissingSpan, true>* missingSpans) const;
399     static void CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
400                              const SkOpSpan* oFirst, const SkOpSpan* oLast,
401                              const SkOpSpan** missingPtr,
402                              SkTArray<MissingSpan, true>* missingSpans);
403     int checkSetAngle(int tIndex) const;
404     void checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>* );
405     bool clockwise(int tStart, int tEnd) const;
406     static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
407                               SkOpAngle::IncludeType );
408     static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
409                                      SkOpAngle::IncludeType );
410     bool decrementSpan(SkOpSpan* span);
411     int findEndSpan(int endIndex) const;
412     int findStartSpan(int startIndex) const;
413     int firstActive(int tIndex) const;
414     const SkOpSpan& firstSpan(const SkOpSpan& thisSpan) const;
415     void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
416     bool inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const;
417     bool isSimple(int end) const;
418     bool isTiny(int index) const;
419     const SkOpSpan& lastSpan(const SkOpSpan& thisSpan) const;
420     void matchWindingValue(int tIndex, double t, bool borrowWind);
421     SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
422     SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding);
423     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding);
424     SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding);
425     SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding);
426     SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle);
427     void markDoneBinary(int index, int winding, int oppWinding);
428     SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding);
429     void markOneDone(const char* funName, int tIndex, int winding);
430     void markOneDoneBinary(const char* funName, int tIndex);
431     void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding);
432     void markOneDoneUnary(const char* funName, int tIndex);
433     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding);
434     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
435     void markWinding(int index, int winding);
436     void markWinding(int index, int winding, int oppWinding);
437     bool monotonicInY(int tStart, int tEnd) const;
438
439     bool multipleEnds() const {
440         return fTs[count() - 2].fT == 1;
441     }
442
443     bool multipleStarts() const {
444         return fTs[1].fT == 0;
445     }
446
447     bool multipleSpans(int end) const;
448     SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last);
449     int nextExactSpan(int from, int step) const;
450     bool serpentine(int tStart, int tEnd) const;
451     void setFromAngleIndex(int endIndex, int angleIndex);
452     void setToAngleIndex(int endIndex, int angleIndex);
453     void setUpWindings(int index, int endIndex, int* sumMiWinding,
454             int* maxWinding, int* sumWinding);
455     void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const;
456     static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoint& endPt,
457             const SkPoint& startPt);
458     static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint& startPt);
459     int updateOppWinding(int index, int endIndex) const;
460     int updateOppWinding(const SkOpAngle* angle) const;
461     int updateWinding(int index, int endIndex) const;
462     int updateWinding(const SkOpAngle* angle) const;
463     int updateWindingReverse(int index, int endIndex) const;
464     SkOpSpan* verifyOneWinding(const char* funName, int tIndex);
465     SkOpSpan* verifyOneWindingU(const char* funName, int tIndex);
466
467     SkScalar xAtT(const SkOpSpan* span) const {
468         return xyAtT(span).fX;
469     }
470
471     SkScalar yAtT(const SkOpSpan* span) const {
472         return xyAtT(span).fY;
473     }
474
475     void zeroSpan(SkOpSpan* span);
476
477 #if DEBUG_SWAP_TOP
478     bool controlsContainedByEnds(int tStart, int tEnd) const;
479 #endif
480     void debugAddAngle(int start, int end);
481 #if DEBUG_CONCIDENT
482     void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
483 #endif
484 #if DEBUG_ANGLE
485     void debugCheckPointsEqualish(int tStart, int tEnd) const;
486 #endif
487 #if DEBUG_SWAP_TOP
488     int debugInflections(int index, int endIndex) const;
489 #endif
490 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
491     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
492     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
493 #endif
494 #if DEBUG_WINDING
495     static char as_digit(int value) {
496         return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
497     }
498 #endif
499     // available to testing only
500     void debugConstruct();
501     void debugConstructCubic(SkPoint shortQuad[4]);
502     void debugConstructLine(SkPoint shortQuad[2]);
503     void debugConstructQuad(SkPoint shortQuad[3]);
504     void debugReset();
505     void dumpDPts() const;
506     void dumpSpan(int index) const;
507
508     const SkPoint* fPts;
509     SkPathOpsBounds fBounds;
510     // FIXME: can't convert to SkTArray because it uses insert
511     SkTDArray<SkOpSpan> fTs;  // 2+ (always includes t=0 t=1) -- at least (number of spans) + 1
512 // FIXME: replace both with bucket storage that allows direct immovable pointers to angles
513     SkTArray<SkOpAngle, true> fSingletonAngles;  // 0 or 2 -- allocated for singletons
514     SkTArray<SkOpAngle, true> fAngles;  // 0 or 2+ -- (number of non-zero spans) * 2
515     // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
516     int fDoneSpans;  // quick check that segment is finished
517     // OPTIMIZATION: force the following to be byte-sized
518     SkPath::Verb fVerb;
519     bool fLoop;   // set if cubic intersects itself
520     bool fOperand;
521     bool fXor;  // set if original contour had even-odd fill
522     bool fOppXor;  // set if opposite operand had even-odd fill
523     bool fSmall;  // set if some span is small
524     bool fTiny;  // set if some span is tiny
525 #if defined(SK_DEBUG) || !FORCE_RELEASE
526     int fID;
527 #endif
528
529     friend class PathOpsSegmentTester;
530 };
531
532 #endif