2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #ifndef SkOpSegment_DEFINE
8 #define SkOpSegment_DEFINE
10 #include "SkOpAngle.h"
12 #include "SkPathOpsBounds.h"
13 #include "SkPathOpsCurve.h"
15 #include "SkTDArray.h"
17 #if defined(SK_DEBUG) || !FORCE_RELEASE
26 #if defined(SK_DEBUG) || !FORCE_RELEASE
27 fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID);
31 bool operator<(const SkOpSegment& rh) const {
32 return fBounds.fTop < rh.fBounds.fTop;
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);
41 const SkPathOpsBounds& bounds() const {
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;
60 SkASSERT(fDoneSpans <= fTs.count());
61 return fDoneSpans == fTs.count();
64 bool done(int min) const {
65 return fTs[min].fDone;
68 bool done(const SkOpAngle* angle) const {
69 return done(SkMin32(angle->start(), angle->end()));
72 SkDPoint dPtAtT(double mid) const {
73 return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
76 SkVector dxdy(int index) const {
77 return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
80 SkScalar dy(int index) const {
81 return dxdy(index).fY;
84 bool hasSmall() const {
88 bool hasTiny() const {
92 bool intersected() const {
93 return fTs.count() > 0;
96 bool isCanceled(int tIndex) const {
97 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
100 bool isConnected(int startIndex, int endIndex) const {
101 return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
104 bool isHorizontal() const {
105 return fBounds.fTop == fBounds.fBottom;
108 bool isVertical() const {
109 return fBounds.fLeft == fBounds.fRight;
112 bool isVertical(int start, int end) const {
113 return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
116 bool operand() const {
120 int oppSign(const SkOpAngle* angle) const {
121 SkASSERT(angle->segment() == this);
122 return oppSign(angle->start(), angle->end());
125 int oppSign(int startIndex, int endIndex) const {
126 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
128 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
133 int oppSum(int tIndex) const {
134 return fTs[tIndex].fOppSum;
137 int oppSum(const SkOpAngle* angle) const {
138 int lesser = SkMin32(angle->start(), angle->end());
139 return fTs[lesser].fOppSum;
142 int oppValue(int tIndex) const {
143 return fTs[tIndex].fOppValue;
146 int oppValue(const SkOpAngle* angle) const {
147 int lesser = SkMin32(angle->start(), angle->end());
148 return fTs[lesser].fOppValue;
152 bool oppXor() const {
157 SkPoint ptAtT(double mid) const {
158 return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
161 const SkPoint* pts() const {
166 init(NULL, (SkPath::Verb) -1, false, false);
167 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
171 void setOppXor(bool isOppXor) {
175 void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
176 int deltaSum = spanSign(index, endIndex);
177 *maxWinding = *sumWinding;
178 *sumWinding -= deltaSum;
181 const SkOpSpan& span(int tIndex) const {
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;
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);
198 int spanSign(const SkOpAngle* angle) const {
199 SkASSERT(angle->segment() == this);
200 return spanSign(angle->start(), angle->end());
203 int spanSign(int startIndex, int endIndex) const {
204 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
206 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
211 double t(int tIndex) const {
212 return fTs[tIndex].fT;
215 double tAtMid(int start, int end, double mid) const {
216 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
219 void updatePts(const SkPoint pts[]) {
223 SkPath::Verb verb() const {
227 int windSum(int tIndex) const {
228 return fTs[tIndex].fWindSum;
231 int windValue(int tIndex) const {
232 return fTs[tIndex].fWindValue;
235 #if defined(SK_DEBUG) || DEBUG_WINDING
236 SkScalar xAtT(int index) const {
237 return xAtT(&fTs[index]);
242 bool _xor() const { // FIXME: used only by SkOpAngle::debugValidateLoop()
247 const SkPoint& xyAtT(const SkOpSpan* span) const {
251 const SkPoint& xyAtT(int index) const {
252 return xyAtT(&fTs[index]);
255 #if defined(SK_DEBUG) || DEBUG_WINDING
256 SkScalar yAtT(int index) const {
257 return yAtT(&fTs[index]);
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,
279 const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
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;
286 void checkDuplicates();
288 void checkMultiples();
290 bool checkSmall(int index) const;
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,
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,
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,
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);
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
338 bool debugContains(const SkOpAngle* ) const;
340 #if defined(SK_DEBUG) || !FORCE_RELEASE
341 int debugID() const {
345 int debugID() const {
349 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
350 void debugShowActiveSpans() const;
353 void debugShowTs(const char* prefix) const;
355 #if DEBUG_SHOW_WINDING
356 int debugShowWindingValues(int slotCount, int ofInterest) const;
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;
370 SkOpSegment* fSegment;
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,
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;
439 bool multipleEnds() const {
440 return fTs[count() - 2].fT == 1;
443 bool multipleStarts() const {
444 return fTs[1].fT == 0;
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);
467 SkScalar xAtT(const SkOpSpan* span) const {
468 return xyAtT(span).fX;
471 SkScalar yAtT(const SkOpSpan* span) const {
472 return xyAtT(span).fY;
475 void zeroSpan(SkOpSpan* span);
478 bool controlsContainedByEnds(int tStart, int tEnd) const;
480 void debugAddAngle(int start, int end);
482 void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
485 void debugCheckPointsEqualish(int tStart, int tEnd) const;
488 int debugInflections(int index, int endIndex) const;
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);
495 static char as_digit(int value) {
496 return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
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]);
505 void dumpDPts() const;
506 void dumpSpan(int index) const;
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
519 bool fLoop; // set if cubic intersects itself
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
529 friend class PathOpsSegmentTester;