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