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