Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: src/pathops/SkOpSegment.cpp

Issue 1037573004: cumulative pathops patch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix pathopsinverse gm Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #include "SkIntersections.h" 7 #include "SkOpCoincidence.h"
8 #include "SkOpContour.h" 8 #include "SkOpContour.h"
9 #include "SkOpSegment.h" 9 #include "SkOpSegment.h"
10 #include "SkPathWriter.h" 10 #include "SkPathWriter.h"
11 #include "SkTSort.h" 11
12 /*
13 After computing raw intersections, post process all segments to:
14 - find small collections of points that can be collapsed to a single point
15 - find missing intersections to resolve differences caused by different algorith ms
16
17 Consider segments containing tiny or small intervals. Consider coincident segmen ts
18 because coincidence finds intersections through distance measurement that non-co incident
19 intersection tests cannot.
20 */
12 21
13 #define F (false) // discard the edge 22 #define F (false) // discard the edge
14 #define T (true) // keep the edge 23 #define T (true) // keep the edge
15 24
16 static const bool gUnaryActiveEdge[2][2] = { 25 static const bool gUnaryActiveEdge[2][2] = {
17 // from=0 from=1 26 // from=0 from=1
18 // to=0,1 to=0,1 27 // to=0,1 to=0,1
19 {F, T}, {T, F}, 28 {F, T}, {T, F},
20 }; 29 };
21 30
22 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { 31 static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
23 // miFrom=0 miFrom=1 32 // miFrom=0 miFrom=1
24 // miTo=0 miTo=1 miTo=0 miTo=1 33 // miTo=0 miTo=1 miTo=0 miTo=1
25 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 34 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1
26 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 35 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1
27 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}} , // mi - su 36 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}} , // mi - su
28 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}} , // mi & su 37 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}} , // mi & su
29 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}} , // mi | su 38 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}} , // mi | su
30 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}} , // mi ^ su 39 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}} , // mi ^ su
31 }; 40 };
32 41
33 #undef F 42 #undef F
34 #undef T 43 #undef T
35 44
36 enum { 45 SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr ,
37 kOutsideTrackedTCount = 16, // FIXME: determine what this should be 46 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
38 kMissingSpanCount = 4, // FIXME: determine what this should be 47 if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done, sort able)) {
39 };
40
41 const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool* done,
42 bool* sortable) const {
43 if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sort able)) {
44 return result; 48 return result;
45 } 49 }
46 double referenceT = fTs[index].fT; 50 if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done, sort able)) {
47 int lesser = index; 51 return result;
48 while (--lesser >= 0
49 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f Tiny)) {
50 if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) {
51 return result;
52 }
53 } 52 }
54 do {
55 if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) {
56 return result;
57 }
58 if (++index == fTs.count()) {
59 break;
60 }
61 if (fTs[index - 1].fTiny) {
62 referenceT = fTs[index].fT;
63 continue;
64 }
65 } while (precisely_negative(fTs[index].fT - referenceT));
66 return NULL; 53 return NULL;
67 } 54 }
68 55
69 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done, 56 SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** sta rtPtr,
70 bool* sortable) const { 57 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
71 int next = nextExactSpan(index, 1); 58 SkOpSpan* upSpan = start->upCastable();
72 if (next > 0) { 59 if (upSpan) {
73 const SkOpSpan& upSpan = fTs[index]; 60 if (upSpan->windValue() || upSpan->oppValue()) {
74 if (upSpan.fWindValue || upSpan.fOppValue) { 61 SkOpSpanBase* next = upSpan->next();
75 if (*end < 0) { 62 if (!*endPtr) {
76 *start = index; 63 *startPtr = start;
77 *end = next; 64 *endPtr = next;
78 } 65 }
79 if (!upSpan.fDone) { 66 if (!upSpan->done()) {
80 if (upSpan.fWindSum != SK_MinS32) { 67 if (upSpan->windSum() != SK_MinS32) {
81 return spanToAngle(index, next); 68 return spanToAngle(start, next);
82 } 69 }
83 *done = false; 70 *done = false;
84 } 71 }
85 } else { 72 } else {
86 SkASSERT(upSpan.fDone); 73 SkASSERT(upSpan->done());
87 } 74 }
88 } 75 }
89 int prev = nextExactSpan(index, -1); 76 SkOpSpan* downSpan = start->prev();
90 // edge leading into junction 77 // edge leading into junction
91 if (prev >= 0) { 78 if (downSpan) {
92 const SkOpSpan& downSpan = fTs[prev]; 79 if (downSpan->windValue() || downSpan->oppValue()) {
93 if (downSpan.fWindValue || downSpan.fOppValue) { 80 if (!*endPtr) {
94 if (*end < 0) { 81 *startPtr = start;
95 *start = index; 82 *endPtr = downSpan;
96 *end = prev;
97 } 83 }
98 if (!downSpan.fDone) { 84 if (!downSpan->done()) {
99 if (downSpan.fWindSum != SK_MinS32) { 85 if (downSpan->windSum() != SK_MinS32) {
100 return spanToAngle(index, prev); 86 return spanToAngle(start, downSpan);
101 } 87 }
102 *done = false; 88 *done = false;
103 } 89 }
104 } else { 90 } else {
105 SkASSERT(downSpan.fDone); 91 SkASSERT(downSpan->done());
106 } 92 }
107 } 93 }
108 return NULL; 94 return NULL;
109 } 95 }
110 96
111 const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, bool* done, 97 SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta rtPtr,
112 bool* sortable) const { 98 SkOpSpanBase** endPtr, bool* done, bool* sortable) {
113 const SkOpSpan* span = &fTs[index]; 99 SkOpPtT* oPtT = start->ptT()->next();
114 SkOpSegment* other = span->fOther; 100 SkOpSegment* other = oPtT->segment();
115 int oIndex = span->fOtherIndex; 101 SkOpSpanBase* oSpan = oPtT->span();
116 return other->activeAngleInner(oIndex, start, end, done, sortable); 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable);
117 } 103 }
118 104
119 SkPoint SkOpSegment::activeLeftTop(int* firstT) const { 105 SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
120 SkASSERT(!done()); 106 SkASSERT(!done());
121 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; 107 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
122 int count = fTs.count();
123 // see if either end is not done since we want smaller Y of the pair 108 // see if either end is not done since we want smaller Y of the pair
124 bool lastDone = true; 109 bool lastDone = true;
125 double lastT = -1; 110 double lastT = -1;
126 for (int index = 0; index < count; ++index) { 111 SkOpSpanBase* span = &fHead;
127 const SkOpSpan& span = fTs[index]; 112 do {
128 if (span.fDone && lastDone) { 113 if (lastDone && (span->final() || span->upCast()->done())) {
129 goto next;
130 }
131 if (approximately_negative(span.fT - lastT)) {
132 goto next; 114 goto next;
133 } 115 }
134 { 116 {
135 const SkPoint& xy = xyAtT(&span); 117 const SkPoint& xy = span->pt();
136 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { 118 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
137 topPt = xy; 119 topPt = xy;
138 if (firstT) { 120 if (firstSpan) {
139 *firstT = index; 121 *firstSpan = span;
140 } 122 }
141 } 123 }
142 if (fVerb != SkPath::kLine_Verb && !lastDone) { 124 if (fVerb != SkPath::kLine_Verb && !lastDone) {
143 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPt s, lastT, span.fT); 125 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPt s, lastT,
126 span->t());
144 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY 127 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
145 && topPt.fX > curveTop.fX)) { 128 && topPt.fX > curveTop.fX)) {
146 topPt = curveTop; 129 topPt = curveTop;
147 if (firstT) { 130 if (firstSpan) {
148 *firstT = index; 131 *firstSpan = span;
149 } 132 }
150 } 133 }
151 } 134 }
152 lastT = span.fT; 135 lastT = span->t();
153 } 136 }
154 next: 137 next:
155 lastDone = span.fDone; 138 if (span->final()) {
156 } 139 break;
140 }
141 lastDone = span->upCast()->done();
142 } while ((span = span->upCast()->next()));
157 return topPt; 143 return topPt;
158 } 144 }
159 145
160 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask , SkPathOp op) { 146 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask , int xorSuMask,
161 int sumMiWinding = updateWinding(endIndex, index); 147 SkPathOp op) {
162 int sumSuWinding = updateOppWinding(endIndex, index); 148 int sumMiWinding = this->updateWinding(end, start);
149 int sumSuWinding = this->updateOppWinding(end, start);
163 #if DEBUG_LIMIT_WIND_SUM 150 #if DEBUG_LIMIT_WIND_SUM
164 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM); 151 SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
165 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM); 152 SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
166 #endif 153 #endif
167 if (fOperand) { 154 if (this->operand()) {
168 SkTSwap<int>(sumMiWinding, sumSuWinding); 155 SkTSwap<int>(sumMiWinding, sumSuWinding);
169 } 156 }
170 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &s umSuWinding); 157 return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, & sumSuWinding);
171 } 158 }
172 159
173 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex , SkPathOp op, 160 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, Sk OpSpanBase* end,
174 int* sumMiWinding, int* sumSuWinding) { 161 SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
175 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 162 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
176 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, 163 this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
177 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 164 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
178 bool miFrom; 165 bool miFrom;
179 bool miTo; 166 bool miTo;
180 bool suFrom; 167 bool suFrom;
181 bool suTo; 168 bool suTo;
182 if (operand()) { 169 if (operand()) {
183 miFrom = (oppMaxWinding & xorMiMask) != 0; 170 miFrom = (oppMaxWinding & xorMiMask) != 0;
184 miTo = (oppSumWinding & xorMiMask) != 0; 171 miTo = (oppSumWinding & xorMiMask) != 0;
185 suFrom = (maxWinding & xorSuMask) != 0; 172 suFrom = (maxWinding & xorSuMask) != 0;
186 suTo = (sumWinding & xorSuMask) != 0; 173 suTo = (sumWinding & xorSuMask) != 0;
187 } else { 174 } else {
188 miFrom = (maxWinding & xorMiMask) != 0; 175 miFrom = (maxWinding & xorMiMask) != 0;
189 miTo = (sumWinding & xorMiMask) != 0; 176 miTo = (sumWinding & xorMiMask) != 0;
190 suFrom = (oppMaxWinding & xorSuMask) != 0; 177 suFrom = (oppMaxWinding & xorSuMask) != 0;
191 suTo = (oppSumWinding & xorSuMask) != 0; 178 suTo = (oppSumWinding & xorSuMask) != 0;
192 } 179 }
193 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; 180 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
194 #if DEBUG_ACTIVE_OP 181 #if DEBUG_ACTIVE_OP
195 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo =%d result=%d\n", 182 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo =%d result=%d\n",
196 __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT, 183 __FUNCTION__, debugID(), start->t(), end->t(),
197 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); 184 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
198 #endif 185 #endif
199 return result; 186 return result;
200 } 187 }
201 188
202 bool SkOpSegment::activeWinding(int index, int endIndex) { 189 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
203 int sumWinding = updateWinding(endIndex, index); 190 int sumWinding = updateWinding(end, start);
204 return activeWinding(index, endIndex, &sumWinding); 191 return activeWinding(start, end, &sumWinding);
205 } 192 }
206 193
207 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) { 194 bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum Winding) {
208 int maxWinding; 195 int maxWinding;
209 setUpWinding(index, endIndex, &maxWinding, sumWinding); 196 setUpWinding(start, end, &maxWinding, sumWinding);
210 bool from = maxWinding != 0; 197 bool from = maxWinding != 0;
211 bool to = *sumWinding != 0; 198 bool to = *sumWinding != 0;
212 bool result = gUnaryActiveEdge[from][to]; 199 bool result = gUnaryActiveEdge[from][to];
213 return result; 200 return result;
214 } 201 }
215 202
216 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt , 203 void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
217 SkOpSegment* other) { 204 SkPathWriter* path, bool active) const {
218 int tIndex = -1;
219 int tCount = fTs.count();
220 int oIndex = -1;
221 int oCount = other->fTs.count();
222 do {
223 ++tIndex;
224 } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
225 int tIndexStart = tIndex;
226 do {
227 ++oIndex;
228 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
229 int oIndexStart = oIndex;
230 const SkPoint* nextPt;
231 do {
232 nextPt = &fTs[++tIndex].fPt;
233 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
234 } while (startPt == *nextPt);
235 double nextT = fTs[tIndex].fT;
236 const SkPoint* oNextPt;
237 do {
238 oNextPt = &other->fTs[++oIndex].fPt;
239 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
240 } while (endPt == *oNextPt);
241 double oNextT = other->fTs[oIndex].fT;
242 // at this point, spans before and after are at:
243 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
244 // if tIndexStart == 0, no prior span
245 // if nextT == 1, no following span
246
247 // advance the span with zero winding
248 // if the following span exists (not past the end, non-zero winding)
249 // connect the two edges
250 if (!fTs[tIndexStart].fWindValue) {
251 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
252 #if DEBUG_CONCIDENT
253 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
254 __FUNCTION__, fID, other->fID, tIndexStart - 1,
255 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
256 xyAtT(tIndexStart).fY);
257 #endif
258 SkPoint copy = fTs[tIndexStart].fPt; // add t pair may move the poi nt array
259 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false, c opy);
260 }
261 if (nextT < 1 && fTs[tIndex].fWindValue) {
262 #if DEBUG_CONCIDENT
263 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
264 __FUNCTION__, fID, other->fID, tIndex,
265 fTs[tIndex].fT, xyAtT(tIndex).fX,
266 xyAtT(tIndex).fY);
267 #endif
268 SkPoint copy = fTs[tIndex].fPt; // add t pair may move the point ar ray
269 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, c opy);
270 }
271 } else {
272 SkASSERT(!other->fTs[oIndexStart].fWindValue);
273 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
274 #if DEBUG_CONCIDENT
275 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
276 __FUNCTION__, fID, other->fID, oIndexStart - 1,
277 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
278 other->xyAtT(oIndexStart).fY);
279 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex]. fT);
280 #endif
281 }
282 if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
283 #if DEBUG_CONCIDENT
284 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
285 __FUNCTION__, fID, other->fID, oIndex,
286 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
287 other->xyAtT(oIndex).fY);
288 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart]. fT);
289 #endif
290 }
291 }
292 }
293
294 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
295 SkOpSegment* other) {
296 // walk this to startPt
297 // walk other to startPt
298 // if either is > 0, add a pointer to the other, copying adjacent winding
299 int tIndex = -1;
300 int oIndex = -1;
301 do {
302 ++tIndex;
303 } while (startPt != fTs[tIndex].fPt);
304 int ttIndex = tIndex;
305 bool checkOtherTMatch = false;
306 do {
307 const SkOpSpan& span = fTs[ttIndex];
308 if (startPt != span.fPt) {
309 break;
310 }
311 if (span.fOther == other && span.fPt == startPt) {
312 checkOtherTMatch = true;
313 break;
314 }
315 } while (++ttIndex < count());
316 do {
317 ++oIndex;
318 } while (startPt != other->fTs[oIndex].fPt);
319 bool skipAdd = false;
320 if (checkOtherTMatch) {
321 int ooIndex = oIndex;
322 do {
323 const SkOpSpan& oSpan = other->fTs[ooIndex];
324 if (startPt != oSpan.fPt) {
325 break;
326 }
327 if (oSpan.fT == fTs[ttIndex].fOtherT) {
328 skipAdd = true;
329 break;
330 }
331 } while (++ooIndex < other->count());
332 }
333 if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) {
334 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
335 }
336 SkPoint nextPt = startPt;
337 do {
338 const SkPoint* workPt;
339 do {
340 workPt = &fTs[++tIndex].fPt;
341 } while (nextPt == *workPt);
342 const SkPoint* oWorkPt;
343 do {
344 oWorkPt = &other->fTs[++oIndex].fPt;
345 } while (nextPt == *oWorkPt);
346 nextPt = *workPt;
347 double tStart = fTs[tIndex].fT;
348 double oStart = other->fTs[oIndex].fT;
349 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
350 break;
351 }
352 if (*workPt == *oWorkPt) {
353 addTPair(tStart, other, oStart, false, nextPt);
354 }
355 } while (endPt != nextPt);
356 }
357
358 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
359 init(pts, SkPath::kCubic_Verb, operand, evenOdd);
360 fBounds.setCubicBounds(pts);
361 }
362
363 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active ) const {
364 SkPoint edge[4]; 205 SkPoint edge[4];
365 const SkPoint* ePtr; 206 const SkPoint* ePtr;
366 int lastT = fTs.count() - 1; 207 if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead) ) {
367 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0 )) {
368 ePtr = fPts; 208 ePtr = fPts;
369 } else { 209 } else {
370 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) 210 // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
371 subDivide(start, end, edge); 211 subDivide(start, end, edge);
372 ePtr = edge; 212 ePtr = edge;
373 } 213 }
374 if (active) { 214 if (active) {
375 bool reverse = ePtr == fPts && start != 0; 215 bool reverse = ePtr == fPts && start != &fHead;
376 if (reverse) { 216 if (reverse) {
377 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); 217 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
378 switch (fVerb) { 218 switch (fVerb) {
379 case SkPath::kLine_Verb: 219 case SkPath::kLine_Verb:
380 path->deferredLine(ePtr[0]); 220 path->deferredLine(ePtr[0]);
381 break; 221 break;
382 case SkPath::kQuad_Verb: 222 case SkPath::kQuad_Verb:
383 path->quadTo(ePtr[1], ePtr[0]); 223 path->quadTo(ePtr[1], ePtr[0]);
384 break; 224 break;
385 case SkPath::kCubic_Verb: 225 case SkPath::kCubic_Verb:
386 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); 226 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
387 break; 227 break;
388 default: 228 default:
389 SkASSERT(0); 229 SkASSERT(0);
390 } 230 }
391 // return ePtr[0];
392 } else { 231 } else {
393 path->deferredMoveLine(ePtr[0]); 232 path->deferredMoveLine(ePtr[0]);
394 switch (fVerb) { 233 switch (fVerb) {
395 case SkPath::kLine_Verb: 234 case SkPath::kLine_Verb:
396 path->deferredLine(ePtr[1]); 235 path->deferredLine(ePtr[1]);
397 break; 236 break;
398 case SkPath::kQuad_Verb: 237 case SkPath::kQuad_Verb:
399 path->quadTo(ePtr[1], ePtr[2]); 238 path->quadTo(ePtr[1], ePtr[2]);
400 break; 239 break;
401 case SkPath::kCubic_Verb: 240 case SkPath::kCubic_Verb:
402 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); 241 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
403 break; 242 break;
404 default: 243 default:
405 SkASSERT(0); 244 SkASSERT(0);
406 } 245 }
407 } 246 }
408 } 247 }
409 // return ePtr[SkPathOpsVerbToPoints(fVerb)]; 248 }
410 } 249
411 250 SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc ator) {
412 void SkOpSegment::addEndSpan(int endIndex) { 251 SkOpSpanBase* existing = NULL;
413 SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny 252 SkOpSpanBase* test = &fHead;
414 // && approximately_greater_than_one(span(endIndex).fT) 253 double testT;
415 ));
416 int spanCount = fTs.count();
417 int startIndex = endIndex - 1;
418 while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
419 --startIndex;
420 SkASSERT(startIndex > 0);
421 --endIndex;
422 }
423 SkOpAngle& angle = fAngles.push_back();
424 angle.set(this, spanCount - 1, startIndex);
425 #if DEBUG_ANGLE
426 debugCheckPointsEqualish(endIndex, spanCount);
427 #endif
428 setFromAngle(endIndex, &angle);
429 }
430
431 void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) {
432 int spanCount = fTs.count();
433 do { 254 do {
434 fTs[endIndex].fFromAngle = angle; 255 if ((testT = test->ptT()->fT) >= t) {
435 } while (++endIndex < spanCount); 256 if (testT == t) {
436 } 257 existing = test;
437 258 }
438 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { 259 break;
439 init(pts, SkPath::kLine_Verb, operand, evenOdd); 260 }
440 fBounds.set(pts, 2); 261 } while ((test = test->upCast()->next()));
441 } 262 SkOpPtT* result;
442 263 if (existing && existing->contains(opp)) {
443 // add 2 to edge or out of range values to get T extremes 264 result = existing->ptT();
444 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) { 265 } else {
445 SkOpSpan& span = fTs[index]; 266 result = this->addT(t, SkOpSegment::kNoAlias, allocator);
446 if (precisely_zero(otherT)) { 267 }
447 otherT = 0; 268 SkASSERT(result);
448 } else if (precisely_equal(otherT, 1)) { 269 return result;
449 otherT = 1; 270 }
450 } 271
451 span.fOtherT = otherT; 272 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle* * anglePtr,
452 span.fOtherIndex = otherIndex; 273 SkChunkAlloc* allocator) {
453 } 274 SkOpSpan* startSpan = fTail.prev();
454 275 SkASSERT(startSpan);
455 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { 276 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
456 init(pts, SkPath::kQuad_Verb, operand, evenOdd); 277 *anglePtr = angle;
457 fBounds.setQuadBounds(pts); 278 angle->set(&fTail, startSpan);
458 } 279 fTail.setFromAngle(angle);
459 280 SkOpSegment* other = NULL; // these initializations silence a release build warning
460 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle* * anglePtr) { 281 SkOpSpan* oStartSpan = NULL;
461 int spanIndex = count() - 1; 282 SkOpSpanBase* oEndSpan = NULL;
462 int startIndex = nextExactSpan(spanIndex, -1); 283 SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT;
463 SkASSERT(startIndex >= 0); 284 while ((ptT = ptT->next()) != startPtT) {
464 SkOpAngle& angle = fAngles.push_back(); 285 other = ptT->segment();
465 *anglePtr = &angle; 286 oStartSpan = ptT->span()->upCastable();
466 angle.set(this, spanIndex, startIndex); 287 if (oStartSpan && oStartSpan->windValue()) {
467 setFromAngle(spanIndex, &angle); 288 oEndSpan = oStartSpan->next();
468 SkOpSegment* other; 289 break;
469 int oStartIndex, oEndIndex; 290 }
470 do { 291 oEndSpan = ptT->span();
471 const SkOpSpan& span = fTs[spanIndex]; 292 oStartSpan = oEndSpan->prev();
472 SkASSERT(span.fT > 0); 293 if (oStartSpan && oStartSpan->windValue()) {
473 other = span.fOther; 294 break;
474 oStartIndex = span.fOtherIndex; 295 }
475 oEndIndex = other->nextExactSpan(oStartIndex, 1); 296 }
476 if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) { 297 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
477 break; 298 oAngle->set(oStartSpan, oEndSpan);
478 } 299 oStartSpan->setToAngle(oAngle);
479 oEndIndex = oStartIndex;
480 oStartIndex = other->nextExactSpan(oEndIndex, -1);
481 --spanIndex;
482 } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum);
483 SkOpAngle& oAngle = other->fAngles.push_back();
484 oAngle.set(other, oStartIndex, oEndIndex);
485 other->setToAngle(oEndIndex, &oAngle);
486 *otherPtr = other; 300 *otherPtr = other;
487 return &oAngle; 301 return oAngle;
488 } 302 }
489 303
490 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) { 304 SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) {
491 int endIndex = nextExactSpan(0, 1);
492 SkASSERT(endIndex > 0);
493 SkOpAngle& angle = fAngles.push_back();
494 *anglePtr = &angle;
495 angle.set(this, 0, endIndex);
496 setToAngle(endIndex, &angle);
497 int spanIndex = 0;
498 SkOpSegment* other;
499 int oStartIndex, oEndIndex;
500 do {
501 const SkOpSpan& span = fTs[spanIndex];
502 SkASSERT(span.fT < 1);
503 other = span.fOther;
504 oEndIndex = span.fOtherIndex;
505 oStartIndex = other->nextExactSpan(oEndIndex, -1);
506 if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) {
507 break;
508 }
509 oStartIndex = oEndIndex;
510 oEndIndex = other->nextExactSpan(oStartIndex, 1);
511 ++spanIndex;
512 } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue);
513 SkOpAngle& oAngle = other->fAngles.push_back();
514 oAngle.set(other, oEndIndex, oStartIndex);
515 other->setFromAngle(oEndIndex, &oAngle);
516 *otherPtr = other;
517 return &oAngle;
518 }
519
520 SkOpAngle* SkOpSegment::addSingletonAngles(int step) {
521 SkOpSegment* other; 305 SkOpSegment* other;
522 SkOpAngle* angle, * otherAngle; 306 SkOpAngle* angle, * otherAngle;
523 if (step > 0) { 307 if (step > 0) {
524 otherAngle = addSingletonAngleUp(&other, &angle); 308 otherAngle = addSingletonAngleUp(&other, &angle, allocator);
525 } else { 309 } else {
526 otherAngle = addSingletonAngleDown(&other, &angle); 310 otherAngle = addSingletonAngleDown(&other, &angle, allocator);
527 } 311 }
528 angle->insert(otherAngle); 312 angle->insert(otherAngle);
529 return angle; 313 return angle;
530 } 314 }
531 315
532 void SkOpSegment::addStartSpan(int endIndex) { 316 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
533 int index = 0; 317 SkChunkAlloc* allocator) {
534 SkOpAngle& angle = fAngles.push_back(); 318 SkOpSpanBase* endSpan = fHead.next();
535 angle.set(this, index, endIndex); 319 SkASSERT(endSpan);
536 #if DEBUG_ANGLE 320 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
537 debugCheckPointsEqualish(index, endIndex); 321 *anglePtr = angle;
322 angle->set(&fHead, endSpan);
323 fHead.setToAngle(angle);
324 SkOpSegment* other = NULL; // these initializations silence a release build warning
325 SkOpSpan* oStartSpan = NULL;
326 SkOpSpanBase* oEndSpan = NULL;
327 SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT;
328 while ((ptT = ptT->next()) != startPtT) {
329 other = ptT->segment();
330 oEndSpan = ptT->span();
331 oStartSpan = oEndSpan->prev();
332 if (oStartSpan && oStartSpan->windValue()) {
333 break;
334 }
335 oStartSpan = oEndSpan->upCastable();
336 if (oStartSpan && oStartSpan->windValue()) {
337 oEndSpan = oStartSpan->next();
338 break;
339 }
340 }
341 SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
342 oAngle->set(oEndSpan, oStartSpan);
343 oEndSpan->setFromAngle(oAngle);
344 *otherPtr = other;
345 return oAngle;
346 }
347
348 SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* alloca tor) {
349 debugValidate();
350 SkPoint pt = this->ptAtT(t);
351 SkOpSpanBase* span = &fHead;
352 do {
353 SkOpPtT* result = span->ptT();
354 if (t == result->fT) {
355 return result;
356 }
357 if (this->match(result, this, t, pt)) {
358 // see if any existing alias matches segment, pt, and t
359 SkOpPtT* loop = result->next();
360 bool duplicatePt = false;
361 while (loop != result) {
362 bool ptMatch = loop->fPt == pt;
363 if (loop->segment() == this && loop->fT == t && ptMatch) {
364 return result;
365 }
366 duplicatePt |= ptMatch;
367 loop = loop->next();
368 }
369 if (kNoAlias == allowAlias) {
370 return result;
371 }
372 SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
373 alias->init(result->span(), t, pt, duplicatePt);
374 result->insert(alias);
375 result->span()->unaligned();
376 this->debugValidate();
377 #if DEBUG_ADD_T
378 SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
379 alias->segment()->debugID(), alias->span()->debugID());
538 #endif 380 #endif
539 setToAngle(endIndex, &angle); 381 return alias;
540 } 382 }
541 383 if (t < result->fT) {
542 void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) { 384 SkOpSpan* prev = result->span()->prev();
543 int index = 0; 385 SkOpSpan* span = insert(prev, allocator);
386 span->init(this, prev, t, pt);
387 this->debugValidate();
388 #if DEBUG_ADD_T
389 SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
390 span->segment()->debugID(), span->debugID());
391 #endif
392 return span->ptT();
393 }
394 SkASSERT(span != &fTail);
395 } while ((span = span->upCast()->next()));
396 SkASSERT(0);
397 return NULL;
398 }
399
400 // choose a solitary t and pt value; remove aliases; align the opposite ends
401 void SkOpSegment::align() {
402 debugValidate();
403 SkOpSpanBase* span = &fHead;
404 if (!span->aligned()) {
405 span->alignEnd(0, fPts[0]);
406 }
407 while ((span = span->upCast()->next())) {
408 if (span == &fTail) {
409 break;
410 }
411 span->align();
412 }
413 if (!span->aligned()) {
414 span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
415 }
416 debugValidate();
417 }
418
419 bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT,
420 const SkOpSpanBase* greater) {
421 if (lesser->t() > greater->t()) {
422 SkTSwap<const SkOpSpanBase*>(lesser, greater);
423 }
424 return approximately_between(lesser->t(), testT, greater->t());
425 }
426
427 void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
428 bool activePrior = !fHead.isCanceled();
429 if (activePrior && !fHead.simple()) {
430 addStartSpan(allocator);
431 }
432 SkOpSpan* prior = &fHead;
433 SkOpSpanBase* spanBase = fHead.next();
434 while (spanBase != &fTail) {
435 if (activePrior) {
436 SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocato r);
437 priorAngle->set(spanBase, prior);
438 spanBase->setFromAngle(priorAngle);
439 }
440 SkOpSpan* span = spanBase->upCast();
441 bool active = !span->isCanceled();
442 SkOpSpanBase* next = span->next();
443 if (active) {
444 SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
445 angle->set(span, next);
446 span->setToAngle(angle);
447 }
448 activePrior = active;
449 prior = span;
450 spanBase = next;
451 }
452 if (activePrior && !fTail.simple()) {
453 addEndSpan(allocator);
454 }
455 }
456
457 void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al locator) {
458 SkOpSpanBase* base = &fHead;
459 SkOpSpan* span;
544 do { 460 do {
545 fTs[index].fToAngle = angle; 461 SkOpAngle* angle = base->fromAngle();
546 } while (++index < endIndex); 462 if (angle && angle->fCheckCoincidence) {
547 } 463 angle->checkNearCoincidence();
548 464 }
549 // Defer all coincident edge processing until 465 if (base->final()) {
550 // after normal intersections have been computed 466 break;
551 467 }
552 // no need to be tricky; insert in normal T order 468 span = base->upCast();
553 // resolve overlapping ts when considering coincidence later 469 angle = span->toAngle();
554 470 if (angle && angle->fCheckCoincidence) {
555 // add non-coincident intersection. Resulting edges are sorted in T. 471 angle->checkNearCoincidence();
556 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { 472 }
557 SkASSERT(this != other || fVerb == SkPath::kCubic_Verb); 473 } while ((base = span->next()));
558 #if 0 // this needs an even rougher association to be useful 474 }
559 SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt)); 475
560 #endif 476 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of -polygon-points-are-in-clockwise-order
561 const SkPoint& firstPt = fPts[0]; 477 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const {
562 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; 478 SkASSERT(fVerb != SkPath::kLine_Verb);
563 SkASSERT(newT == 0 || !precisely_zero(newT)); 479 SkPoint edge[4];
564 SkASSERT(newT == 1 || !precisely_equal(newT, 1)); 480 if (fVerb == SkPath::kCubic_Verb) {
565 // FIXME: in the pathological case where there is a ton of intercepts, 481 double startT = start->t();
566 // binary search? 482 double endT = end->t();
567 int insertedAt = -1; 483 bool flip = startT > endT;
568 int tCount = fTs.count(); 484 SkDCubic cubic;
569 for (int index = 0; index < tCount; ++index) { 485 cubic.set(fPts);
570 // OPTIMIZATION: if there are three or more identical Ts, then 486 double inflectionTs[2];
571 // the fourth and following could be further insertion-sorted so 487 int inflections = cubic.findInflections(inflectionTs);
572 // that all the edges are clockwise or counterclockwise. 488 for (int index = 0; index < inflections; ++index) {
573 // This could later limit segment tests to the two adjacent 489 double inflectionT = inflectionTs[index];
574 // neighbors, although it doesn't help with determining which 490 if (between(startT, inflectionT, endT)) {
575 // circular direction to go in. 491 if (flip) {
576 const SkOpSpan& span = fTs[index]; 492 if (inflectionT != endT) {
577 if (newT < span.fT) { 493 startT = inflectionT;
578 insertedAt = index; 494 }
579 break;
580 }
581 if (newT == span.fT) {
582 if (pt == span.fPt) {
583 insertedAt = index;
584 break;
585 }
586 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1 )) {
587 insertedAt = index;
588 break;
589 }
590 }
591 }
592 SkOpSpan* span;
593 if (insertedAt >= 0) {
594 span = fTs.insert(insertedAt);
595 } else {
596 insertedAt = tCount;
597 span = fTs.append();
598 }
599 span->fT = newT;
600 span->fOtherT = -1;
601 span->fOther = other;
602 span->fPt = pt;
603 #if 0
604 // cubics, for instance, may not be exact enough to satisfy this check (e.g. , cubicOp69d)
605 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
606 && approximately_equal(xyAtT(newT).fY, pt.fY));
607 #endif
608 span->fFromAngle = NULL;
609 span->fToAngle = NULL;
610 span->fWindSum = SK_MinS32;
611 span->fOppSum = SK_MinS32;
612 span->fWindValue = 1;
613 span->fOppValue = 0;
614 span->fChased = false;
615 span->fCoincident = false;
616 span->fLoop = false;
617 span->fNear = false;
618 span->fMultiple = false;
619 span->fSmall = false;
620 span->fTiny = false;
621 if ((span->fDone = newT == 1)) {
622 ++fDoneSpans;
623 }
624 setSpanFlags(pt, newT, span);
625 return insertedAt;
626 }
627
628 void SkOpSegment::setSpanFlags(const SkPoint& pt, double newT, SkOpSpan* span) {
629 int less = -1;
630 // FIXME: note that this relies on spans being a continguous array
631 // find range of spans with nearly the same point as this one
632 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the mom ent
633 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
634 if (fVerb == SkPath::kCubic_Verb) {
635 double tInterval = newT - span[less].fT;
636 double tMid = newT - tInterval / 2;
637 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
638 if (!midPt.approximatelyEqual(xyAtT(span))) {
639 break;
640 }
641 }
642 --less;
643 }
644 int more = 1;
645 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the mom ent
646 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt )) {
647 if (fVerb == SkPath::kCubic_Verb) {
648 double tEndInterval = span[more].fT - newT;
649 double tMid = newT - tEndInterval / 2;
650 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
651 if (!midEndPt.approximatelyEqual(xyAtT(span))) {
652 break;
653 }
654 }
655 ++more;
656 }
657 ++less;
658 --more;
659 while (more - 1 > less && span[more].fPt == span[more - 1].fPt
660 && span[more].fT == span[more - 1].fT) {
661 --more;
662 }
663 if (less == more) {
664 return;
665 }
666 if (precisely_negative(span[more].fT - span[less].fT)) {
667 return;
668 }
669 // if the total range of t values is big enough, mark all tiny
670 bool tiny = span[less].fPt == span[more].fPt;
671 int index = less;
672 do {
673 fSmall = span[index].fSmall = true;
674 fTiny |= span[index].fTiny = tiny;
675 if (!span[index].fDone) {
676 span[index].fDone = true;
677 ++fDoneSpans;
678 }
679 } while (++index < more);
680 return;
681 }
682
683 void SkOpSegment::resetSpanFlags() {
684 fSmall = fTiny = false;
685 fDoneSpans = 0;
686 int start = 0;
687 int last = this->count() - 1;
688 do {
689 SkOpSpan* startSpan = &this->fTs[start];
690 double startT = startSpan->fT;
691 startSpan->fSmall = startSpan->fTiny = false; // sets range initial
692 bool terminus = startT == 1;
693 if ((startSpan->fDone = !startSpan->fWindValue | terminus)) {
694 ++fDoneSpans;
695 }
696 ++start; // range initial + 1
697 if (terminus) {
698 continue;
699 }
700 const SkPoint& pt = startSpan->fPt;
701 int end = start; // range initial + 1
702 while (end <= last) {
703 const SkOpSpan& endSpan = this->span(end);
704 if (!AlmostEqualUlps(endSpan.fPt, pt)) {
705 break;
706 }
707 if (fVerb == SkPath::kCubic_Verb) {
708 double tMid = (startSpan->fT + endSpan.fT) / 2;
709 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
710 if (!midEndPt.approximatelyEqual(xyAtT(startSpan))) {
711 break;
712 }
713 }
714 ++end;
715 }
716 if (start == end) { // end == range final + 1
717 continue;
718 }
719 while (--end >= start) { // end == range final
720 const SkOpSpan& endSpan = this->span(end);
721 const SkOpSpan& priorSpan = this->span(end - 1);
722 if (endSpan.fPt != priorSpan.fPt || endSpan.fT != priorSpan.fT) {
723 break; // end == range final + 1
724 }
725 }
726 if (end < start) { // end == range final + 1
727 continue;
728 }
729 int index = start - 1; // index == range initial
730 start = end; // start = range final + 1
731 const SkOpSpan& nextSpan = this->span(end);
732 if (precisely_negative(nextSpan.fT - startSpan->fT)) {
733 while (++index < end) {
734 startSpan = &this->fTs[index];
735 startSpan->fSmall = startSpan->fTiny = false; // sets range ini tial + 1
736 if ((startSpan->fDone = !startSpan->fWindValue)) {
737 ++fDoneSpans;
738 }
739 }
740 continue;
741 }
742 if (!startSpan->fWindValue) {
743 --fDoneSpans; // added back below
744 }
745 bool tiny = nextSpan.fPt == startSpan->fPt;
746 do {
747 fSmall = startSpan->fSmall = true; // sets range initial
748 fTiny |= startSpan->fTiny = tiny;
749 startSpan->fDone = true;
750 ++fDoneSpans;
751 startSpan = &this->fTs[++index];
752 } while (index < end); // loop through tiny small range end (last)
753 } while (start <= last);
754 }
755
756 // set spans from start to end to decrement by one
757 // note this walks other backwards
758 // FIXME: there's probably an edge case that can be constructed where
759 // two span in one segment are separated by float epsilon on one span but
760 // not the other, if one segment is very small. For this
761 // case the counts asserted below may or may not be enough to separate the
762 // spans. Even if the counts work out, what if the spans aren't correctly
763 // sorted? It feels better in such a case to match the span's other span
764 // pointer since both coincident segments must contain the same spans.
765 // FIXME? It seems that decrementing by one will fail for complex paths that
766 // have three or more coincident edges. Shouldn't this subtract the difference
767 // between the winding values?
768 /* |--> |-->
769 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>> 4
770 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0
771 ^ ^ <--| <--|
772 startPt endPt test/oTest first pos test/oTest final po s
773 */
774 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS egment* other) {
775 bool binary = fOperand != other->fOperand;
776 int index = 0;
777 while (startPt != fTs[index].fPt) {
778 SkASSERT(index < fTs.count());
779 ++index;
780 }
781 while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
782 --index;
783 }
784 bool oFoundEnd = false;
785 int oIndex = other->fTs.count();
786 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match
787 SkASSERT(oIndex > 0);
788 }
789 double oStartT = other->fTs[oIndex].fT;
790 // look for first point beyond match
791 while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other ->fTs[oIndex].fT)) {
792 if (!oIndex) {
793 return; // tiny spans may move in the wrong direction
794 }
795 }
796 SkOpSpan* test = &fTs[index];
797 SkOpSpan* oTest = &other->fTs[oIndex];
798 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
799 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
800 bool decrement, track, bigger;
801 int originalWindValue;
802 const SkPoint* testPt;
803 const SkPoint* oTestPt;
804 do {
805 SkASSERT(test->fT < 1);
806 SkASSERT(oTest->fT < 1);
807 decrement = test->fWindValue && oTest->fWindValue;
808 track = test->fWindValue || oTest->fWindValue;
809 bigger = test->fWindValue >= oTest->fWindValue;
810 testPt = &test->fPt;
811 double testT = test->fT;
812 oTestPt = &oTest->fPt;
813 double oTestT = oTest->fT;
814 do {
815 if (decrement) {
816 if (binary && bigger) {
817 test->fOppValue--;
818 } else { 495 } else {
819 decrementSpan(test); 496 if (inflectionT != startT) {
820 } 497 endT = inflectionT;
821 } else if (track) {
822 TrackOutsidePair(&outsidePts, *testPt, *oTestPt);
823 }
824 SkASSERT(index < fTs.count() - 1);
825 test = &fTs[++index];
826 } while (*testPt == test->fPt || precisely_equal(testT, test->fT));
827 originalWindValue = oTest->fWindValue;
828 do {
829 SkASSERT(oTest->fT < 1);
830 SkASSERT(originalWindValue == oTest->fWindValue);
831 if (decrement) {
832 if (binary && !bigger) {
833 oTest->fOppValue--;
834 } else {
835 other->decrementSpan(oTest);
836 }
837 } else if (track) {
838 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
839 }
840 if (!oIndex) {
841 break;
842 }
843 oFoundEnd |= endPt == oTest->fPt;
844 oTest = &other->fTs[--oIndex];
845 } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
846 } while (endPt != test->fPt && test->fT < 1);
847 // FIXME: determine if canceled edges need outside ts added
848 if (!oFoundEnd) {
849 for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) {
850 SkOpSpan* oTst2 = &other->fTs[oIdx2];
851 if (originalWindValue != oTst2->fWindValue) {
852 goto skipAdvanceOtherCancel;
853 }
854 if (!oTst2->fWindValue) {
855 goto skipAdvanceOtherCancel;
856 }
857 if (endPt == other->fTs[oIdx2].fPt) {
858 break;
859 }
860 }
861 oFoundEnd = endPt == oTest->fPt;
862 do {
863 SkASSERT(originalWindValue == oTest->fWindValue);
864 if (decrement) {
865 if (binary && !bigger) {
866 oTest->fOppValue--;
867 } else {
868 other->decrementSpan(oTest);
869 }
870 } else if (track) {
871 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
872 }
873 if (!oIndex) {
874 break;
875 }
876 oTest = &other->fTs[--oIndex];
877 oFoundEnd |= endPt == oTest->fPt;
878 } while (!oFoundEnd || endPt == oTest->fPt);
879 }
880 skipAdvanceOtherCancel:
881 int outCount = outsidePts.count();
882 if (!done() && outCount) {
883 addCancelOutsides(outsidePts[0], outsidePts[1], other);
884 if (outCount > 2) {
885 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1] , other);
886 }
887 }
888 if (!other->done() && oOutsidePts.count()) {
889 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
890 }
891 setCoincidentRange(startPt, endPt, other);
892 other->setCoincidentRange(startPt, endPt, this);
893 }
894
895 int SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
896 // if the tail nearly intersects itself but not quite, the caller records th is separately
897 int result = addT(this, pt, newT);
898 SkOpSpan* span = &fTs[result];
899 fLoop = span->fLoop = true;
900 return result;
901 }
902
903 // find the starting or ending span with an existing loop of angles
904 // FIXME? replicate for all identical starting/ending spans?
905 // OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
906 // FIXME? assert that only one other span has a valid windValue or oppValue
907 void SkOpSegment::addSimpleAngle(int index) {
908 SkOpSpan* span = &fTs[index];
909 int idx;
910 int start, end;
911 if (span->fT == 0) {
912 idx = 0;
913 span = &fTs[0];
914 do {
915 if (span->fToAngle) {
916 SkASSERT(span->fToAngle->loopCount() == 2);
917 SkASSERT(!span->fFromAngle);
918 span->fFromAngle = span->fToAngle->next();
919 return;
920 }
921 span = &fTs[++idx];
922 } while (span->fT == 0);
923 SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0);
924 addStartSpan(idx);
925 start = 0;
926 end = idx;
927 } else {
928 idx = count() - 1;
929 span = &fTs[idx];
930 do {
931 if (span->fFromAngle) {
932 SkASSERT(span->fFromAngle->loopCount() == 2);
933 SkASSERT(!span->fToAngle);
934 span->fToAngle = span->fFromAngle->next();
935 return;
936 }
937 span = &fTs[--idx];
938 } while (span->fT == 1);
939 SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1);
940 addEndSpan(++idx);
941 start = idx;
942 end = count();
943 }
944 SkOpSegment* other;
945 SkOpSpan* oSpan;
946 index = start;
947 do {
948 span = &fTs[index];
949 other = span->fOther;
950 int oFrom = span->fOtherIndex;
951 oSpan = &other->fTs[oFrom];
952 if (oSpan->fT < 1 && oSpan->fWindValue) {
953 break;
954 }
955 if (oSpan->fT == 0) {
956 continue;
957 }
958 oFrom = other->nextExactSpan(oFrom, -1);
959 SkOpSpan* oFromSpan = &other->fTs[oFrom];
960 SkASSERT(oFromSpan->fT < 1);
961 if (oFromSpan->fWindValue) {
962 break;
963 }
964 } while (++index < end);
965 SkOpAngle* angle, * oAngle;
966 if (span->fT == 0) {
967 SkASSERT(span->fOtherIndex - 1 >= 0);
968 SkASSERT(span->fOtherT == 1);
969 SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1 ));
970 SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex));
971 SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
972 other->addEndSpan(span->fOtherIndex);
973 angle = span->fToAngle;
974 oAngle = oSpan->fFromAngle;
975 } else {
976 SkASSERT(span->fOtherIndex + 1 < other->count());
977 SkASSERT(span->fOtherT == 0);
978 SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
979 || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL
980 && other->fTs[span->fOtherIndex + 1].fToAngle == NULL)));
981 int oIndex = 1;
982 do {
983 const SkOpSpan& osSpan = other->span(oIndex);
984 if (osSpan.fFromAngle || osSpan.fT > 0) {
985 break;
986 }
987 ++oIndex;
988 SkASSERT(oIndex < other->count());
989 } while (true);
990 other->addStartSpan(oIndex);
991 angle = span->fFromAngle;
992 oAngle = oSpan->fToAngle;
993 }
994 angle->insert(oAngle);
995 }
996
997 void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) {
998 debugValidate();
999 int count = this->count();
1000 for (int index = 0; index < count; ++index) {
1001 SkOpSpan& span = fTs[index];
1002 if (!span.fMultiple) {
1003 continue;
1004 }
1005 int end = nextExactSpan(index, 1);
1006 SkASSERT(end > index + 1);
1007 const SkPoint& thisPt = span.fPt;
1008 while (index < end - 1) {
1009 SkOpSegment* other1 = span.fOther;
1010 int oCnt = other1->count();
1011 for (int idx2 = index + 1; idx2 < end; ++idx2) {
1012 SkOpSpan& span2 = fTs[idx2];
1013 SkOpSegment* other2 = span2.fOther;
1014 for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
1015 SkOpSpan& oSpan = other1->fTs[oIdx];
1016 if (oSpan.fOther != other2) {
1017 continue;
1018 }
1019 if (oSpan.fPt == thisPt) {
1020 goto skipExactMatches;
1021 } 498 }
1022 } 499 }
1023 for (int oIdx = 0; oIdx < oCnt; ++oIdx) { 500 }
1024 SkOpSpan& oSpan = other1->fTs[oIdx]; 501 }
1025 if (oSpan.fOther != other2) { 502 SkDCubic part = cubic.subDivide(startT, endT);
1026 continue; 503 for (int index = 0; index < 4; ++index) {
1027 } 504 edge[index] = part[index].asSkPoint();
1028 if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) { 505 }
1029 SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex]; 506 } else {
1030 if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT) 507 subDivide(start, end, edge);
1031 || zero_or_one(span2.fOtherT) || zero_or_one(oSp an2.fT)) { 508 }
1032 return; 509 bool sumSet = false;
1033 } 510 int points = SkPathOpsVerbToPoints(fVerb);
1034 if (!way_roughly_equal(span.fOtherT, oSpan.fT) 511 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY) ;
1035 || !way_roughly_equal(span2.fOtherT, oSpan2.fT) 512 if (!sumSet) {
1036 || !way_roughly_equal(span2.fOtherT, oSpan.fOthe rT) 513 for (int idx = 0; idx < points; ++idx){
1037 || !way_roughly_equal(span.fOtherT, oSpan2.fOthe rT)) { 514 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[ idx].fY);
1038 return; 515 }
1039 } 516 }
1040 alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT, 517 if (fVerb == SkPath::kCubic_Verb) {
1041 other2, &oSpan, alignedArray); 518 SkDCubic cubic;
1042 alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT, 519 cubic.set(edge);
1043 other1, &oSpan2, alignedArray); 520 *swap = sum > 0 && !cubic.monotonicInY();
1044 break; 521 } else {
1045 } 522 SkDQuad quad;
1046 } 523 quad.set(edge);
1047 skipExactMatches: 524 *swap = sum > 0 && !quad.monotonicInY();
1048 ; 525 }
1049 } 526 return sum <= 0;
1050 ++index; 527 }
1051 } 528
1052 } 529 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle ,
1053 debugValidate(); 530 SkOpAngle::IncludeType includeType) {
1054 } 531 const SkOpSegment* baseSegment = baseAngle->segment();
1055 532 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1056 void SkOpSegment::alignRange(int lower, int upper, 533 int sumSuWinding;
1057 const SkOpSegment* other, int oLower, int oUpper) { 534 bool binary = includeType >= SkOpAngle::kBinarySingle;
1058 for (int oIndex = oLower; oIndex <= oUpper; ++oIndex) {
1059 const SkOpSpan& oSpan = other->span(oIndex);
1060 const SkOpSegment* oOther = oSpan.fOther;
1061 if (oOther == this) {
1062 continue;
1063 }
1064 SkOpSpan* matchSpan;
1065 int matchIndex;
1066 const SkOpSpan* refSpan;
1067 for (int iIndex = lower; iIndex <= upper; ++iIndex) {
1068 const SkOpSpan& iSpan = this->span(iIndex);
1069 const SkOpSegment* iOther = iSpan.fOther;
1070 if (iOther == other) {
1071 continue;
1072 }
1073 if (iOther == oOther) {
1074 goto nextI;
1075 }
1076 }
1077 {
1078 // oSpan does not have a match in this
1079 int iCount = this->count();
1080 const SkOpSpan* iMatch = NULL;
1081 double iMatchTDiff;
1082 matchIndex = -1;
1083 for (int iIndex = 0; iIndex < iCount; ++iIndex) {
1084 const SkOpSpan& iSpan = this->span(iIndex);
1085 const SkOpSegment* iOther = iSpan.fOther;
1086 if (iOther != oOther) {
1087 continue;
1088 }
1089 double testTDiff = fabs(iSpan.fOtherT - oSpan.fOtherT);
1090 if (!iMatch || testTDiff < iMatchTDiff) {
1091 matchIndex = iIndex;
1092 iMatch = &iSpan;
1093 iMatchTDiff = testTDiff;
1094 }
1095 }
1096 if (matchIndex < 0) {
1097 continue; // the entry is missing, & will be picked up later (F IXME: fix it here?)
1098 }
1099 matchSpan = &this->fTs[matchIndex];
1100 refSpan = &this->span(lower);
1101 if (!SkDPoint::ApproximatelyEqual(matchSpan->fPt, refSpan->fPt)) {
1102 goto nextI;
1103 }
1104 if (matchIndex != lower - 1 && matchIndex != upper + 1) {
1105 // the consecutive spans need to be rearranged to get the missin g one close
1106 continue; // FIXME: more work to do
1107 }
1108 }
1109 {
1110 this->fixOtherTIndex();
1111 SkScalar newT;
1112 if (matchSpan->fT != 0 && matchSpan->fT != 1) {
1113 newT = matchSpan->fT = refSpan->fT;
1114 matchSpan->fOther->fTs[matchSpan->fOtherIndex].fOtherT = refSpan ->fT;
1115 } else { // leave span at the start or end there and adjust the nei ghbors
1116 newT = matchSpan->fT;
1117 for (int iIndex = lower; iIndex <= upper; ++iIndex) {
1118 matchSpan = &this->fTs[iIndex];
1119 matchSpan->fT = newT;
1120 matchSpan->fOther->fTs[matchSpan->fOtherIndex].fOtherT = new T;
1121 }
1122 }
1123 this->resetSpanFlags(); // fix up small / tiny / done
1124 // align ts of other ranges with adjacent spans that match the align ed points
1125 lower = SkTMin(lower, matchIndex);
1126 while (lower > 0) {
1127 const SkOpSpan& span = this->span(lower - 1);
1128 if (span.fT != newT) {
1129 break;
1130 }
1131 --lower;
1132 }
1133 upper = SkTMax(upper, matchIndex);
1134 int last = this->count() - 1;
1135 while (upper < last) {
1136 const SkOpSpan& span = this->span(upper + 1);
1137 if (span.fT != newT) {
1138 break;
1139 }
1140 ++upper;
1141 }
1142 for (int iIndex = lower; iIndex <= upper; ++iIndex) {
1143 const SkOpSpan& span = this->span(iIndex);
1144 SkOpSegment* aOther = span.fOther;
1145 int aLower = span.fOtherIndex;
1146 SkScalar aT = span.fOtherT;
1147 bool aResetFlags = false;
1148 while (aLower > 0) {
1149 SkOpSpan* aSpan = &aOther->fTs[aLower - 1];
1150 for (int iIndex = lower; iIndex <= upper; ++iIndex) {
1151 if (aSpan->fPt == this->fTs[iIndex].fPt) {
1152 goto matchFound;
1153 }
1154 }
1155 break;
1156 matchFound:
1157 --aLower;
1158 }
1159 int aUpper = span.fOtherIndex;
1160 int aLast = aOther->count() - 1;
1161 while (aUpper < aLast) {
1162 SkOpSpan* aSpan = &aOther->fTs[aUpper + 1];
1163 for (int iIndex = lower; iIndex <= upper; ++iIndex) {
1164 if (aSpan->fPt == this->fTs[iIndex].fPt) {
1165 goto matchFound2;
1166 }
1167 }
1168 break;
1169 matchFound2:
1170 ++aUpper;
1171 }
1172 if (aOther->fTs[aLower].fT == 0) {
1173 aT = 0;
1174 } else if (aOther->fTs[aUpper].fT == 1) {
1175 aT = 1;
1176 }
1177 bool aFixed = false;
1178 for (int aIndex = aLower; aIndex <= aUpper; ++aIndex) {
1179 SkOpSpan* aSpan = &aOther->fTs[aIndex];
1180 if (aSpan->fT == aT) {
1181 continue;
1182 }
1183 SkASSERT(way_roughly_equal(aSpan->fT, aT));
1184 if (!aFixed) {
1185 aOther->fixOtherTIndex();
1186 aFixed = true;
1187 }
1188 aSpan->fT = aT;
1189 aSpan->fOther->fTs[aSpan->fOtherIndex].fOtherT = aT;
1190 aResetFlags = true;
1191 }
1192 if (aResetFlags) {
1193 aOther->resetSpanFlags();
1194 }
1195 }
1196 }
1197 nextI: ;
1198 }
1199 }
1200
1201 void SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment * other,
1202 double otherT, const SkOpSegment* other2, SkOpSpan* oSpan,
1203 SkTDArray<AlignedSpan>* alignedArray) {
1204 AlignedSpan* aligned = alignedArray->append();
1205 aligned->fOldPt = oSpan->fPt;
1206 aligned->fPt = newPt;
1207 aligned->fOldT = oSpan->fT;
1208 aligned->fT = newT;
1209 aligned->fSegment = this; // OPTIMIZE: may be unused, can remove
1210 aligned->fOther1 = other;
1211 aligned->fOther2 = other2;
1212 SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt));
1213 oSpan->fPt = newPt;
1214 // SkASSERT(way_roughly_equal(oSpan->fT, newT));
1215 oSpan->fT = newT;
1216 // SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT));
1217 oSpan->fOtherT = otherT;
1218 }
1219
1220 bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
1221 bool aligned = false;
1222 SkOpSpan* span = &fTs[index];
1223 SkOpSegment* other = span->fOther;
1224 int oIndex = span->fOtherIndex;
1225 SkOpSpan* oSpan = &other->fTs[oIndex];
1226 if (span->fT != thisT) {
1227 span->fT = thisT;
1228 oSpan->fOtherT = thisT;
1229 aligned = true;
1230 }
1231 if (span->fPt != thisPt) {
1232 span->fPt = thisPt;
1233 oSpan->fPt = thisPt;
1234 aligned = true;
1235 }
1236 double oT = oSpan->fT;
1237 if (oT == 0) {
1238 return aligned;
1239 }
1240 int oStart = other->nextSpan(oIndex, -1) + 1;
1241 oSpan = &other->fTs[oStart];
1242 int otherIndex = oStart;
1243 if (oT == 1) {
1244 if (aligned) {
1245 while (oSpan->fPt == thisPt && oSpan->fT != 1) {
1246 oSpan->fTiny = true;
1247 ++oSpan;
1248 }
1249 }
1250 return aligned;
1251 }
1252 oT = oSpan->fT;
1253 int oEnd = other->nextSpan(oIndex, 1);
1254 bool oAligned = false;
1255 if (oSpan->fPt != thisPt) {
1256 oAligned |= other->alignSpan(oStart, oT, thisPt);
1257 }
1258 while (++otherIndex < oEnd) {
1259 SkOpSpan* oNextSpan = &other->fTs[otherIndex];
1260 if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
1261 oAligned |= other->alignSpan(otherIndex, oT, thisPt);
1262 }
1263 }
1264 if (oAligned) {
1265 other->alignSpanState(oStart, oEnd);
1266 }
1267 return aligned;
1268 }
1269
1270 void SkOpSegment::alignSpanState(int start, int end) {
1271 SkOpSpan* lastSpan = &fTs[--end];
1272 bool allSmall = lastSpan->fSmall;
1273 bool allTiny = lastSpan->fTiny;
1274 bool allDone = lastSpan->fDone;
1275 SkDEBUGCODE(int winding = lastSpan->fWindValue);
1276 SkDEBUGCODE(int oppWinding = lastSpan->fOppValue);
1277 int index = start;
1278 while (index < end) {
1279 SkOpSpan* span = &fTs[index];
1280 span->fSmall = allSmall;
1281 span->fTiny = allTiny;
1282 if (span->fDone != allDone) {
1283 span->fDone = allDone;
1284 fDoneSpans += allDone ? 1 : -1;
1285 }
1286 SkASSERT(span->fWindValue == winding);
1287 SkASSERT(span->fOppValue == oppWinding);
1288 ++index;
1289 }
1290 }
1291
1292 void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* oth er) {
1293 bool binary = fOperand != other->fOperand;
1294 int index = 0;
1295 int last = this->count();
1296 do {
1297 SkOpSpan& span = this->fTs[--last];
1298 if (span.fT != 1 && !span.fSmall) {
1299 break;
1300 }
1301 span.fCoincident = true;
1302 } while (true);
1303 int oIndex = other->count();
1304 do {
1305 SkOpSpan& oSpan = other->fTs[--oIndex];
1306 if (oSpan.fT != 1 && !oSpan.fSmall) {
1307 break;
1308 }
1309 oSpan.fCoincident = true;
1310 } while (true);
1311 do {
1312 SkOpSpan* test = &this->fTs[index];
1313 int baseWind = test->fWindValue;
1314 int baseOpp = test->fOppValue;
1315 int endIndex = index;
1316 while (++endIndex <= last) {
1317 SkOpSpan* endSpan = &this->fTs[endIndex];
1318 SkASSERT(endSpan->fT < 1);
1319 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp ) {
1320 break;
1321 }
1322 endSpan->fCoincident = true;
1323 }
1324 SkOpSpan* oTest = &other->fTs[oIndex];
1325 int oBaseWind = oTest->fWindValue;
1326 int oBaseOpp = oTest->fOppValue;
1327 int oStartIndex = oIndex;
1328 while (--oStartIndex >= 0) {
1329 SkOpSpan* oStartSpan = &other->fTs[oStartIndex];
1330 if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue != oBaseOpp) {
1331 break;
1332 }
1333 oStartSpan->fCoincident = true;
1334 }
1335 bool decrement = baseWind && oBaseWind;
1336 bool bigger = baseWind >= oBaseWind;
1337 do {
1338 SkASSERT(test->fT < 1);
1339 if (decrement) {
1340 if (binary && bigger) {
1341 test->fOppValue--;
1342 } else {
1343 decrementSpan(test);
1344 }
1345 }
1346 test->fCoincident = true;
1347 test = &fTs[++index];
1348 } while (index < endIndex);
1349 do {
1350 SkASSERT(oTest->fT < 1);
1351 if (decrement) {
1352 if (binary && !bigger) {
1353 oTest->fOppValue--;
1354 } else {
1355 other->decrementSpan(oTest);
1356 }
1357 }
1358 oTest->fCoincident = true;
1359 oTest = &other->fTs[--oIndex];
1360 } while (oIndex > oStartIndex);
1361 } while (index <= last && oIndex >= 0);
1362 SkASSERT(index > last);
1363 SkASSERT(oIndex < 0);
1364 }
1365
1366 void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) {
1367 bool binary = fOperand != other->fOperand;
1368 int index = 0;
1369 int last = this->count();
1370 do {
1371 SkOpSpan& span = this->fTs[--last];
1372 if (span.fT != 1 && !span.fSmall) {
1373 break;
1374 }
1375 span.fCoincident = true;
1376 } while (true);
1377 int oIndex = 0;
1378 int oLast = other->count();
1379 do {
1380 SkOpSpan& oSpan = other->fTs[--oLast];
1381 if (oSpan.fT != 1 && !oSpan.fSmall) {
1382 break;
1383 }
1384 oSpan.fCoincident = true;
1385 } while (true);
1386 do {
1387 SkOpSpan* test = &this->fTs[index];
1388 int baseWind = test->fWindValue;
1389 int baseOpp = test->fOppValue;
1390 int endIndex = index;
1391 SkOpSpan* endSpan;
1392 while (++endIndex <= last) {
1393 endSpan = &this->fTs[endIndex];
1394 SkASSERT(endSpan->fT < 1);
1395 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp ) {
1396 break;
1397 }
1398 endSpan->fCoincident = true;
1399 }
1400 SkOpSpan* oTest = &other->fTs[oIndex];
1401 int oBaseWind = oTest->fWindValue;
1402 int oBaseOpp = oTest->fOppValue;
1403 int oEndIndex = oIndex;
1404 SkOpSpan* oEndSpan;
1405 while (++oEndIndex <= oLast) {
1406 oEndSpan = &this->fTs[oEndIndex];
1407 SkASSERT(oEndSpan->fT < 1);
1408 if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBas eOpp) {
1409 break;
1410 }
1411 oEndSpan->fCoincident = true;
1412 }
1413 // consolidate the winding count even if done
1414 if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest ->fOppValue)) {
1415 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1416 bumpCoincidentBlind(binary, index, endIndex);
1417 other->bumpCoincidentOBlind(oIndex, oEndIndex);
1418 } else {
1419 other->bumpCoincidentBlind(binary, oIndex, oEndIndex);
1420 bumpCoincidentOBlind(index, endIndex);
1421 }
1422 }
1423 index = endIndex;
1424 oIndex = oEndIndex;
1425 } while (index <= last && oIndex <= oLast);
1426 SkASSERT(index > last);
1427 SkASSERT(oIndex > oLast);
1428 }
1429
1430 void SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) {
1431 const SkOpSpan& oTest = fTs[index];
1432 int oWindValue = oTest.fWindValue;
1433 int oOppValue = oTest.fOppValue;
1434 if (binary) { 535 if (binary) {
1435 SkTSwap<int>(oWindValue, oOppValue); 536 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1436 } 537 if (baseSegment->operand()) {
1437 do { 538 SkTSwap<int>(sumMiWinding, sumSuWinding);
1438 (void) bumpSpan(&fTs[index], oWindValue, oOppValue); 539 }
1439 } while (++index < endIndex); 540 }
1440 } 541 SkOpSegment* nextSegment = nextAngle->segment();
1441 542 int maxWinding, sumWinding;
1442 bool SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in dexPtr, 543 SkOpSpanBase* last;
1443 SkTArray<SkPoint, true>* outsideTs) {
1444 int index = *indexPtr;
1445 int oWindValue = oTest.fWindValue;
1446 int oOppValue = oTest.fOppValue;
1447 if (binary) { 544 if (binary) {
1448 SkTSwap<int>(oWindValue, oOppValue); 545 int oppMaxWinding, oppSumWinding;
1449 } 546 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
1450 SkOpSpan* const test = &fTs[index]; 547 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding);
1451 SkOpSpan* end = test; 548 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding,
1452 const SkPoint& oStartPt = oTest.fPt; 549 nextAngle);
1453 do { 550 } else {
1454 if (end->fDone && !end->fTiny && !end->fSmall) { // extremely large pat hs trigger this 551 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
1455 return false; 552 &maxWinding, &sumWinding);
1456 } 553 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1457 if (bumpSpan(end, oWindValue, oOppValue)) { 554 }
1458 TrackOutside(outsideTs, oStartPt); 555 nextAngle->setLastMarked(last);
1459 } 556 }
1460 end = &fTs[++index]; 557
1461 } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && en d->fT < 1); 558 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne xtAngle,
1462 *indexPtr = index; 559 SkOpAngle::IncludeType includeType) {
1463 return true; 560 const SkOpSegment* baseSegment = baseAngle->segment();
1464 } 561 int sumMiWinding = baseSegment->updateWinding(baseAngle);
1465 562 int sumSuWinding;
1466 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) { 563 bool binary = includeType >= SkOpAngle::kBinarySingle;
1467 do { 564 if (binary) {
1468 zeroSpan(&fTs[index]); 565 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1469 } while (++index < endIndex); 566 if (baseSegment->operand()) {
1470 } 567 SkTSwap<int>(sumMiWinding, sumSuWinding);
1471 568 }
1472 // because of the order in which coincidences are resolved, this and other 569 }
1473 // may not have the same intermediate points. Compute the corresponding 570 SkOpSegment* nextSegment = nextAngle->segment();
1474 // intermediate T values (using this as the master, other as the follower) 571 int maxWinding, sumWinding;
1475 // and walk other conditionally -- hoping that it catches up in the end 572 SkOpSpanBase* last;
1476 bool SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, 573 if (binary) {
1477 SkTArray<SkPoint, true>* oOutsidePts, const SkPoint& oEndPt) { 574 int oppMaxWinding, oppSumWinding;
1478 int oIndex = *oIndexPtr; 575 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW inding,
1479 SkOpSpan* const oTest = &fTs[oIndex]; 576 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding);
1480 SkOpSpan* oEnd = oTest; 577 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding,
1481 const SkPoint& oStartPt = oTest->fPt; 578 nextAngle);
1482 double oStartT = oTest->fT; 579 } else {
1483 #if 0 // FIXME : figure out what disabling this breaks 580 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW inding,
1484 const SkPoint& startPt = test.fPt; 581 &maxWinding, &sumWinding);
1485 // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition 582 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1486 if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { 583 }
1487 TrackOutside(oOutsidePts, startPt); 584 nextAngle->setLastMarked(last);
1488 }
1489 #endif
1490 bool foundEnd = false;
1491 while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
1492 foundEnd |= oEndPt == oEnd->fPt;
1493 zeroSpan(oEnd);
1494 oEnd = &fTs[++oIndex];
1495 }
1496 *oIndexPtr = oIndex;
1497 return foundEnd;
1498 }
1499
1500 // FIXME: need to test this case:
1501 // contourA has two segments that are coincident
1502 // contourB has two segments that are coincident in the same place
1503 // each ends up with +2/0 pairs for winding count
1504 // since logic below doesn't transfer count (only increments/decrements) can thi s be
1505 // resolved to +4/0 ?
1506
1507 // set spans from start to end to increment the greater by one and decrement
1508 // the lesser
1509 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d ouble endT,
1510 SkOpSegment* other) {
1511 bool binary = fOperand != other->fOperand;
1512 int index = 0;
1513 while (startPt != fTs[index].fPt) {
1514 SkASSERT(index < fTs.count());
1515 ++index;
1516 }
1517 double startT = fTs[index].fT;
1518 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) {
1519 --index;
1520 }
1521 int oIndex = 0;
1522 while (startPt != other->fTs[oIndex].fPt) {
1523 SkASSERT(oIndex < other->fTs.count());
1524 ++oIndex;
1525 }
1526 double oStartT = other->fTs[oIndex].fT;
1527 while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) {
1528 --oIndex;
1529 }
1530 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
1531 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
1532 SkOpSpan* test = &fTs[index];
1533 const SkPoint* testPt = &test->fPt;
1534 double testT = test->fT;
1535 SkOpSpan* oTest = &other->fTs[oIndex];
1536 const SkPoint* oTestPt = &oTest->fPt;
1537 // paths with extreme data will fail this test and eject out of pathops alto gether later on
1538 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1539 do {
1540 SkASSERT(test->fT < 1);
1541 if (oTest->fT == 1) {
1542 // paths with extreme data may be so mismatched that we fail here
1543 return false;
1544 }
1545
1546 // consolidate the winding count even if done
1547 bool foundEnd = false;
1548 if ((test->fWindValue == 0 && test->fOppValue == 0)
1549 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
1550 SkDEBUGCODE(int firstWind = test->fWindValue);
1551 SkDEBUGCODE(int firstOpp = test->fOppValue);
1552 do {
1553 SkASSERT(firstWind == fTs[index].fWindValue);
1554 SkASSERT(firstOpp == fTs[index].fOppValue);
1555 ++index;
1556 SkASSERT(index < fTs.count());
1557 } while (*testPt == fTs[index].fPt);
1558 SkDEBUGCODE(firstWind = oTest->fWindValue);
1559 SkDEBUGCODE(firstOpp = oTest->fOppValue);
1560 do {
1561 SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
1562 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
1563 ++oIndex;
1564 SkASSERT(oIndex < other->fTs.count());
1565 } while (*oTestPt == other->fTs[oIndex].fPt);
1566 } else {
1567 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1568 if (!bumpCoincidentThis(*oTest, binary, &index, &outsidePts)) {
1569 return false;
1570 }
1571 foundEnd = other->bumpCoincidentOther(*test, &oIndex, &oOutsideP ts, endPt);
1572 } else {
1573 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOutside Pts)) {
1574 return false;
1575 }
1576 foundEnd = bumpCoincidentOther(*oTest, &index, &outsidePts, endP t);
1577 }
1578 }
1579 test = &fTs[index];
1580 testPt = &test->fPt;
1581 testT = test->fT;
1582 oTest = &other->fTs[oIndex];
1583 oTestPt = &oTest->fPt;
1584 if (endPt == *testPt || precisely_equal(endT, testT)) {
1585 break;
1586 }
1587 if (0 && foundEnd) { // FIXME: this is likely needed but wait until a t est case triggers it
1588 break;
1589 }
1590 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1591 } while (endPt != *oTestPt);
1592 // in rare cases, one may have ended before the other
1593 if (endPt != *testPt && !precisely_equal(endT, testT)) {
1594 int lastWind = test[-1].fWindValue;
1595 int lastOpp = test[-1].fOppValue;
1596 bool zero = lastWind == 0 && lastOpp == 0;
1597 do {
1598 if (test->fWindValue || test->fOppValue) {
1599 test->fWindValue = lastWind;
1600 test->fOppValue = lastOpp;
1601 if (zero) {
1602 SkASSERT(!test->fDone);
1603 test->fDone = true;
1604 ++fDoneSpans;
1605 }
1606 }
1607 test = &fTs[++index];
1608 testPt = &test->fPt;
1609 } while (endPt != *testPt);
1610 }
1611 if (endPt != *oTestPt) {
1612 // look ahead to see if zeroing more spans will allows us to catch up
1613 int oPeekIndex = oIndex;
1614 bool success = true;
1615 SkOpSpan* oPeek;
1616 int oCount = other->count();
1617 do {
1618 oPeek = &other->fTs[oPeekIndex];
1619 if (++oPeekIndex == oCount) {
1620 success = false;
1621 break;
1622 }
1623 } while (endPt != oPeek->fPt);
1624 if (success) {
1625 // make sure the matching point completes the coincidence span
1626 success = false;
1627 do {
1628 if (oPeek->fOther == this) {
1629 success = true;
1630 break;
1631 }
1632 if (++oPeekIndex == oCount) {
1633 break;
1634 }
1635 oPeek = &other->fTs[oPeekIndex];
1636 } while (endPt == oPeek->fPt);
1637 }
1638 if (success) {
1639 do {
1640 if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1641 if (other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts, endPt)) {
1642 break;
1643 }
1644 } else {
1645 if (!other->bumpCoincidentThis(*test, binary, &oIndex, &oOut sidePts)) {
1646 return false;
1647 }
1648 }
1649 oTest = &other->fTs[oIndex];
1650 oTestPt = &oTest->fPt;
1651 } while (endPt != *oTestPt);
1652 }
1653 }
1654 int outCount = outsidePts.count();
1655 if (!done() && outCount) {
1656 addCoinOutsides(outsidePts[0], endPt, other);
1657 }
1658 if (!other->done() && oOutsidePts.count()) {
1659 other->addCoinOutsides(oOutsidePts[0], endPt, this);
1660 }
1661 setCoincidentRange(startPt, endPt, other);
1662 other->setCoincidentRange(startPt, endPt, this);
1663 return true;
1664 }
1665
1666 // FIXME: this doesn't prevent the same span from being added twice
1667 // fix in caller, SkASSERT here?
1668 // FIXME: this may erroneously reject adds for cubic loops
1669 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other T, bool borrowWind,
1670 const SkPoint& pt, const SkPoint& pt2) {
1671 int tCount = fTs.count();
1672 for (int tIndex = 0; tIndex < tCount; ++tIndex) {
1673 const SkOpSpan& span = fTs[tIndex];
1674 if (!approximately_negative(span.fT - t)) {
1675 break;
1676 }
1677 if (span.fOther == other) {
1678 bool tsMatch = approximately_equal(span.fT, t);
1679 bool otherTsMatch = approximately_equal(span.fOtherT, otherT);
1680 // FIXME: add cubic loop detecting logic here
1681 // if fLoop bit is set on span, that could be enough if addOtherT co pies the bit
1682 // or if a new bit is added ala fOtherLoop
1683 if (tsMatch || otherTsMatch) {
1684 #if DEBUG_ADD_T_PAIR
1685 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
1686 __FUNCTION__, fID, t, other->fID, otherT);
1687 #endif
1688 return NULL;
1689 }
1690 }
1691 }
1692 int oCount = other->count();
1693 for (int oIndex = 0; oIndex < oCount; ++oIndex) {
1694 const SkOpSpan& oSpan = other->span(oIndex);
1695 if (!approximately_negative(oSpan.fT - otherT)) {
1696 break;
1697 }
1698 if (oSpan.fOther == this) {
1699 bool otherTsMatch = approximately_equal(oSpan.fT, otherT);
1700 bool tsMatch = approximately_equal(oSpan.fOtherT, t);
1701 if (otherTsMatch || tsMatch) {
1702 #if DEBUG_ADD_T_PAIR
1703 SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1. 9g\n",
1704 __FUNCTION__, fID, t, other->fID, otherT);
1705 #endif
1706 return NULL;
1707 }
1708 }
1709 }
1710 #if DEBUG_ADD_T_PAIR
1711 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
1712 __FUNCTION__, fID, t, other->fID, otherT);
1713 #endif
1714 SkASSERT(other != this);
1715 int insertedAt = addT(other, pt, t);
1716 int otherInsertedAt = other->addT(this, pt2, otherT);
1717 this->addOtherT(insertedAt, otherT, otherInsertedAt);
1718 other->addOtherT(otherInsertedAt, t, insertedAt);
1719 this->matchWindingValue(insertedAt, t, borrowWind);
1720 other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
1721 SkOpSpan& span = this->fTs[insertedAt];
1722 if (pt != pt2) {
1723 span.fNear = true;
1724 SkOpSpan& oSpan = other->fTs[otherInsertedAt];
1725 oSpan.fNear = true;
1726 }
1727 // if the newly inserted spans match a neighbor on one but not the other, ma ke them agree
1728 int lower = this->nextExactSpan(insertedAt, -1) + 1;
1729 int upper = this->nextExactSpan(insertedAt, 1) - 1;
1730 if (upper < 0) {
1731 upper = this->count() - 1;
1732 }
1733 int oLower = other->nextExactSpan(otherInsertedAt, -1) + 1;
1734 int oUpper = other->nextExactSpan(otherInsertedAt, 1) - 1;
1735 if (oUpper < 0) {
1736 oUpper = other->count() - 1;
1737 }
1738 if (lower == upper && oLower == oUpper) {
1739 return &span;
1740 }
1741 #if DEBUG_CONCIDENT
1742 SkDebugf("%s id=%d lower=%d upper=%d other=%d oLower=%d oUpper=%d\n", __FUNC TION__,
1743 debugID(), lower, upper, other->debugID(), oLower, oUpper);
1744 #endif
1745 // find the nearby spans in one range missing in the other
1746 this->alignRange(lower, upper, other, oLower, oUpper);
1747 other->alignRange(oLower, oUpper, this, lower, upper);
1748 return &span;
1749 }
1750
1751 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other T, bool borrowWind,
1752 const SkPoint& pt) {
1753 return addTPair(t, other, otherT, borrowWind, pt, pt);
1754 }
1755
1756 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
1757 const SkPoint midPt = ptAtT(midT);
1758 SkPathOpsBounds bounds;
1759 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1760 bounds.sort();
1761 return bounds.almostContains(midPt);
1762 }
1763
1764 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
1765 if (lesser > greater) {
1766 SkTSwap<int>(lesser, greater);
1767 }
1768 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
1769 }
1770
1771 // in extreme cases (like the buffer overflow test) return false to abort
1772 // for now, if one t value represents two different points, then the values are too extreme
1773 // to generate meaningful results
1774 bool SkOpSegment::calcAngles() {
1775 int spanCount = fTs.count();
1776 if (spanCount <= 2) {
1777 return spanCount == 2;
1778 }
1779 int index = 1;
1780 const SkOpSpan* firstSpan = &fTs[index];
1781 int activePrior = checkSetAngle(0);
1782 const SkOpSpan* span = &fTs[0];
1783 if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther- >multipleEnds()) {
1784 index = findStartSpan(0); // curve start intersects
1785 if (fTs[index].fT == 0) {
1786 return false;
1787 }
1788 SkASSERT(index > 0);
1789 if (activePrior >= 0) {
1790 addStartSpan(index);
1791 }
1792 }
1793 bool addEnd;
1794 int endIndex = spanCount - 1;
1795 span = &fTs[endIndex - 1];
1796 if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects
1797 endIndex = findEndSpan(endIndex);
1798 SkASSERT(endIndex > 0);
1799 } else {
1800 addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleSta rts();
1801 }
1802 SkASSERT(endIndex >= index);
1803 int prior = 0;
1804 while (index < endIndex) {
1805 const SkOpSpan& fromSpan = fTs[index]; // for each intermediate interse ction
1806 const SkOpSpan* lastSpan;
1807 span = &fromSpan;
1808 int start = index;
1809 do {
1810 lastSpan = span;
1811 span = &fTs[++index];
1812 SkASSERT(index < spanCount);
1813 if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny ) {
1814 break;
1815 }
1816 if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) {
1817 return false;
1818 }
1819 } while (true);
1820 SkOpAngle* angle = NULL;
1821 SkOpAngle* priorAngle;
1822 if (activePrior >= 0) {
1823 int pActive = firstActive(prior);
1824 SkASSERT(pActive < start);
1825 priorAngle = &fAngles.push_back();
1826 priorAngle->set(this, start, pActive);
1827 }
1828 int active = checkSetAngle(start);
1829 if (active >= 0) {
1830 SkASSERT(active < index);
1831 angle = &fAngles.push_back();
1832 angle->set(this, active, index);
1833 }
1834 #if DEBUG_ANGLE
1835 debugCheckPointsEqualish(start, index);
1836 #endif
1837 prior = start;
1838 do {
1839 const SkOpSpan* startSpan = &fTs[start - 1];
1840 if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromA ngle
1841 || startSpan->fToAngle) {
1842 break;
1843 }
1844 --start;
1845 } while (start > 0);
1846 do {
1847 if (activePrior >= 0) {
1848 SkASSERT(fTs[start].fFromAngle == NULL);
1849 fTs[start].fFromAngle = priorAngle;
1850 }
1851 if (active >= 0) {
1852 SkASSERT(fTs[start].fToAngle == NULL);
1853 fTs[start].fToAngle = angle;
1854 }
1855 } while (++start < index);
1856 activePrior = active;
1857 }
1858 if (addEnd && activePrior >= 0) {
1859 addEndSpan(endIndex);
1860 }
1861 return true;
1862 }
1863
1864 int SkOpSegment::checkSetAngle(int tIndex) const {
1865 const SkOpSpan* span = &fTs[tIndex];
1866 while (span->fTiny /* || span->fSmall */) {
1867 span = &fTs[++tIndex];
1868 }
1869 return isCanceled(tIndex) ? -1 : tIndex;
1870 } 585 }
1871 586
1872 // at this point, the span is already ordered, or unorderable 587 // at this point, the span is already ordered, or unorderable
1873 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) { 588 int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
589 SkOpAngle::IncludeType includeType) {
1874 SkASSERT(includeType != SkOpAngle::kUnaryXor); 590 SkASSERT(includeType != SkOpAngle::kUnaryXor);
1875 SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex); 591 SkOpAngle* firstAngle = this->spanToAngle(end, start);
1876 if (NULL == firstAngle || NULL == firstAngle->next()) { 592 if (NULL == firstAngle || NULL == firstAngle->next()) {
1877 return SK_NaN32; 593 return SK_NaN32;
1878 } 594 }
1879 // if all angles have a computed winding, 595 // if all angles have a computed winding,
1880 // or if no adjacent angles are orderable, 596 // or if no adjacent angles are orderable,
1881 // or if adjacent orderable angles have no computed winding, 597 // or if adjacent orderable angles have no computed winding,
1882 // there's nothing to do 598 // there's nothing to do
1883 // if two orderable angles are adjacent, and both are next to orderable angl es, 599 // if two orderable angles are adjacent, and both are next to orderable angl es,
1884 // and one has winding computed, transfer to the other 600 // and one has winding computed, transfer to the other
1885 SkOpAngle* baseAngle = NULL; 601 SkOpAngle* baseAngle = NULL;
1886 bool tryReverse = false; 602 bool tryReverse = false;
1887 // look for counterclockwise transfers 603 // look for counterclockwise transfers
1888 SkOpAngle* angle = firstAngle->previous(); 604 SkOpAngle* angle = firstAngle->previous();
1889 SkOpAngle* next = angle->next(); 605 SkOpAngle* next = angle->next();
1890 firstAngle = next; 606 firstAngle = next;
1891 do { 607 do {
1892 SkOpAngle* prior = angle; 608 SkOpAngle* prior = angle;
1893 angle = next; 609 angle = next;
1894 next = angle->next(); 610 next = angle->next();
1895 SkASSERT(prior->next() == angle); 611 SkASSERT(prior->next() == angle);
1896 SkASSERT(angle->next() == next); 612 SkASSERT(angle->next() == next);
1897 if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 613 if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
1898 baseAngle = NULL; 614 baseAngle = NULL;
1899 continue; 615 continue;
1900 } 616 }
1901 int testWinding = angle->segment()->windSum(angle); 617 int testWinding = angle->starter()->windSum();
1902 if (SK_MinS32 != testWinding) { 618 if (SK_MinS32 != testWinding) {
1903 baseAngle = angle; 619 baseAngle = angle;
1904 tryReverse = true; 620 tryReverse = true;
1905 continue; 621 continue;
1906 } 622 }
1907 if (baseAngle) { 623 if (baseAngle) {
1908 ComputeOneSum(baseAngle, angle, includeType); 624 ComputeOneSum(baseAngle, angle, includeType);
1909 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL; 625 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
1910 } 626 }
1911 } while (next != firstAngle); 627 } while (next != firstAngle);
1912 if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) { 628 if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
1913 firstAngle = baseAngle; 629 firstAngle = baseAngle;
1914 tryReverse = true; 630 tryReverse = true;
1915 } 631 }
1916 if (tryReverse) { 632 if (tryReverse) {
1917 baseAngle = NULL; 633 baseAngle = NULL;
1918 SkOpAngle* prior = firstAngle; 634 SkOpAngle* prior = firstAngle;
1919 do { 635 do {
1920 angle = prior; 636 angle = prior;
1921 prior = angle->previous(); 637 prior = angle->previous();
1922 SkASSERT(prior->next() == angle); 638 SkASSERT(prior->next() == angle);
1923 next = angle->next(); 639 next = angle->next();
1924 if (prior->unorderable() || angle->unorderable() || next->unorderabl e()) { 640 if (prior->unorderable() || angle->unorderable() || next->unorderabl e()) {
1925 baseAngle = NULL; 641 baseAngle = NULL;
1926 continue; 642 continue;
1927 } 643 }
1928 int testWinding = angle->segment()->windSum(angle); 644 int testWinding = angle->starter()->windSum();
1929 if (SK_MinS32 != testWinding) { 645 if (SK_MinS32 != testWinding) {
1930 baseAngle = angle; 646 baseAngle = angle;
1931 continue; 647 continue;
1932 } 648 }
1933 if (baseAngle) { 649 if (baseAngle) {
1934 ComputeOneSumReverse(baseAngle, angle, includeType); 650 ComputeOneSumReverse(baseAngle, angle, includeType);
1935 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angl e : NULL; 651 baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : N ULL;
1936 } 652 }
1937 } while (prior != firstAngle); 653 } while (prior != firstAngle);
1938 } 654 }
1939 int minIndex = SkMin32(startIndex, endIndex); 655 return start->starter(end)->windSum();
1940 return windSum(minIndex);
1941 } 656 }
1942 657
1943 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle , 658 SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool current,
1944 SkOpAngle::IncludeType includeType) { 659 SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) {
1945 const SkOpSegment* baseSegment = baseAngle->segment();
1946 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1947 int sumSuWinding;
1948 bool binary = includeType >= SkOpAngle::kBinarySingle;
1949 if (binary) {
1950 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1951 if (baseSegment->operand()) {
1952 SkTSwap<int>(sumMiWinding, sumSuWinding);
1953 }
1954 }
1955 SkOpSegment* nextSegment = nextAngle->segment();
1956 int maxWinding, sumWinding;
1957 SkOpSpan* last;
1958 if (binary) {
1959 int oppMaxWinding, oppSumWinding;
1960 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
1961 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding);
1962 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding,
1963 nextAngle);
1964 } else {
1965 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW inding,
1966 &maxWinding, &sumWinding);
1967 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1968 }
1969 nextAngle->setLastMarked(last);
1970 }
1971
1972 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne xtAngle,
1973 SkOpAngle::IncludeType includeType) {
1974 const SkOpSegment* baseSegment = baseAngle->segment();
1975 int sumMiWinding = baseSegment->updateWinding(baseAngle);
1976 int sumSuWinding;
1977 bool binary = includeType >= SkOpAngle::kBinarySingle;
1978 if (binary) {
1979 sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1980 if (baseSegment->operand()) {
1981 SkTSwap<int>(sumMiWinding, sumSuWinding);
1982 }
1983 }
1984 SkOpSegment* nextSegment = nextAngle->segment();
1985 int maxWinding, sumWinding;
1986 SkOpSpan* last;
1987 if (binary) {
1988 int oppMaxWinding, oppSumWinding;
1989 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW inding,
1990 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum Winding);
1991 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp SumWinding,
1992 nextAngle);
1993 } else {
1994 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW inding,
1995 &maxWinding, &sumWinding);
1996 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1997 }
1998 nextAngle->setLastMarked(last);
1999 }
2000
2001 bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
2002 int step = index < endIndex ? 1 : -1;
2003 do {
2004 const SkOpSpan& span = this->span(index);
2005 if (span.fPt == pt) {
2006 const SkOpSpan& endSpan = this->span(endIndex);
2007 return span.fT == endSpan.fT && pt != endSpan.fPt;
2008 }
2009 index += step;
2010 } while (index != endIndex);
2011 return false;
2012 }
2013
2014 bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) c onst {
2015 int count = this->count();
2016 for (int index = 0; index < count; ++index) {
2017 const SkOpSpan& span = fTs[index];
2018 if (t < span.fT) {
2019 return false;
2020 }
2021 if (t == span.fT) {
2022 if (other != span.fOther) {
2023 continue;
2024 }
2025 if (other->fVerb != SkPath::kCubic_Verb) {
2026 return true;
2027 }
2028 if (!other->fLoop) {
2029 return true;
2030 }
2031 double otherMidT = (otherT + span.fOtherT) / 2;
2032 SkPoint otherPt = other->ptAtT(otherMidT);
2033 return SkDPoint::ApproximatelyEqual(span.fPt, otherPt);
2034 }
2035 }
2036 return false;
2037 }
2038
2039 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi tT,
2040 bool* hitSomething, double mid, bool opp, bool cur rent) const {
2041 SkScalar bottom = fBounds.fBottom; 660 SkScalar bottom = fBounds.fBottom;
2042 int bestTIndex = -1; 661 *vertical = false;
2043 if (bottom <= *bestY) { 662 if (bottom <= *bestY) {
2044 return bestTIndex; 663 return NULL;
2045 } 664 }
2046 SkScalar top = fBounds.fTop; 665 SkScalar top = fBounds.fTop;
2047 if (top >= basePt.fY) { 666 if (top >= basePt.fY) {
2048 return bestTIndex; 667 return NULL;
2049 } 668 }
2050 if (fBounds.fLeft > basePt.fX) { 669 if (fBounds.fLeft > basePt.fX) {
2051 return bestTIndex; 670 return NULL;
2052 } 671 }
2053 if (fBounds.fRight < basePt.fX) { 672 if (fBounds.fRight < basePt.fX) {
2054 return bestTIndex; 673 return NULL;
2055 } 674 }
2056 if (fBounds.fLeft == fBounds.fRight) { 675 if (fBounds.fLeft == fBounds.fRight) {
2057 // if vertical, and directly above test point, wait for another one 676 // if vertical, and directly above test point, wait for another one
2058 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde x; 677 *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft);
678 return NULL;
2059 } 679 }
2060 // intersect ray starting at basePt with edge 680 // intersect ray starting at basePt with edge
2061 SkIntersections intersections; 681 SkIntersections intersections;
2062 // OPTIMIZE: use specialty function that intersects ray with curve, 682 // OPTIMIZE: use specialty function that intersects ray with curve,
2063 // returning t values only for curve (we don't care about t on ray) 683 // returning t values only for curve (we don't care about t on ray)
2064 intersections.allowNear(false); 684 intersections.allowNear(false);
2065 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) 685 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
2066 (fPts, top, bottom, basePt.fX, false); 686 (fPts, top, bottom, basePt.fX, false);
2067 if (pts == 0 || (current && pts == 1)) { 687 if (pts == 0 || (current && pts == 1)) {
2068 return bestTIndex; 688 return NULL;
2069 } 689 }
2070 if (current) { 690 if (current) {
2071 SkASSERT(pts > 1); 691 SkASSERT(pts > 1);
2072 int closestIdx = 0; 692 int closestIdx = 0;
2073 double closest = fabs(intersections[0][0] - mid); 693 double closest = fabs(intersections[0][0] - mid);
2074 for (int idx = 1; idx < pts; ++idx) { 694 for (int idx = 1; idx < pts; ++idx) {
2075 double test = fabs(intersections[0][idx] - mid); 695 double test = fabs(intersections[0][idx] - mid);
2076 if (closest > test) { 696 if (closest > test) {
2077 closestIdx = idx; 697 closestIdx = idx;
2078 closest = test; 698 closest = test;
2079 } 699 }
2080 } 700 }
2081 intersections.quickRemoveOne(closestIdx, --pts); 701 intersections.quickRemoveOne(closestIdx, --pts);
2082 } 702 }
2083 double bestT = -1; 703 double bestT = -1;
2084 for (int index = 0; index < pts; ++index) { 704 for (int index = 0; index < pts; ++index) {
2085 double foundT = intersections[0][index]; 705 double foundT = intersections[0][index];
2086 if (approximately_less_than_zero(foundT) 706 if (approximately_less_than_zero(foundT)
2087 || approximately_greater_than_one(foundT)) { 707 || approximately_greater_than_one(foundT)) {
2088 continue; 708 continue;
2089 } 709 }
2090 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fo undT).fY; 710 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fo undT).fY;
2091 if (approximately_negative(testY - *bestY) 711 if (approximately_negative(testY - *bestY)
2092 || approximately_negative(basePt.fY - testY)) { 712 || approximately_negative(basePt.fY - testY)) {
2093 continue; 713 continue;
2094 } 714 }
2095 if (pts > 1 && fVerb == SkPath::kLine_Verb) { 715 if (pts > 1 && fVerb == SkPath::kLine_Verb) {
2096 return SK_MinS32; // if the intersection is edge on, wait for anoth er one 716 *vertical = true;
717 return NULL; // if the intersection is edge on, wait for another on e
2097 } 718 }
2098 if (fVerb > SkPath::kLine_Verb) { 719 if (fVerb > SkPath::kLine_Verb) {
2099 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, f oundT).fX; 720 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, f oundT).fX;
2100 if (approximately_zero(dx)) { 721 if (approximately_zero(dx)) {
2101 return SK_MinS32; // hit vertical, wait for another one 722 *vertical = true;
723 return NULL; // hit vertical, wait for another one
2102 } 724 }
2103 } 725 }
2104 *bestY = testY; 726 *bestY = testY;
2105 bestT = foundT; 727 bestT = foundT;
2106 } 728 }
2107 if (bestT < 0) { 729 if (bestT < 0) {
2108 return bestTIndex; 730 return NULL;
2109 } 731 }
2110 SkASSERT(bestT >= 0); 732 SkASSERT(bestT >= 0);
2111 SkASSERT(bestT <= 1); 733 SkASSERT(bestT < 1);
2112 int start; 734 SkOpSpanBase* testTSpanBase = &this->fHead;
2113 int end = 0; 735 SkOpSpanBase* nextTSpan;
736 double endT = 0;
2114 do { 737 do {
2115 start = end; 738 nextTSpan = testTSpanBase->upCast()->next();
2116 end = nextSpan(start, 1); 739 endT = nextTSpan->t();
2117 } while (fTs[end].fT < bestT); 740 if (endT >= bestT) {
2118 // FIXME: see next candidate for a better pattern to find the next start/end pair 741 break;
2119 while (start + 1 < end && fTs[start].fDone) { 742 }
2120 ++start; 743 testTSpanBase = nextTSpan;
2121 } 744 } while (testTSpanBase);
2122 if (!isCanceled(start)) { 745 SkOpSpan* bestTSpan = NULL;
746 SkOpSpan* testTSpan = testTSpanBase->upCast();
747 if (!testTSpan->isCanceled()) {
2123 *hitT = bestT; 748 *hitT = bestT;
2124 bestTIndex = start; 749 bestTSpan = testTSpan;
2125 *hitSomething = true; 750 *hitSomething = true;
2126 } 751 }
2127 return bestTIndex; 752 return bestTSpan;
2128 } 753 }
2129 754
2130 bool SkOpSegment::decrementSpan(SkOpSpan* span) { 755 void SkOpSegment::detach(const SkOpSpan* span) {
2131 SkASSERT(span->fWindValue > 0); 756 if (span->done()) {
2132 if (--(span->fWindValue) == 0) { 757 --this->fDoneCount;
2133 if (!span->fOppValue && !span->fDone) { 758 }
2134 span->fDone = true; 759 --this->fCount;
2135 ++fDoneSpans; 760 }
2136 return true; 761
762 double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
763 SkDPoint testPt = this->dPtAtT(t);
764 SkDLine testPerp = {{ testPt, testPt }};
765 SkDVector slope = this->dSlopeAtT(t);
766 testPerp[1].fX += slope.fY;
767 testPerp[1].fY -= slope.fX;
768 SkIntersections i;
769 SkOpSegment* oppSegment = oppAngle->segment();
770 int oppPtCount = SkPathOpsVerbToPoints(oppSegment->verb());
771 (*CurveIntersectRay[oppPtCount])(oppSegment->pts(), testPerp, &i);
772 double closestDistSq = SK_ScalarInfinity;
773 for (int index = 0; index < i.used(); ++index) {
774 if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
775 continue;
776 }
777 double testDistSq = testPt.distanceSquared(i.pt(index));
778 if (closestDistSq > testDistSq) {
779 closestDistSq = testDistSq;
2137 } 780 }
2138 } 781 }
2139 return false; 782 return closestDistSq;
2140 }
2141
2142 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
2143 SkASSERT(!span->fDone || span->fTiny || span->fSmall);
2144 span->fWindValue += windDelta;
2145 SkASSERT(span->fWindValue >= 0);
2146 span->fOppValue += oppDelta;
2147 SkASSERT(span->fOppValue >= 0);
2148 if (fXor) {
2149 span->fWindValue &= 1;
2150 }
2151 if (fOppXor) {
2152 span->fOppValue &= 1;
2153 }
2154 if (!span->fWindValue && !span->fOppValue) {
2155 if (!span->fDone) {
2156 span->fDone = true;
2157 ++fDoneSpans;
2158 }
2159 return true;
2160 }
2161 return false;
2162 }
2163
2164 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const {
2165 const SkOpSpan* firstSpan = &thisSpan; // rewind to the start
2166 const SkOpSpan* beginSpan = fTs.begin();
2167 const SkPoint& testPt = thisSpan.fPt;
2168 while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) {
2169 --firstSpan;
2170 }
2171 return *firstSpan;
2172 }
2173
2174 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const {
2175 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small
2176 const SkOpSpan* lastSpan = &thisSpan; // find the end
2177 const SkPoint& testPt = thisSpan.fPt;
2178 while (lastSpan < endSpan && lastSpan[1].fPt == testPt) {
2179 ++lastSpan;
2180 }
2181 return *lastSpan;
2182 }
2183
2184 // with a loop, the comparison is move involved
2185 // scan backwards and forwards to count all matching points
2186 // (verify that there are twp scans marked as loops)
2187 // compare that against 2 matching scans for loop plus other results
2188 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) {
2189 const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the star t
2190 const SkOpSpan& lastSpan = this->lastSpan(thisSpan); // find the end
2191 double firstLoopT = -1, lastLoopT = -1;
2192 const SkOpSpan* testSpan = &firstSpan - 1;
2193 while (++testSpan <= &lastSpan) {
2194 if (testSpan->fLoop) {
2195 firstLoopT = testSpan->fT;
2196 break;
2197 }
2198 }
2199 testSpan = &lastSpan + 1;
2200 while (--testSpan >= &firstSpan) {
2201 if (testSpan->fLoop) {
2202 lastLoopT = testSpan->fT;
2203 break;
2204 }
2205 }
2206 SkASSERT((firstLoopT == -1) == (lastLoopT == -1));
2207 if (firstLoopT == -1) {
2208 return false;
2209 }
2210 SkASSERT(firstLoopT < lastLoopT);
2211 testSpan = &firstSpan - 1;
2212 smallCounts[0] = smallCounts[1] = 0;
2213 while (++testSpan <= &lastSpan) {
2214 SkASSERT(approximately_equal(testSpan->fT, firstLoopT) +
2215 approximately_equal(testSpan->fT, lastLoopT) == 1);
2216 smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++;
2217 }
2218 return true;
2219 }
2220
2221 double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
2222 double hiEnd, const SkOpSegment* other, int thisStart) {
2223 if (max >= hiEnd) {
2224 return -1;
2225 }
2226 int end = findOtherT(hiEnd, ref);
2227 if (end < 0) {
2228 return -1;
2229 }
2230 double tHi = span(end).fT;
2231 double tLo, refLo;
2232 if (thisStart >= 0) {
2233 tLo = span(thisStart).fT;
2234 refLo = min;
2235 } else {
2236 int start1 = findOtherT(loEnd, ref);
2237 SkASSERT(start1 >= 0);
2238 tLo = span(start1).fT;
2239 refLo = loEnd;
2240 }
2241 double missingT = (max - refLo) / (hiEnd - refLo);
2242 missingT = tLo + missingT * (tHi - tLo);
2243 return missingT;
2244 }
2245
2246 double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, doub le min, double max,
2247 double hiEnd, const SkOpSegment* other, int thisEnd) {
2248 if (min <= loEnd) {
2249 return -1;
2250 }
2251 int start = findOtherT(loEnd, ref);
2252 if (start < 0) {
2253 return -1;
2254 }
2255 double tLo = span(start).fT;
2256 double tHi, refHi;
2257 if (thisEnd >= 0) {
2258 tHi = span(thisEnd).fT;
2259 refHi = max;
2260 } else {
2261 int end1 = findOtherT(hiEnd, ref);
2262 if (end1 < 0) {
2263 return -1;
2264 }
2265 tHi = span(end1).fT;
2266 refHi = hiEnd;
2267 }
2268 double missingT = (min - loEnd) / (refHi - loEnd);
2269 missingT = tLo + missingT * (tHi - tLo);
2270 return missingT;
2271 }
2272
2273 // see if spans with two or more intersections have the same number on the other end
2274 void SkOpSegment::checkDuplicates() {
2275 debugValidate();
2276 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2277 int index;
2278 int endIndex = 0;
2279 bool endFound;
2280 do {
2281 index = endIndex;
2282 endIndex = nextExactSpan(index, 1);
2283 if ((endFound = endIndex < 0)) {
2284 endIndex = count();
2285 }
2286 int dupCount = endIndex - index;
2287 if (dupCount < 2) {
2288 continue;
2289 }
2290 do {
2291 const SkOpSpan* thisSpan = &fTs[index];
2292 if (thisSpan->fNear) {
2293 continue;
2294 }
2295 SkOpSegment* other = thisSpan->fOther;
2296 int oIndex = thisSpan->fOtherIndex;
2297 int oStart = other->nextExactSpan(oIndex, -1) + 1;
2298 int oEnd = other->nextExactSpan(oIndex, 1);
2299 if (oEnd < 0) {
2300 oEnd = other->count();
2301 }
2302 int oCount = oEnd - oStart;
2303 // force the other to match its t and this pt if not on an end point
2304 if (oCount != dupCount) {
2305 MissingSpan& missing = missingSpans.push_back();
2306 missing.fOther = NULL;
2307 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2308 missing.fPt = thisSpan->fPt;
2309 const SkOpSpan& oSpan = other->span(oIndex);
2310 if (oCount > dupCount) {
2311 missing.fSegment = this;
2312 missing.fT = thisSpan->fT;
2313 other->checkLinks(&oSpan, &missingSpans);
2314 } else {
2315 missing.fSegment = other;
2316 missing.fT = oSpan.fT;
2317 checkLinks(thisSpan, &missingSpans);
2318 }
2319 if (!missingSpans.back().fOther) {
2320 missingSpans.pop_back();
2321 }
2322 }
2323 } while (++index < endIndex);
2324 } while (!endFound);
2325 int missingCount = missingSpans.count();
2326 if (missingCount == 0) {
2327 return;
2328 }
2329 SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence;
2330 for (index = 0; index < missingCount; ++index) {
2331 MissingSpan& missing = missingSpans[index];
2332 SkOpSegment* missingOther = missing.fOther;
2333 if (missing.fSegment == missing.fOther) {
2334 continue;
2335 }
2336 #if 0 // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 bu t breaks
2337 // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't unde rstand why
2338 if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOth erT)) {
2339 #if DEBUG_DUPLICATES
2340 SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSe gment->fID,
2341 missing.fT, missing.fOther->fID, missing.fOtherT);
2342 #endif
2343 continue;
2344 }
2345 if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing .fT)) {
2346 #if DEBUG_DUPLICATES
2347 SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOt her->fID,
2348 missing.fOtherT, missing.fSegment->fID, missing.fT);
2349 #endif
2350 continue;
2351 }
2352 #endif
2353 // skip if adding would insert point into an existing coincindent span
2354 if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther)
2355 && missingOther->inCoincidentSpan(missing.fOtherT, this)) {
2356 continue;
2357 }
2358 // skip if the created coincident spans are small
2359 if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOt her)
2360 && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, m issing.fSegment)) {
2361 continue;
2362 }
2363 const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOt her,
2364 missing.fOtherT, false, missing.fPt);
2365 if (added && added->fSmall) {
2366 missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence) ;
2367 }
2368 }
2369 for (index = 0; index < missingCount; ++index) {
2370 MissingSpan& missing = missingSpans[index];
2371 missing.fSegment->fixOtherTIndex();
2372 missing.fOther->fixOtherTIndex();
2373 }
2374 for (index = 0; index < missingCoincidence.count(); ++index) {
2375 MissingSpan& missing = missingCoincidence[index];
2376 missing.fSegment->fixOtherTIndex();
2377 }
2378 debugValidate();
2379 }
2380
2381 // look to see if the curve end intersects an intermediary that intersects the o ther
2382 bool SkOpSegment::checkEnds() {
2383 debugValidate();
2384 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2385 int count = fTs.count();
2386 for (int index = 0; index < count; ++index) {
2387 const SkOpSpan& span = fTs[index];
2388 double otherT = span.fOtherT;
2389 if (otherT != 0 && otherT != 1) { // only check ends
2390 continue;
2391 }
2392 const SkOpSegment* other = span.fOther;
2393 // peek start/last describe the range of spans that match the other t of this span
2394 int peekStart = span.fOtherIndex;
2395 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
2396 ;
2397 int otherCount = other->fTs.count();
2398 int peekLast = span.fOtherIndex;
2399 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
2400 ;
2401 if (++peekStart == --peekLast) { // if there isn't a range, there's noth ing to do
2402 continue;
2403 }
2404 // t start/last describe the range of spans that match the t of this spa n
2405 double t = span.fT;
2406 double tBottom = -1;
2407 int tStart = -1;
2408 int tLast = count;
2409 bool lastSmall = false;
2410 double afterT = t;
2411 for (int inner = 0; inner < count; ++inner) {
2412 double innerT = fTs[inner].fT;
2413 if (innerT <= t && innerT > tBottom) {
2414 if (innerT < t || !lastSmall) {
2415 tStart = inner - 1;
2416 }
2417 tBottom = innerT;
2418 }
2419 if (innerT > afterT) {
2420 if (t == afterT && lastSmall) {
2421 afterT = innerT;
2422 } else {
2423 tLast = inner;
2424 break;
2425 }
2426 }
2427 lastSmall = innerT <= t ? fTs[inner].fSmall : false;
2428 }
2429 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
2430 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span
2431 continue;
2432 }
2433 const SkOpSpan& peekSpan = other->fTs[peekIndex];
2434 SkOpSegment* match = peekSpan.fOther;
2435 if (match->done()) {
2436 continue; // if the edge has already been eaten (likely coincid ence), ignore it
2437 }
2438 const double matchT = peekSpan.fOtherT;
2439 // see if any of the spans match the other spans
2440 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
2441 const SkOpSpan& tSpan = fTs[tIndex];
2442 if (tSpan.fOther == match) {
2443 if (tSpan.fOtherT == matchT) {
2444 goto nextPeekIndex;
2445 }
2446 double midT = (tSpan.fOtherT + matchT) / 2;
2447 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
2448 goto nextPeekIndex;
2449 }
2450 }
2451 }
2452 if (missingSpans.count() > 0) {
2453 const MissingSpan& lastMissing = missingSpans.back();
2454 if (lastMissing.fT == t
2455 && lastMissing.fOther == match
2456 && lastMissing.fOtherT == matchT) {
2457 SkASSERT(SkDPoint::ApproximatelyEqual(lastMissing.fPt, peekS pan.fPt));
2458 continue;
2459 }
2460 }
2461 if (this == match) {
2462 return false; // extremely large paths can trigger this
2463 }
2464 #if DEBUG_CHECK_ALIGN
2465 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,% 1.9g)\n",
2466 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, p eekSpan.fPt.fY);
2467 #endif
2468 // this segment is missing a entry that the other contains
2469 // remember so we can add the missing one and recompute the indices
2470 {
2471 MissingSpan& missing = missingSpans.push_back();
2472 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2473 missing.fT = t;
2474 SkASSERT(this != match);
2475 missing.fOther = match;
2476 missing.fOtherT = matchT;
2477 missing.fPt = peekSpan.fPt;
2478 }
2479 break;
2480 nextPeekIndex:
2481 ;
2482 }
2483 }
2484 if (missingSpans.count() == 0) {
2485 debugValidate();
2486 return true;
2487 }
2488 debugValidate();
2489 int missingCount = missingSpans.count();
2490 for (int index = 0; index < missingCount; ++index) {
2491 MissingSpan& missing = missingSpans[index];
2492 if (this != missing.fOther) {
2493 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing .fPt);
2494 }
2495 }
2496 fixOtherTIndex();
2497 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq ue segments to
2498 // avoid this
2499 for (int index = 0; index < missingCount; ++index) {
2500 missingSpans[index].fOther->fixOtherTIndex();
2501 }
2502 debugValidate();
2503 return true;
2504 }
2505
2506 void SkOpSegment::checkLinks(const SkOpSpan* base,
2507 SkTArray<MissingSpan, true>* missingSpans) const {
2508 const SkOpSpan* first = fTs.begin();
2509 const SkOpSpan* last = fTs.end() - 1;
2510 SkASSERT(base >= first && last >= base);
2511 const SkOpSegment* other = base->fOther;
2512 const SkOpSpan* oFirst = other->fTs.begin();
2513 const SkOpSpan* oLast = other->fTs.end() - 1;
2514 const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex];
2515 const SkOpSpan* test = base;
2516 const SkOpSpan* missing = NULL;
2517 while (test > first && (--test)->fPt == base->fPt) {
2518 if (this == test->fOther) {
2519 continue;
2520 }
2521 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
2522 }
2523 test = base;
2524 while (test < last && (++test)->fPt == base->fPt) {
2525 SkASSERT(this != test->fOther || test->fLoop);
2526 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
2527 }
2528 }
2529
2530 // see if spans with two or more intersections all agree on common t and point v alues
2531 void SkOpSegment::checkMultiples() {
2532 debugValidate();
2533 int index;
2534 int end = 0;
2535 while (fTs[++end].fT == 0)
2536 ;
2537 while (fTs[end].fT < 1) {
2538 int start = index = end;
2539 end = nextExactSpan(index, 1);
2540 if (end <= index) {
2541 return; // buffer overflow example triggers this
2542 }
2543 if (index + 1 == end) {
2544 continue;
2545 }
2546 // force the duplicates to agree on t and pt if not on the end
2547 SkOpSpan& span = fTs[index];
2548 double thisT = span.fT;
2549 const SkPoint& thisPt = span.fPt;
2550 span.fMultiple = true;
2551 bool aligned = false;
2552 while (++index < end) {
2553 aligned |= alignSpan(index, thisT, thisPt);
2554 }
2555 if (aligned) {
2556 alignSpanState(start, end);
2557 }
2558 fMultiples = true;
2559 }
2560 debugValidate();
2561 }
2562
2563 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
2564 const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingP tr,
2565 SkTArray<MissingSpan, true>* missingSpans) {
2566 SkASSERT(oSpan->fPt == test->fPt);
2567 const SkOpSpan* oTest = oSpan;
2568 while (oTest > oFirst && (--oTest)->fPt == test->fPt) {
2569 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
2570 return;
2571 }
2572 }
2573 oTest = oSpan;
2574 while (oTest < oLast && (++oTest)->fPt == test->fPt) {
2575 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
2576 return;
2577 }
2578 }
2579 if (*missingPtr) {
2580 missingSpans->push_back();
2581 }
2582 MissingSpan& lastMissing = missingSpans->back();
2583 if (*missingPtr) {
2584 lastMissing = missingSpans->end()[-2];
2585 }
2586 *missingPtr = test;
2587 lastMissing.fOther = test->fOther;
2588 lastMissing.fOtherT = test->fOtherT;
2589 }
2590
2591 bool SkOpSegment::checkSmall(int index) const {
2592 if (fTs[index].fSmall) {
2593 return true;
2594 }
2595 double tBase = fTs[index].fT;
2596 while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
2597 ;
2598 return fTs[index].fSmall;
2599 }
2600
2601 // a pair of curves may turn into coincident lines -- small may be a hint that t hat happened
2602 // if a cubic contains a loop, the counts must be adjusted
2603 void SkOpSegment::checkSmall() {
2604 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2605 const SkOpSpan* beginSpan = fTs.begin();
2606 const SkOpSpan* thisSpan = beginSpan - 1;
2607 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small
2608 while (++thisSpan < endSpan) {
2609 if (!thisSpan->fSmall) {
2610 continue;
2611 }
2612 if (!thisSpan->fWindValue) {
2613 continue;
2614 }
2615 const SkOpSpan& firstSpan = this->firstSpan(*thisSpan);
2616 const SkOpSpan& lastSpan = this->lastSpan(*thisSpan);
2617 const SkOpSpan* nextSpan = &firstSpan + 1;
2618 ptrdiff_t smallCount = &lastSpan - &firstSpan + 1;
2619 SkASSERT(1 <= smallCount && smallCount < count());
2620 if (smallCount <= 1 && !nextSpan->fSmall) {
2621 SkASSERT(1 == smallCount);
2622 checkSmallCoincidence(firstSpan, NULL);
2623 continue;
2624 }
2625 // at this point, check for missing computed intersections
2626 const SkPoint& testPt = firstSpan.fPt;
2627 thisSpan = &firstSpan - 1;
2628 SkOpSegment* other = NULL;
2629 while (++thisSpan <= &lastSpan) {
2630 other = thisSpan->fOther;
2631 if (other != this) {
2632 break;
2633 }
2634 }
2635 SkASSERT(other != this);
2636 int oIndex = thisSpan->fOtherIndex;
2637 const SkOpSpan& oSpan = other->span(oIndex);
2638 const SkOpSpan& oFirstSpan = other->firstSpan(oSpan);
2639 const SkOpSpan& oLastSpan = other->lastSpan(oSpan);
2640 ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1;
2641 if (fLoop) {
2642 int smallCounts[2];
2643 SkASSERT(!other->fLoop); // FIXME: we need more complicated logic f or pair of loops
2644 if (calcLoopSpanCount(*thisSpan, smallCounts)) {
2645 if (smallCounts[0] && oCount != smallCounts[0]) {
2646 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2647 }
2648 if (smallCounts[1] && oCount != smallCounts[1]) {
2649 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2650 }
2651 goto nextSmallCheck;
2652 }
2653 }
2654 if (other->fLoop) {
2655 int otherCounts[2];
2656 if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) {
2657 if (otherCounts[0] && otherCounts[0] != smallCount) {
2658 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2659 }
2660 if (otherCounts[1] && otherCounts[1] != smallCount) {
2661 SkASSERT(0); // FIXME: need a working test case to properly code & debug
2662 }
2663 goto nextSmallCheck;
2664 }
2665 }
2666 if (oCount != smallCount) { // check if number of pts in this match oth er
2667 MissingSpan& missing = missingSpans.push_back();
2668 missing.fOther = NULL;
2669 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2670 missing.fPt = testPt;
2671 const SkOpSpan& oSpan = other->span(oIndex);
2672 if (oCount > smallCount) {
2673 missing.fSegment = this;
2674 missing.fT = thisSpan->fT;
2675 other->checkLinks(&oSpan, &missingSpans);
2676 } else {
2677 missing.fSegment = other;
2678 missing.fT = oSpan.fT;
2679 checkLinks(thisSpan, &missingSpans);
2680 }
2681 if (!missingSpans.back().fOther || missing.fSegment->done()) {
2682 missingSpans.pop_back();
2683 }
2684 }
2685 nextSmallCheck:
2686 thisSpan = &lastSpan;
2687 }
2688 int missingCount = missingSpans.count();
2689 for (int index = 0; index < missingCount; ++index) {
2690 MissingSpan& missing = missingSpans[index];
2691 SkOpSegment* missingOther = missing.fOther;
2692 // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid
2693 if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOther T, false,
2694 missing.fPt)) {
2695 continue;
2696 }
2697 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, miss ing.fSegment);
2698 const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
2699 if (otherSpan.fSmall) {
2700 const SkOpSpan* nextSpan = &otherSpan;
2701 if (nextSpan->fPt == missing.fPt) {
2702 continue;
2703 }
2704 do {
2705 ++nextSpan;
2706 } while (nextSpan->fSmall);
2707 if (nextSpan->fT == 1) {
2708 continue;
2709 }
2710 SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpa n->fPt,
2711 nextSpan->fT, missingOther));
2712 } else if (otherSpan.fT > 0) {
2713 const SkOpSpan* priorSpan = &otherSpan;
2714 do {
2715 --priorSpan;
2716 } while (priorSpan->fT == otherSpan.fT);
2717 if (priorSpan->fSmall) {
2718 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missin gOther);
2719 }
2720 }
2721 }
2722 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq ue segments to
2723 // avoid this
2724 for (int index = 0; index < missingCount; ++index) {
2725 MissingSpan& missing = missingSpans[index];
2726 missing.fSegment->fixOtherTIndex();
2727 missing.fOther->fixOtherTIndex();
2728 }
2729 debugValidate();
2730 }
2731
2732 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
2733 SkTArray<MissingSpan, true>* checkMultiple) {
2734 SkASSERT(span.fSmall);
2735 if (0 && !span.fWindValue) {
2736 return;
2737 }
2738 SkASSERT(&span < fTs.end() - 1);
2739 const SkOpSpan* next = &span + 1;
2740 SkASSERT(!next->fSmall || checkMultiple);
2741 if (checkMultiple) {
2742 while (next->fSmall) {
2743 ++next;
2744 SkASSERT(next < fTs.end());
2745 }
2746 }
2747 SkOpSegment* other = span.fOther;
2748 while (other != next->fOther) {
2749 if (!checkMultiple) {
2750 return;
2751 }
2752 const SkOpSpan* test = next + 1;
2753 if (test == fTs.end()) {
2754 return;
2755 }
2756 if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) {
2757 return;
2758 }
2759 next = test;
2760 }
2761 SkASSERT(span.fT < next->fT);
2762 int oStartIndex = other->findExactT(span.fOtherT, this);
2763 int oEndIndex = other->findExactT(next->fOtherT, this);
2764 // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls
2765 if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath: :kLine_Verb) {
2766 SkPoint mid = ptAtT((span.fT + next->fT) / 2);
2767 const SkOpSpan& oSpanStart = other->fTs[oStartIndex];
2768 const SkOpSpan& oSpanEnd = other->fTs[oEndIndex];
2769 SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2);
2770 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
2771 return;
2772 }
2773 }
2774 // FIXME: again, be overly conservative to avoid breaking existing tests
2775 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex]
2776 : other->fTs[oEndIndex];
2777 if (checkMultiple && !oSpan.fSmall) {
2778 return;
2779 }
2780 // SkASSERT(oSpan.fSmall);
2781 if (oStartIndex < oEndIndex) {
2782 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other));
2783 } else {
2784 addTCancel(span.fPt, next->fPt, other);
2785 }
2786 if (!checkMultiple) {
2787 return;
2788 }
2789 // check to see if either segment is coincident with a third segment -- if i t is, and if
2790 // the opposite segment is not already coincident with the third, make it so
2791 // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit
2792 if (span.fWindValue != 1 || span.fOppValue != 0) {
2793 // start here;
2794 // iterate through the spans, looking for the third coincident case
2795 // if we find one, we need to return state to the caller so that the ind ices can be fixed
2796 // this also suggests that all of this function is fragile since it reli es on a valid index
2797 }
2798 // probably should make this a common function rather than copy/paste code
2799 if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) {
2800 const SkOpSpan* oTest = &oSpan;
2801 while (--oTest >= other->fTs.begin()) {
2802 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT) ) {
2803 break;
2804 }
2805 SkOpSegment* testOther = oTest->fOther;
2806 SkASSERT(testOther != this);
2807 // look in both directions to see if there is a coincident span
2808 const SkOpSpan* tTest = testOther->fTs.begin();
2809 for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) {
2810 if (tTest->fPt != span.fPt) {
2811 ++tTest;
2812 continue;
2813 }
2814 if (testOther->verb() != SkPath::kLine_Verb
2815 || other->verb() != SkPath::kLine_Verb) {
2816 SkPoint mid = ptAtT((span.fT + next->fT) / 2);
2817 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2 );
2818 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
2819 continue;
2820 }
2821 }
2822 #if DEBUG_CONCIDENT
2823 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, t estOther->fID,
2824 oTest->fOtherT, tTest->fT);
2825 #endif
2826 if (tTest->fT < oTest->fOtherT) {
2827 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, testOther));
2828 } else {
2829 addTCancel(span.fPt, next->fPt, testOther);
2830 }
2831 MissingSpan missing;
2832 missing.fSegment = testOther;
2833 checkMultiple->push_back(missing);
2834 break;
2835 }
2836 }
2837 oTest = &oSpan;
2838 while (++oTest < other->fTs.end()) {
2839 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT) ) {
2840 break;
2841 }
2842
2843 }
2844 }
2845 }
2846
2847 // if pair of spans on either side of tiny have the same end point and mid point , mark
2848 // them as parallel
2849 void SkOpSegment::checkTiny() {
2850 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2851 SkOpSpan* thisSpan = fTs.begin() - 1;
2852 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny
2853 while (++thisSpan < endSpan) {
2854 if (!thisSpan->fTiny) {
2855 continue;
2856 }
2857 SkOpSpan* nextSpan = thisSpan + 1;
2858 double thisT = thisSpan->fT;
2859 double nextT = nextSpan->fT;
2860 if (thisT == nextT) {
2861 continue;
2862 }
2863 SkASSERT(thisT < nextT);
2864 SkASSERT(thisSpan->fPt == nextSpan->fPt);
2865 SkOpSegment* thisOther = thisSpan->fOther;
2866 SkOpSegment* nextOther = nextSpan->fOther;
2867 int oIndex = thisSpan->fOtherIndex;
2868 for (int oStep = -1; oStep <= 1; oStep += 2) {
2869 int oEnd = thisOther->nextExactSpan(oIndex, oStep);
2870 if (oEnd < 0) {
2871 continue;
2872 }
2873 const SkOpSpan& oSpan = thisOther->span(oEnd);
2874 int nIndex = nextSpan->fOtherIndex;
2875 for (int nStep = -1; nStep <= 1; nStep += 2) {
2876 int nEnd = nextOther->nextExactSpan(nIndex, nStep);
2877 if (nEnd < 0) {
2878 continue;
2879 }
2880 const SkOpSpan& nSpan = nextOther->span(nEnd);
2881 if (oSpan.fPt != nSpan.fPt) {
2882 continue;
2883 }
2884 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
2885 const SkPoint& oPt = thisOther->ptAtT(oMidT);
2886 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
2887 const SkPoint& nPt = nextOther->ptAtT(nMidT);
2888 if (!AlmostEqualUlps(oPt, nPt)) {
2889 continue;
2890 }
2891 #if DEBUG_CHECK_TINY
2892 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fI D,
2893 thisOther->fID, nextOther->fID);
2894 #endif
2895 // this segment is missing a entry that the other contains
2896 // remember so we can add the missing one and recompute the indi ces
2897 MissingSpan& missing = missingSpans.push_back();
2898 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2899 missing.fSegment = thisOther;
2900 missing.fT = thisSpan->fOtherT;
2901 SkASSERT(this != nextOther);
2902 missing.fOther = nextOther;
2903 missing.fOtherT = nextSpan->fOtherT;
2904 missing.fPt = thisSpan->fPt;
2905 }
2906 }
2907 }
2908 int missingCount = missingSpans.count();
2909 if (!missingCount) {
2910 return;
2911 }
2912 for (int index = 0; index < missingCount; ++index) {
2913 MissingSpan& missing = missingSpans[index];
2914 if (missing.fSegment != missing.fOther) {
2915 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOthe rT, false,
2916 missing.fPt);
2917 }
2918 }
2919 // OPTIMIZE: consolidate to avoid multiple calls to fix index
2920 for (int index = 0; index < missingCount; ++index) {
2921 MissingSpan& missing = missingSpans[index];
2922 missing.fSegment->fixOtherTIndex();
2923 missing.fOther->fixOtherTIndex();
2924 }
2925 }
2926
2927 bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment * other) const {
2928 int count = this->count();
2929 for (int index = 0; index < count; ++index) {
2930 const SkOpSpan& span = this->span(index);
2931 if (span.fOther != other) {
2932 continue;
2933 }
2934 if (span.fPt == pt) {
2935 continue;
2936 }
2937 if (!AlmostEqualUlps(span.fPt, pt)) {
2938 continue;
2939 }
2940 if (fVerb != SkPath::kCubic_Verb) {
2941 return true;
2942 }
2943 double tInterval = t - span.fT;
2944 double tMid = t - tInterval / 2;
2945 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
2946 return midPt.approximatelyEqual(xyAtT(t));
2947 }
2948 return false;
2949 }
2950
2951 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* o ther, int oStart,
2952 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) cons t {
2953 SkASSERT(span->fT == 0 || span->fT == 1);
2954 SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
2955 const SkOpSpan* otherSpan = &other->span(oEnd);
2956 double refT = otherSpan->fT;
2957 const SkPoint& refPt = otherSpan->fPt;
2958 const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
2959 do {
2960 const SkOpSegment* match = span->fOther;
2961 if (match == otherSpan->fOther) {
2962 // find start of respective spans and see if both have winding
2963 int startIndex, endIndex;
2964 if (span->fOtherT == 1) {
2965 endIndex = span->fOtherIndex;
2966 startIndex = match->nextExactSpan(endIndex, -1);
2967 } else {
2968 startIndex = span->fOtherIndex;
2969 endIndex = match->nextExactSpan(startIndex, 1);
2970 }
2971 const SkOpSpan& startSpan = match->span(startIndex);
2972 if (startSpan.fWindValue != 0) {
2973 // draw ray from endSpan.fPt perpendicular to end tangent and me asure distance
2974 // to other segment.
2975 const SkOpSpan& endSpan = match->span(endIndex);
2976 SkDLine ray;
2977 SkVector dxdy;
2978 if (span->fOtherT == 1) {
2979 ray.fPts[0].set(startSpan.fPt);
2980 dxdy = match->dxdy(startIndex);
2981 } else {
2982 ray.fPts[0].set(endSpan.fPt);
2983 dxdy = match->dxdy(endIndex);
2984 }
2985 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
2986 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
2987 SkIntersections i;
2988 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])( other->pts(), ray);
2989 for (int index = 0; index < roots; ++index) {
2990 if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
2991 double matchMidT = (match->span(startIndex).fT
2992 + match->span(endIndex).fT) / 2;
2993 SkPoint matchMidPt = match->ptAtT(matchMidT);
2994 double otherMidT = (i[0][index] + other->span(oStart).fT ) / 2;
2995 SkPoint otherMidPt = other->ptAtT(otherMidT);
2996 if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt) ) {
2997 *startPt = startSpan.fPt;
2998 *endPt = endSpan.fPt;
2999 *endT = endSpan.fT;
3000 return true;
3001 }
3002 }
3003 }
3004 }
3005 return false;
3006 }
3007 if (otherSpan == lastSpan) {
3008 break;
3009 }
3010 otherSpan += step;
3011 } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
3012 return false;
3013 }
3014
3015 int SkOpSegment::findEndSpan(int endIndex) const {
3016 const SkOpSpan* span = &fTs[--endIndex];
3017 const SkPoint& lastPt = span->fPt;
3018 double endT = span->fT;
3019 do {
3020 span = &fTs[--endIndex];
3021 } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == end T || span->fTiny));
3022 return endIndex + 1;
3023 } 783 }
3024 784
3025 /* 785 /*
3026 The M and S variable name parts stand for the operators. 786 The M and S variable name parts stand for the operators.
3027 Mi stands for Minuend (see wiki subtraction, analogous to difference) 787 Mi stands for Minuend (see wiki subtraction, analogous to difference)
3028 Su stands for Subtrahend 788 Su stands for Subtrahend
3029 The Opp variable name part designates that the value is for the Opposite operat or. 789 The Opp variable name part designates that the value is for the Opposite operat or.
3030 Opposite values result from combining coincident spans. 790 Opposite values result from combining coincident spans.
3031 */ 791 */
3032 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart , int* nextEnd, 792 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBa se** nextStart,
3033 bool* unsortable, SkPathOp op, const int xo rMiMask, 793 SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, in t xorSuMask) {
3034 const int xorSuMask) { 794 SkOpSpanBase* start = *nextStart;
3035 const int startIndex = *nextStart; 795 SkOpSpanBase* end = *nextEnd;
3036 const int endIndex = *nextEnd; 796 SkASSERT(start != end);
3037 SkASSERT(startIndex != endIndex); 797 int step = start->step(end);
3038 SkDEBUGCODE(const int count = fTs.count()); 798 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar t
3039 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 799 if (other) {
3040 int step = SkSign32(endIndex - startIndex);
3041 *nextStart = startIndex;
3042 SkOpSegment* other = isSimple(nextStart, &step);
3043 if (other)
3044 {
3045 // mark the smaller of startIndex, endIndex done, and all adjacent 800 // mark the smaller of startIndex, endIndex done, and all adjacent
3046 // spans with the same T value (but not 'other' spans) 801 // spans with the same T value (but not 'other' spans)
3047 #if DEBUG_WINDING 802 #if DEBUG_WINDING
3048 SkDebugf("%s simple\n", __FUNCTION__); 803 SkDebugf("%s simple\n", __FUNCTION__);
3049 #endif 804 #endif
3050 int min = SkMin32(startIndex, endIndex); 805 SkOpSpan* startSpan = start->starter(end);
3051 if (fTs[min].fDone) { 806 if (startSpan->done()) {
3052 return NULL; 807 return NULL;
3053 } 808 }
3054 markDoneBinary(min); 809 markDone(startSpan);
3055 double startT = other->fTs[*nextStart].fT; 810 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre v();
3056 *nextEnd = *nextStart;
3057 do {
3058 *nextEnd += step;
3059 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
3060 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
3061 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
3062 *unsortable = true;
3063 return NULL;
3064 }
3065 return other; 811 return other;
3066 } 812 }
3067 const int end = nextExactSpan(startIndex, step); 813 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextSt art)->prev();
3068 SkASSERT(end >= 0); 814 SkASSERT(endNear == end); // is this ever not end?
3069 SkASSERT(startIndex - endIndex != 0); 815 SkASSERT(endNear);
3070 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 816 SkASSERT(start != endNear);
817 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
3071 // more than one viable candidate -- measure angles to find best 818 // more than one viable candidate -- measure angles to find best
3072 819 int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
3073 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp);
3074 bool sortable = calcWinding != SK_NaN32; 820 bool sortable = calcWinding != SK_NaN32;
3075 if (!sortable) { 821 if (!sortable) {
3076 *unsortable = true; 822 *unsortable = true;
3077 markDoneBinary(SkMin32(startIndex, endIndex)); 823 markDone(start->starter(end));
3078 return NULL; 824 return NULL;
3079 } 825 }
3080 SkOpAngle* angle = spanToAngle(end, startIndex); 826 SkOpAngle* angle = this->spanToAngle(end, start);
3081 if (angle->unorderable()) { 827 if (angle->unorderable()) {
3082 *unsortable = true; 828 *unsortable = true;
3083 markDoneBinary(SkMin32(startIndex, endIndex)); 829 markDone(start->starter(end));
3084 return NULL; 830 return NULL;
3085 } 831 }
3086 #if DEBUG_SORT 832 #if DEBUG_SORT
3087 SkDebugf("%s\n", __FUNCTION__); 833 SkDebugf("%s\n", __FUNCTION__);
3088 angle->debugLoop(); 834 angle->debugLoop();
3089 #endif 835 #endif
3090 int sumMiWinding = updateWinding(endIndex, startIndex); 836 int sumMiWinding = updateWinding(end, start);
3091 if (sumMiWinding == SK_MinS32) { 837 if (sumMiWinding == SK_MinS32) {
3092 *unsortable = true; 838 *unsortable = true;
3093 markDoneBinary(SkMin32(startIndex, endIndex)); 839 markDone(start->starter(end));
3094 return NULL; 840 return NULL;
3095 } 841 }
3096 int sumSuWinding = updateOppWinding(endIndex, startIndex); 842 int sumSuWinding = updateOppWinding(end, start);
3097 if (operand()) { 843 if (operand()) {
3098 SkTSwap<int>(sumMiWinding, sumSuWinding); 844 SkTSwap<int>(sumMiWinding, sumSuWinding);
3099 } 845 }
3100 SkOpAngle* nextAngle = angle->next(); 846 SkOpAngle* nextAngle = angle->next();
3101 const SkOpAngle* foundAngle = NULL; 847 const SkOpAngle* foundAngle = NULL;
3102 bool foundDone = false; 848 bool foundDone = false;
3103 // iterate through the angle, and compute everyone's winding 849 // iterate through the angle, and compute everyone's winding
3104 SkOpSegment* nextSegment; 850 SkOpSegment* nextSegment;
3105 int activeCount = 0; 851 int activeCount = 0;
3106 do { 852 do {
3107 nextSegment = nextAngle->segment(); 853 nextSegment = nextAngle->segment();
3108 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle ->start(), 854 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle ->start(),
3109 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); 855 nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
3110 if (activeAngle) { 856 if (activeAngle) {
3111 ++activeCount; 857 ++activeCount;
3112 if (!foundAngle || (foundDone && activeCount & 1)) { 858 if (!foundAngle || (foundDone && activeCount & 1)) {
3113 if (nextSegment->isTiny(nextAngle)) {
3114 *unsortable = true;
3115 markDoneBinary(SkMin32(startIndex, endIndex));
3116 return NULL;
3117 }
3118 foundAngle = nextAngle; 859 foundAngle = nextAngle;
3119 foundDone = nextSegment->done(nextAngle); 860 foundDone = nextSegment->done(nextAngle);
3120 } 861 }
3121 } 862 }
3122 if (nextSegment->done()) { 863 if (nextSegment->done()) {
3123 continue; 864 continue;
3124 } 865 }
3125 if (nextSegment->isTiny(nextAngle)) { 866 if (!activeAngle) {
3126 continue; 867 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle-> end());
3127 } 868 }
3128 if (!activeAngle) { 869 SkOpSpanBase* last = nextAngle->lastMarked();
3129 (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextA ngle->end());
3130 }
3131 SkOpSpan* last = nextAngle->lastMarked();
3132 if (last) { 870 if (last) {
3133 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 871 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
3134 *chase->append() = last; 872 *chase->append() = last;
3135 #if DEBUG_WINDING 873 #if DEBUG_WINDING
3136 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__ , 874 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
3137 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last ->fWindSum, 875 last->segment()->debugID(), last->debugID());
3138 last->fSmall); 876 if (!last->final()) {
877 SkDebugf(" windSum=%d", last->upCast()->windSum());
878 }
879 SkDebugf("\n");
3139 #endif 880 #endif
3140 } 881 }
3141 } while ((nextAngle = nextAngle->next()) != angle); 882 } while ((nextAngle = nextAngle->next()) != angle);
3142 #if DEBUG_ANGLE 883 start->segment()->markDone(start->starter(end));
3143 if (foundAngle) {
3144 foundAngle->debugSameAs(foundAngle);
3145 }
3146 #endif
3147
3148 markDoneBinary(SkMin32(startIndex, endIndex));
3149 if (!foundAngle) { 884 if (!foundAngle) {
3150 return NULL; 885 return NULL;
3151 } 886 }
3152 *nextStart = foundAngle->start(); 887 *nextStart = foundAngle->start();
3153 *nextEnd = foundAngle->end(); 888 *nextEnd = foundAngle->end();
3154 nextSegment = foundAngle->segment(); 889 nextSegment = foundAngle->segment();
3155 #if DEBUG_WINDING 890 #if DEBUG_WINDING
3156 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 891 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
3157 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d); 892 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d);
3158 #endif 893 #endif
3159 return nextSegment; 894 return nextSegment;
3160 } 895 }
3161 896
3162 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next Start, 897 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
3163 int* nextEnd, bool* unsortable) { 898 SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
3164 const int startIndex = *nextStart; 899 SkOpSpanBase* start = *nextStart;
3165 const int endIndex = *nextEnd; 900 SkOpSpanBase* end = *nextEnd;
3166 SkASSERT(startIndex != endIndex); 901 SkASSERT(start != end);
3167 SkDEBUGCODE(const int count = fTs.count()); 902 int step = start->step(end);
3168 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 903 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar t
3169 int step = SkSign32(endIndex - startIndex); 904 if (other) {
3170 *nextStart = startIndex;
3171 SkOpSegment* other = isSimple(nextStart, &step);
3172 if (other)
3173 {
3174 // mark the smaller of startIndex, endIndex done, and all adjacent 905 // mark the smaller of startIndex, endIndex done, and all adjacent
3175 // spans with the same T value (but not 'other' spans) 906 // spans with the same T value (but not 'other' spans)
3176 #if DEBUG_WINDING 907 #if DEBUG_WINDING
3177 SkDebugf("%s simple\n", __FUNCTION__); 908 SkDebugf("%s simple\n", __FUNCTION__);
3178 #endif 909 #endif
3179 int min = SkMin32(startIndex, endIndex); 910 SkOpSpan* startSpan = start->starter(end);
3180 if (fTs[min].fDone) { 911 if (startSpan->done()) {
3181 return NULL; 912 return NULL;
3182 } 913 }
3183 markDoneUnary(min); 914 markDone(startSpan);
3184 double startT = other->fTs[*nextStart].fT; 915 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre v();
3185 *nextEnd = *nextStart;
3186 do {
3187 *nextEnd += step;
3188 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
3189 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
3190 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
3191 *unsortable = true;
3192 return NULL;
3193 }
3194 return other; 916 return other;
3195 } 917 }
3196 const int end = nextExactSpan(startIndex, step); 918 SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextSt art)->prev();
3197 SkASSERT(end >= 0); 919 SkASSERT(endNear == end); // is this ever not end?
3198 SkASSERT(startIndex - endIndex != 0); 920 SkASSERT(endNear);
3199 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 921 SkASSERT(start != endNear);
922 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
3200 // more than one viable candidate -- measure angles to find best 923 // more than one viable candidate -- measure angles to find best
3201 924 int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
3202 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding);
3203 bool sortable = calcWinding != SK_NaN32; 925 bool sortable = calcWinding != SK_NaN32;
3204 if (!sortable) { 926 if (!sortable) {
3205 *unsortable = true; 927 *unsortable = true;
3206 markDoneUnary(SkMin32(startIndex, endIndex)); 928 markDone(start->starter(end));
3207 return NULL; 929 return NULL;
3208 } 930 }
3209 SkOpAngle* angle = spanToAngle(end, startIndex); 931 SkOpAngle* angle = this->spanToAngle(end, start);
932 if (angle->unorderable()) {
933 *unsortable = true;
934 markDone(start->starter(end));
935 return NULL;
936 }
3210 #if DEBUG_SORT 937 #if DEBUG_SORT
3211 SkDebugf("%s\n", __FUNCTION__); 938 SkDebugf("%s\n", __FUNCTION__);
3212 angle->debugLoop(); 939 angle->debugLoop();
3213 #endif 940 #endif
3214 int sumWinding = updateWinding(endIndex, startIndex); 941 int sumWinding = updateWinding(end, start);
3215 SkOpAngle* nextAngle = angle->next(); 942 SkOpAngle* nextAngle = angle->next();
3216 const SkOpAngle* foundAngle = NULL; 943 const SkOpAngle* foundAngle = NULL;
3217 bool foundDone = false; 944 bool foundDone = false;
945 // iterate through the angle, and compute everyone's winding
3218 SkOpSegment* nextSegment; 946 SkOpSegment* nextSegment;
3219 int activeCount = 0; 947 int activeCount = 0;
3220 do { 948 do {
3221 nextSegment = nextAngle->segment(); 949 nextSegment = nextAngle->segment();
3222 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn gle->end(), 950 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn gle->end(),
3223 &sumWinding); 951 &sumWinding);
3224 if (activeAngle) { 952 if (activeAngle) {
3225 ++activeCount; 953 ++activeCount;
3226 if (!foundAngle || (foundDone && activeCount & 1)) { 954 if (!foundAngle || (foundDone && activeCount & 1)) {
3227 if (nextSegment->isTiny(nextAngle)) {
3228 *unsortable = true;
3229 markDoneUnary(SkMin32(startIndex, endIndex));
3230 return NULL;
3231 }
3232 foundAngle = nextAngle; 955 foundAngle = nextAngle;
3233 foundDone = nextSegment->done(nextAngle); 956 foundDone = nextSegment->done(nextAngle);
3234 } 957 }
3235 } 958 }
3236 if (nextSegment->done()) { 959 if (nextSegment->done()) {
3237 continue; 960 continue;
3238 } 961 }
3239 if (nextSegment->isTiny(nextAngle)) { 962 if (!activeAngle) {
3240 continue; 963 (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle-> end());
3241 } 964 }
3242 if (!activeAngle) { 965 SkOpSpanBase* last = nextAngle->lastMarked();
3243 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->en d());
3244 }
3245 SkOpSpan* last = nextAngle->lastMarked();
3246 if (last) { 966 if (last) {
3247 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 967 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
3248 *chase->append() = last; 968 *chase->append() = last;
3249 #if DEBUG_WINDING 969 #if DEBUG_WINDING
3250 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__ , 970 SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
3251 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last ->fWindSum, 971 last->segment()->debugID(), last->debugID());
3252 last->fSmall); 972 if (!last->final()) {
973 SkDebugf(" windSum=%d", last->upCast()->windSum());
974 }
975 SkDebugf("\n");
3253 #endif 976 #endif
3254 } 977 }
3255 } while ((nextAngle = nextAngle->next()) != angle); 978 } while ((nextAngle = nextAngle->next()) != angle);
3256 markDoneUnary(SkMin32(startIndex, endIndex)); 979 start->segment()->markDone(start->starter(end));
3257 if (!foundAngle) { 980 if (!foundAngle) {
3258 return NULL; 981 return NULL;
3259 } 982 }
3260 *nextStart = foundAngle->start(); 983 *nextStart = foundAngle->start();
3261 *nextEnd = foundAngle->end(); 984 *nextEnd = foundAngle->end();
3262 nextSegment = foundAngle->segment(); 985 nextSegment = foundAngle->segment();
3263 #if DEBUG_WINDING 986 #if DEBUG_WINDING
3264 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 987 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
3265 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d); 988 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d);
3266 #endif 989 #endif
3267 return nextSegment; 990 return nextSegment;
3268 } 991 }
3269 992
3270 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort able) { 993 SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** n extEnd,
3271 const int startIndex = *nextStart; 994 bool* unsortable) {
3272 const int endIndex = *nextEnd; 995 SkOpSpanBase* start = *nextStart;
3273 SkASSERT(startIndex != endIndex); 996 SkOpSpanBase* end = *nextEnd;
3274 SkDEBUGCODE(int count = fTs.count()); 997 SkASSERT(start != end);
3275 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 998 int step = start->step(end);
3276 int step = SkSign32(endIndex - startIndex); 999 SkOpSegment* other = this->isSimple(nextStart, &step); // advances nextStar t
3277 // Detect cases where all the ends canceled out (e.g., 1000 if (other) {
3278 // there is no angle) and therefore there's only one valid connection 1001 // mark the smaller of startIndex, endIndex done, and all adjacent
3279 *nextStart = startIndex; 1002 // spans with the same T value (but not 'other' spans)
3280 SkOpSegment* other = isSimple(nextStart, &step);
3281 if (other)
3282 {
3283 #if DEBUG_WINDING 1003 #if DEBUG_WINDING
3284 SkDebugf("%s simple\n", __FUNCTION__); 1004 SkDebugf("%s simple\n", __FUNCTION__);
3285 #endif 1005 #endif
3286 int min = SkMin32(startIndex, endIndex); 1006 SkOpSpan* startSpan = start->starter(end);
3287 if (fTs[min].fDone) { 1007 if (startSpan->done()) {
3288 return NULL; 1008 return NULL;
3289 } 1009 }
3290 markDone(min, 1); 1010 markDone(startSpan);
3291 double startT = other->fTs[*nextStart].fT; 1011 *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->pre v();
3292 // FIXME: I don't know why the logic here is difference from the winding case
3293 SkDEBUGCODE(bool firstLoop = true;)
3294 if ((approximately_less_than_zero(startT) && step < 0)
3295 || (approximately_greater_than_one(startT) && step > 0)) {
3296 step = -step;
3297 SkDEBUGCODE(firstLoop = false;)
3298 }
3299 do {
3300 *nextEnd = *nextStart;
3301 do {
3302 *nextEnd += step;
3303 } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
3304 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
3305 break;
3306 }
3307 SkASSERT(firstLoop);
3308 SkDEBUGCODE(firstLoop = false;)
3309 step = -step;
3310 } while (true);
3311 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
3312 return other; 1012 return other;
3313 } 1013 }
3314 SkASSERT(startIndex - endIndex != 0); 1014 SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next( ) \
3315 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 1015 : (*nextStart)->prev());
3316 // parallel block above with presorted version 1016 SkASSERT(endNear == end); // is this ever not end?
3317 int end = nextExactSpan(startIndex, step); 1017 SkASSERT(endNear);
3318 SkASSERT(end >= 0); 1018 SkASSERT(start != endNear);
3319 SkOpAngle* angle = spanToAngle(end, startIndex); 1019 SkASSERT((start->t() < endNear->t()) ^ (step < 0));
3320 SkASSERT(angle); 1020 SkOpAngle* angle = this->spanToAngle(end, start);
1021 if (angle->unorderable()) {
1022 *unsortable = true;
1023 markDone(start->starter(end));
1024 return NULL;
1025 }
3321 #if DEBUG_SORT 1026 #if DEBUG_SORT
3322 SkDebugf("%s\n", __FUNCTION__); 1027 SkDebugf("%s\n", __FUNCTION__);
3323 angle->debugLoop(); 1028 angle->debugLoop();
3324 #endif 1029 #endif
3325 SkOpAngle* nextAngle = angle->next(); 1030 SkOpAngle* nextAngle = angle->next();
3326 const SkOpAngle* foundAngle = NULL; 1031 const SkOpAngle* foundAngle = NULL;
3327 bool foundDone = false; 1032 bool foundDone = false;
1033 // iterate through the angle, and compute everyone's winding
3328 SkOpSegment* nextSegment; 1034 SkOpSegment* nextSegment;
3329 int activeCount = 0; 1035 int activeCount = 0;
3330 do { 1036 do {
3331 nextSegment = nextAngle->segment(); 1037 nextSegment = nextAngle->segment();
3332 ++activeCount; 1038 ++activeCount;
3333 if (!foundAngle || (foundDone && activeCount & 1)) { 1039 if (!foundAngle || (foundDone && activeCount & 1)) {
3334 if (nextSegment->isTiny(nextAngle)) {
3335 *unsortable = true;
3336 return NULL;
3337 }
3338 foundAngle = nextAngle; 1040 foundAngle = nextAngle;
3339 if (!(foundDone = nextSegment->done(nextAngle))) { 1041 if (!(foundDone = nextSegment->done(nextAngle))) {
3340 break; 1042 break;
3341 } 1043 }
3342 } 1044 }
3343 nextAngle = nextAngle->next(); 1045 nextAngle = nextAngle->next();
3344 } while (nextAngle != angle); 1046 } while (nextAngle != angle);
3345 markDone(SkMin32(startIndex, endIndex), 1); 1047 start->segment()->markDone(start->starter(end));
3346 if (!foundAngle) { 1048 if (!foundAngle) {
3347 return NULL; 1049 return NULL;
3348 } 1050 }
3349 *nextStart = foundAngle->start(); 1051 *nextStart = foundAngle->start();
3350 *nextEnd = foundAngle->end(); 1052 *nextEnd = foundAngle->end();
3351 nextSegment = foundAngle->segment(); 1053 nextSegment = foundAngle->segment();
3352 #if DEBUG_WINDING 1054 #if DEBUG_WINDING
3353 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 1055 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
3354 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d); 1056 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn d);
3355 #endif 1057 #endif
3356 return nextSegment; 1058 return nextSegment;
3357 } 1059 }
3358 1060
3359 int SkOpSegment::findStartSpan(int startIndex) const { 1061 SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS panBase** endPtr,
3360 int index = startIndex; 1062 bool* unsortable, SkChunkAlloc* allocator) {
3361 const SkOpSpan* span = &fTs[index];
3362 const SkPoint& firstPt = span->fPt;
3363 double firstT = span->fT;
3364 const SkOpSpan* prior;
3365 do {
3366 prior = span;
3367 span = &fTs[++index];
3368 } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt)
3369 && (span->fT == firstT || prior->fTiny));
3370 return index;
3371 }
3372
3373 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
3374 int count = this->count();
3375 for (int index = 0; index < count; ++index) {
3376 const SkOpSpan& span = fTs[index];
3377 if (span.fT == t && span.fOther == match) {
3378 return index;
3379 }
3380 }
3381 SkASSERT(0);
3382 return -1;
3383 }
3384
3385
3386
3387 int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const {
3388 int count = this->count();
3389 for (int index = 0; index < count; ++index) {
3390 const SkOpSpan& span = fTs[index];
3391 if (span.fOtherT == t && span.fOther == match) {
3392 return index;
3393 }
3394 }
3395 return -1;
3396 }
3397
3398 int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) co nst {
3399 int count = this->count();
3400 // prefer exact matches over approximate matches
3401 for (int index = 0; index < count; ++index) {
3402 const SkOpSpan& span = fTs[index];
3403 if (span.fT == t && span.fOther == match) {
3404 return index;
3405 }
3406 }
3407 for (int index = 0; index < count; ++index) {
3408 const SkOpSpan& span = fTs[index];
3409 if (approximately_equal_orderable(span.fT, t) && span.fOther == match) {
3410 return index;
3411 }
3412 }
3413 // Usually, the pair of ts are an exact match. It's possible that the t valu es have
3414 // been adjusted to make multiple intersections align. In this rare case, lo ok for a
3415 // matching point / match pair instead.
3416 for (int index = 0; index < count; ++index) {
3417 const SkOpSpan& span = fTs[index];
3418 if (span.fPt == pt && span.fOther == match) {
3419 return index;
3420 }
3421 }
3422 SkASSERT(0);
3423 return -1;
3424 }
3425
3426 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort able,
3427 bool firstPass) {
3428 // iterate through T intersections and return topmost 1063 // iterate through T intersections and return topmost
3429 // topmost tangent from y-min to first pt is closer to horizontal 1064 // topmost tangent from y-min to first pt is closer to horizontal
3430 SkASSERT(!done()); 1065 SkASSERT(!done());
3431 int firstT = -1; 1066 SkOpSpanBase* firstT = NULL;
3432 /* SkPoint topPt = */ activeLeftTop(&firstT); 1067 (void) this->activeLeftTop(&firstT);
3433 if (firstT < 0) { 1068 if (!firstT) {
3434 *unsortable = !firstPass; 1069 *unsortable = !firstPass;
3435 firstT = 0; 1070 firstT = &fHead;
3436 while (fTs[firstT].fDone) { 1071 while (firstT->upCast()->done()) {
3437 SkASSERT(firstT < fTs.count()); 1072 firstT = firstT->upCast()->next();
3438 ++firstT;
3439 } 1073 }
3440 *tIndexPtr = firstT; 1074 *startPtr = firstT;
3441 *endIndexPtr = nextExactSpan(firstT, 1); 1075 *endPtr = firstT->upCast()->next();
3442 return this; 1076 return this;
3443 } 1077 }
3444 // sort the edges to find the leftmost 1078 // sort the edges to find the leftmost
3445 int step = 1; 1079 int step = 1;
3446 int end; 1080 SkOpSpanBase* end;
3447 if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) { 1081 if (firstT->final() || firstT->upCast()->done()) {
3448 step = -1; 1082 step = -1;
3449 end = nextSpan(firstT, step); 1083 end = firstT->prev();
3450 SkASSERT(end != -1); 1084 SkASSERT(end);
1085 } else {
1086 end = firstT->upCast()->next();
3451 } 1087 }
3452 // if the topmost T is not on end, or is three-way or more, find left 1088 // if the topmost T is not on end, or is three-way or more, find left
3453 // look for left-ness from tLeft to firstT (matching y of other) 1089 // look for left-ness from tLeft to firstT (matching y of other)
3454 SkASSERT(firstT - end != 0); 1090 SkASSERT(firstT != end);
3455 SkOpAngle* markAngle = spanToAngle(firstT, end); 1091 SkOpAngle* markAngle = spanToAngle(firstT, end);
3456 if (!markAngle) { 1092 if (!markAngle) {
3457 markAngle = addSingletonAngles(step); 1093 markAngle = addSingletonAngles(step, allocator);
3458 } 1094 }
3459 markAngle->markStops(); 1095 markAngle->markStops();
3460 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle 1096 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
3461 : markAngle->findFirst(); 1097 : markAngle->findFirst();
3462 if (!baseAngle) { 1098 if (!baseAngle) {
3463 return NULL; // nothing to do 1099 return NULL; // nothing to do
3464 } 1100 }
3465 SkScalar top = SK_ScalarMax; 1101 SkScalar top = SK_ScalarMax;
3466 const SkOpAngle* firstAngle = NULL; 1102 const SkOpAngle* firstAngle = NULL;
3467 const SkOpAngle* angle = baseAngle; 1103 const SkOpAngle* angle = baseAngle;
3468 do { 1104 do {
3469 if (!angle->unorderable()) { 1105 if (!angle->unorderable()) {
3470 SkOpSegment* next = angle->segment(); 1106 const SkOpSegment* next = angle->segment();
3471 SkPathOpsBounds bounds; 1107 SkPathOpsBounds bounds;
3472 next->subDivideBounds(angle->end(), angle->start(), &bounds); 1108 next->subDivideBounds(angle->end(), angle->start(), &bounds);
3473 bool nearSame = AlmostEqualUlps(top, bounds.top()); 1109 bool nearSame = AlmostEqualUlps(top, bounds.top());
3474 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s ectorStart(); 1110 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s ectorStart();
3475 bool lesserSector = top > bounds.fTop; 1111 bool lesserSector = top > bounds.fTop;
3476 if (lesserSector && (!nearSame || lowerSector)) { 1112 if (lesserSector && (!nearSame || lowerSector)) {
3477 top = bounds.fTop; 1113 top = bounds.fTop;
3478 firstAngle = angle; 1114 firstAngle = angle;
3479 } 1115 }
3480 } 1116 }
3481 angle = angle->next(); 1117 angle = angle->next();
3482 } while (angle != baseAngle); 1118 } while (angle != baseAngle);
3483 if (!firstAngle) { 1119 if (!firstAngle) {
3484 return NULL; // if all are unorderable, give up 1120 return NULL; // if all are unorderable, give up
3485 } 1121 }
3486 #if DEBUG_SORT 1122 #if DEBUG_SORT
3487 SkDebugf("%s\n", __FUNCTION__); 1123 SkDebugf("%s\n", __FUNCTION__);
3488 firstAngle->debugLoop(); 1124 firstAngle->debugLoop();
3489 #endif 1125 #endif
3490 // skip edges that have already been processed 1126 // skip edges that have already been processed
3491 angle = firstAngle; 1127 angle = firstAngle;
3492 SkOpSegment* leftSegment = NULL; 1128 SkOpSegment* leftSegment = NULL;
3493 bool looped = false; 1129 bool looped = false;
3494 do { 1130 do {
3495 *unsortable = angle->unorderable(); 1131 *unsortable = angle->unorderable();
3496 if (firstPass || !*unsortable) { 1132 if (firstPass || !*unsortable) {
3497 leftSegment = angle->segment(); 1133 leftSegment = angle->segment();
3498 *tIndexPtr = angle->end(); 1134 *startPtr = angle->end();
3499 *endIndexPtr = angle->start(); 1135 *endPtr = angle->start();
3500 if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) { 1136 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr);
1137 if (!firstSpan->done()) {
3501 break; 1138 break;
3502 } 1139 }
3503 } 1140 }
3504 angle = angle->next(); 1141 angle = angle->next();
3505 looped = true; 1142 looped = true;
3506 } while (angle != firstAngle); 1143 } while (angle != firstAngle);
3507 if (angle == firstAngle && looped) { 1144 if (angle == firstAngle && looped) {
3508 return NULL; 1145 return NULL;
3509 } 1146 }
3510 if (leftSegment->verb() >= SkPath::kQuad_Verb) { 1147 if (leftSegment->verb() >= SkPath::kQuad_Verb) {
3511 const int tIndex = *tIndexPtr; 1148 SkOpSpanBase* start = *startPtr;
3512 const int endIndex = *endIndexPtr; 1149 SkOpSpanBase* end = *endPtr;
3513 bool swap; 1150 bool swap;
3514 if (!leftSegment->clockwise(tIndex, endIndex, &swap)) { 1151 if (!leftSegment->clockwise(start, end, &swap)) {
3515 #if DEBUG_SWAP_TOP 1152 #if DEBUG_SWAP_TOP
3516 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=% d monotonic=%d\n", 1153 SkDebugf("%s swap=%d inflections=%d monotonic=%d\n",
3517 __FUNCTION__, 1154 __FUNCTION__,
3518 swap, leftSegment->debugInflections(tIndex, endIndex), 1155 swap, leftSegment->debugInflections(start, end),
3519 leftSegment->serpentine(tIndex, endIndex), 1156 leftSegment->monotonicInY(start, end));
3520 leftSegment->controlsContainedByEnds(tIndex, endIndex),
3521 leftSegment->monotonicInY(tIndex, endIndex));
3522 #endif 1157 #endif
3523 if (swap) { 1158 if (swap) {
3524 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t he first 1159 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t he first
3525 // sorted but merely the first not already processed (i.e., not done) 1160 // sorted but merely the first not already processed (i.e., not done)
3526 SkTSwap(*tIndexPtr, *endIndexPtr); 1161 SkTSwap(*startPtr, *endPtr);
3527 } 1162 }
3528 } 1163 }
3529 } 1164 }
3530 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
3531 return leftSegment; 1165 return leftSegment;
3532 } 1166 }
3533 1167
3534 int SkOpSegment::firstActive(int tIndex) const { 1168 SkOpGlobalState* SkOpSegment::globalState() const {
3535 while (fTs[tIndex].fTiny) { 1169 return contour()->globalState();
3536 SkASSERT(!isCanceled(tIndex));
3537 ++tIndex;
3538 }
3539 return tIndex;
3540 } 1170 }
3541 1171
3542 // FIXME: not crazy about this 1172 void SkOpSegment::init(SkPoint pts[], SkOpContour* contour, SkPath::Verb verb) {
3543 // when the intersections are performed, the other index is into an 1173 fContour = contour;
3544 // incomplete array. As the array grows, the indices become incorrect 1174 fNext = NULL;
3545 // while the following fixes the indices up again, it isn't smart about 1175 fPts = pts;
3546 // skipping segments whose indices are already correct 1176 fVerb = verb;
3547 // assuming we leave the code that wrote the index in the first place 1177 fCount = 0;
3548 // FIXME: if called after remove, this needs to correct tiny 1178 fDoneCount = 0;
3549 void SkOpSegment::fixOtherTIndex() { 1179 fVisited = false;
3550 int iCount = fTs.count(); 1180 SkOpSpan* zeroSpan = &fHead;
3551 for (int i = 0; i < iCount; ++i) { 1181 zeroSpan->init(this, NULL, 0, fPts[0]);
3552 SkOpSpan& iSpan = fTs[i]; 1182 SkOpSpanBase* oneSpan = &fTail;
3553 double oT = iSpan.fOtherT; 1183 zeroSpan->setNext(oneSpan);
3554 SkOpSegment* other = iSpan.fOther; 1184 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
3555 int oCount = other->fTs.count(); 1185 PATH_OPS_DEBUG_CODE(fID = globalState()->nextSegmentID());
3556 SkDEBUGCODE(iSpan.fOtherIndex = -1);
3557 for (int o = 0; o < oCount; ++o) {
3558 SkOpSpan& oSpan = other->fTs[o];
3559 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan .fT) {
3560 iSpan.fOtherIndex = o;
3561 oSpan.fOtherIndex = i;
3562 break;
3563 }
3564 }
3565 SkASSERT(iSpan.fOtherIndex >= 0);
3566 }
3567 } 1186 }
3568 1187
3569 bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const { 1188 void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
3570 int foundEnds = 0; 1189 SkOpAngle::IncludeType angleIncludeType) {
3571 int count = this->count(); 1190 int local = SkOpSegment::SpanSign(start, end);
3572 for (int index = 0; index < count; ++index) {
3573 const SkOpSpan& span = this->span(index);
3574 if (span.fCoincident) {
3575 foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.f T));
3576 }
3577 }
3578 SkASSERT(foundEnds != 7);
3579 return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6; // two bit s set
3580 }
3581
3582 bool SkOpSegment::inconsistentAngle(int maxWinding, int sumWinding, int oppMaxWi nding,
3583 int oppSumWinding, const SkOpAngle* angle) const {
3584 SkASSERT(angle->segment() == this);
3585 if (UseInnerWinding(maxWinding, sumWinding)) {
3586 maxWinding = sumWinding;
3587 }
3588 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW inding)) {
3589 oppMaxWinding = oppSumWinding;
3590 }
3591 return inconsistentWinding(angle, maxWinding, oppMaxWinding);
3592 }
3593
3594 bool SkOpSegment::inconsistentWinding(const SkOpAngle* angle, int winding,
3595 int oppWinding) const {
3596 int index = angle->start();
3597 int endIndex = angle->end();
3598 int min = SkMin32(index, endIndex);
3599 int step = SkSign32(endIndex - index);
3600 if (inconsistentWinding(min, winding, oppWinding)) {
3601 return true;
3602 }
3603 const SkOpSegment* other = this;
3604 while ((other = other->nextChase(&index, &step, &min, NULL))) {
3605 if (other->fTs[min].fWindSum != SK_MinS32) {
3606 break;
3607 }
3608 if (fOperand == other->fOperand) {
3609 if (other->inconsistentWinding(min, winding, oppWinding)) {
3610 return true;
3611 }
3612 } else {
3613 if (other->inconsistentWinding(min, oppWinding, winding)) {
3614 return true;
3615 }
3616 }
3617 }
3618 return false;
3619 }
3620
3621 bool SkOpSegment::inconsistentWinding(int index, int winding, int oppWinding) co nst {
3622 SkASSERT(winding || oppWinding);
3623 double referenceT = this->span(index).fT;
3624 int lesser = index;
3625 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3626 if (inconsistentWinding(__FUNCTION__, lesser, winding, oppWinding)) {
3627 return true;
3628 }
3629 }
3630 do {
3631 if (inconsistentWinding(__FUNCTION__, index, winding, oppWinding)) {
3632 return true;
3633 }
3634 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc eT));
3635 return false;
3636 }
3637
3638 bool SkOpSegment::inconsistentWinding(const char* funName, int tIndex, int windi ng,
3639 int oppWinding) const {
3640 const SkOpSpan& span = this->span(tIndex);
3641 if (span.fDone && !span.fSmall) {
3642 return false;
3643 }
3644 return (span.fWindSum != SK_MinS32 && span.fWindSum != winding)
3645 || (span.fOppSum != SK_MinS32 && span.fOppSum != oppWinding);
3646 }
3647
3648 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, boo l evenOdd) {
3649 fDoneSpans = 0;
3650 fOperand = operand;
3651 fXor = evenOdd;
3652 fPts = pts;
3653 fVerb = verb;
3654 fLoop = fMultiples = fSmall = fTiny = false;
3655 }
3656
3657 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIn cludeType) {
3658 int local = spanSign(start, end);
3659 SkDEBUGCODE(bool success); 1191 SkDEBUGCODE(bool success);
3660 if (angleIncludeType == SkOpAngle::kBinarySingle) { 1192 if (angleIncludeType == SkOpAngle::kBinarySingle) {
3661 int oppLocal = oppSign(start, end); 1193 int oppLocal = SkOpSegment::OppSign(start, end);
3662 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal, NULL); 1194 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal, NULL);
3663 // OPTIMIZATION: the reverse mark and chase could skip the first marking 1195 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3664 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal, NULL); 1196 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal, NULL);
3665 } else { 1197 } else {
3666 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL); 1198 SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL);
3667 // OPTIMIZATION: the reverse mark and chase could skip the first marking 1199 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3668 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL); 1200 SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL);
3669 } 1201 }
3670 SkASSERT(success); 1202 SkASSERT(success);
3671 } 1203 }
3672 1204
3673 /* 1205 /*
3674 when we start with a vertical intersect, we try to use the dx to determine if th e edge is to 1206 when we start with a vertical intersect, we try to use the dx to determine if th e edge is to
3675 the left or the right of vertical. This determines if we need to add the span's 1207 the left or the right of vertical. This determines if we need to add the span's
3676 sign or not. However, this isn't enough. 1208 sign or not. However, this isn't enough.
3677 If the supplied sign (winding) is zero, then we didn't hit another vertical span , so dx is needed. 1209 If the supplied sign (winding) is zero, then we didn't hit another vertical span , so dx is needed.
3678 If there was a winding, then it may or may not need adjusting. If the span the w inding was borrowed 1210 If there was a winding, then it may or may not need adjusting. If the span the w inding was borrowed
3679 from has the same x direction as this span, the winding should change. If the dx is opposite, then 1211 from has the same x direction as this span, the winding should change. If the dx is opposite, then
3680 the same winding is shared by both. 1212 the same winding is shared by both.
3681 */ 1213 */
3682 bool SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc alar hitDx, 1214 bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHi t,
3683 int oppWind, SkScalar hitOppDx) { 1215 int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) {
1216 SkASSERT(this == start->segment());
3684 SkASSERT(hitDx || !winding); 1217 SkASSERT(hitDx || !winding);
3685 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; 1218 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
3686 SkASSERT(dx); 1219 // SkASSERT(dx);
3687 int windVal = windValue(SkMin32(start, end)); 1220 int windVal = start->starter(end)->windValue();
3688 #if DEBUG_WINDING_AT_T 1221 #if DEBUG_WINDING_AT_T
3689 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d ebugID(), winding, 1222 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, d ebugID(), winding,
3690 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); 1223 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
3691 #endif 1224 #endif
3692 int sideWind = winding + (dx < 0 ? windVal : -windVal); 1225 int sideWind = winding + (dx < 0 ? windVal : -windVal);
3693 if (abs(winding) < abs(sideWind)) { 1226 if (abs(winding) < abs(sideWind)) {
3694 winding = sideWind; 1227 winding = sideWind;
3695 } 1228 }
3696 SkDEBUGCODE(int oppLocal = oppSign(start, end)); 1229 SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end));
3697 SkASSERT(hitOppDx || !oppWind || !oppLocal); 1230 SkASSERT(hitOppDx || !oppWind || !oppLocal);
3698 int oppWindVal = oppValue(SkMin32(start, end)); 1231 int oppWindVal = start->starter(end)->oppValue();
3699 if (!oppWind) { 1232 if (!oppWind) {
3700 oppWind = dx < 0 ? oppWindVal : -oppWindVal; 1233 oppWind = dx < 0 ? oppWindVal : -oppWindVal;
3701 } else if (hitOppDx * dx >= 0) { 1234 } else if (hitOppDx * dx >= 0) {
3702 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); 1235 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
3703 if (abs(oppWind) < abs(oppSideWind)) { 1236 if (abs(oppWind) < abs(oppSideWind)) {
3704 oppWind = oppSideWind; 1237 oppWind = oppSideWind;
3705 } 1238 }
3706 } 1239 }
3707 #if DEBUG_WINDING_AT_T 1240 #if DEBUG_WINDING_AT_T
3708 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind); 1241 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
3709 #endif 1242 #endif
3710 // if this fails to mark (because the edges are too small) inform caller to try again 1243 // if this fails to mark (because the edges are too small) inform caller to try again
3711 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL); 1244 bool success = markAndChaseWinding(start, end, winding, oppWind, NULL);
3712 // OPTIMIZATION: the reverse mark and chase could skip the first marking 1245 // OPTIMIZATION: the reverse mark and chase could skip the first marking
3713 success |= markAndChaseWinding(end, start, winding, oppWind, NULL); 1246 success |= markAndChaseWinding(end, start, winding, oppWind, NULL);
3714 return success; 1247 return success;
3715 } 1248 }
3716 1249
3717 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPt r) const { 1250 bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
3718 if (!baseAngle->inLoop()) { 1251 SkDPoint cPt = this->dPtAtT(t);
3719 return false; 1252 int pts = SkPathOpsVerbToPoints(this->verb());
3720 } 1253 SkDVector dxdy = (*CurveDSlopeAtT[pts])(this->pts(), t);
3721 int index = *indexPtr; 1254 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
3722 SkOpAngle* from = fTs[index].fFromAngle; 1255 SkIntersections i;
3723 SkOpAngle* to = fTs[index].fToAngle; 1256 int oppPts = SkPathOpsVerbToPoints(opp->verb());
3724 while (++index < spanCount) { 1257 (*CurveIntersectRay[oppPts])(opp->pts(), perp, &i);
3725 SkOpAngle* nextFrom = fTs[index].fFromAngle; 1258 int used = i.used();
3726 SkOpAngle* nextTo = fTs[index].fToAngle; 1259 for (int index = 0; index < used; ++index) {
3727 if (from != nextFrom || to != nextTo) { 1260 if (cPt.roughlyEqual(i.pt(index))) {
3728 break; 1261 return true;
3729 } 1262 }
3730 } 1263 }
3731 *indexPtr = index;
3732 return true;
3733 }
3734
3735 // OPTIMIZE: successive calls could start were the last leaves off
3736 // or calls could specialize to walk forwards or backwards
3737 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
3738 int tCount = fTs.count();
3739 for (int index = 0; index < tCount; ++index) {
3740 const SkOpSpan& span = fTs[index];
3741 if (approximately_zero(startT - span.fT) && pt == span.fPt) {
3742 return false;
3743 }
3744 }
3745 return true;
3746 }
3747
3748
3749 SkOpSegment* SkOpSegment::isSimple(int* end, int* step) {
3750 return nextChase(end, step, NULL, NULL);
3751 }
3752
3753 bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
3754 int start = angle->start();
3755 int end = angle->end();
3756 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
3757 return mSpan.fTiny;
3758 }
3759
3760 bool SkOpSegment::isTiny(int index) const {
3761 return fTs[index].fTiny;
3762 }
3763
3764 // look pair of active edges going away from coincident edge
3765 // one of them should be the continuation of other
3766 // if both are active, look to see if they both the connect to another coinciden t pair
3767 // if at least one is a line, then make the pair coincident
3768 // if neither is a line, test for coincidence
3769 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoi nt& otherPt,
3770 int step, bool cancel) {
3771 int otherTIndex = other->findT(otherT, otherPt, this);
3772 int next = other->nextExactSpan(otherTIndex, step);
3773 int otherMin = SkMin32(otherTIndex, next);
3774 int otherWind = other->span(otherMin).fWindValue;
3775 if (otherWind == 0) {
3776 return false;
3777 }
3778 if (next < 0) {
3779 return false; // can happen if t values were adjusted but coincident ts were not
3780 }
3781 int tIndex = 0;
3782 do {
3783 SkOpSpan* test = &fTs[tIndex];
3784 SkASSERT(test->fT == 0);
3785 if (test->fOther == other || test->fOtherT != 1) {
3786 continue;
3787 }
3788 SkPoint startPt, endPt;
3789 double endT;
3790 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
3791 SkOpSegment* match = test->fOther;
3792 if (cancel) {
3793 match->addTCancel(startPt, endPt, other);
3794 } else {
3795 if (!match->addTCoincident(startPt, endPt, endT, other)) {
3796 return false;
3797 }
3798 }
3799 return true;
3800 }
3801 } while (fTs[++tIndex].fT == 0);
3802 return false; 1264 return false;
3803 } 1265 }
3804 1266
3805 // this span is excluded by the winding rule -- chase the ends 1267 bool SkOpSegment::isXor() const {
3806 // as long as they are unambiguous to mark connections as done 1268 return fContour->isXor();
3807 // and give them the same winding value 1269 }
3808 1270
3809 SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) { 1271 SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* e nd) {
3810 int step = SkSign32(endIndex - index); 1272 int step = start->step(end);
3811 int min = SkMin32(index, endIndex); 1273 SkOpSpan* minSpan = start->starter(end);
3812 markDoneBinary(min); 1274 markDone(minSpan);
3813 SkOpSpan* last = NULL; 1275 SkOpSpanBase* last = NULL;
3814 SkOpSegment* other = this; 1276 SkOpSegment* other = this;
3815 while ((other = other->nextChase(&index, &step, &min, &last))) { 1277 while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
3816 if (other->done()) { 1278 if (other->done()) {
3817 SkASSERT(!last); 1279 SkASSERT(!last);
3818 break; 1280 break;
3819 } 1281 }
3820 other->markDoneBinary(min); 1282 other->markDone(minSpan);
3821 } 1283 }
3822 return last; 1284 return last;
3823 } 1285 }
3824 1286
3825 SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) { 1287 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, in t winding,
3826 int step = SkSign32(endIndex - index); 1288 SkOpSpanBase** lastPtr) {
3827 int min = SkMin32(index, endIndex); 1289 SkOpSpan* spanStart = start->starter(end);
3828 markDoneUnary(min); 1290 int step = start->step(end);
3829 SkOpSpan* last = NULL; 1291 bool success = markWinding(spanStart, winding);
1292 SkOpSpanBase* last = NULL;
3830 SkOpSegment* other = this; 1293 SkOpSegment* other = this;
3831 while ((other = other->nextChase(&index, &step, &min, &last))) { 1294 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
3832 if (other->done()) { 1295 if (spanStart->windSum() != SK_MinS32) {
1296 SkASSERT(spanStart->windSum() == winding);
3833 SkASSERT(!last); 1297 SkASSERT(!last);
3834 break; 1298 break;
3835 } 1299 }
3836 other->markDoneUnary(min); 1300 (void) other->markWinding(spanStart, winding);
3837 }
3838 return last;
3839 }
3840
3841 bool SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, SkOpS pan** lastPtr) {
3842 int index = angle->start();
3843 int endIndex = angle->end();
3844 return markAndChaseWinding(index, endIndex, winding, lastPtr);
3845 }
3846
3847 bool SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, SkOp Span** lastPtr) {
3848 int min = SkMin32(index, endIndex);
3849 int step = SkSign32(endIndex - index);
3850 bool success = markWinding(min, winding);
3851 SkOpSpan* last = NULL;
3852 SkOpSegment* other = this;
3853 while ((other = other->nextChase(&index, &step, &min, &last))) {
3854 if (other->fTs[min].fWindSum != SK_MinS32) {
3855 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoo p);
3856 SkASSERT(!last);
3857 break;
3858 }
3859 (void) other->markWinding(min, winding);
3860 } 1301 }
3861 if (lastPtr) { 1302 if (lastPtr) {
3862 *lastPtr = last; 1303 *lastPtr = last;
3863 } 1304 }
3864 return success; 1305 return success;
3865 } 1306 }
3866 1307
3867 bool SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding, 1308 bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
3868 SkOpSpan** lastPtr) { 1309 int winding, int oppWinding, SkOpSpanBase** lastPtr) {
3869 int min = SkMin32(index, endIndex); 1310 SkOpSpan* spanStart = start->starter(end);
3870 int step = SkSign32(endIndex - index); 1311 int step = start->step(end);
3871 bool success = markWinding(min, winding, oppWinding); 1312 bool success = markWinding(spanStart, winding, oppWinding);
3872 SkOpSpan* last = NULL; 1313 SkOpSpanBase* last = NULL;
3873 SkOpSegment* other = this; 1314 SkOpSegment* other = this;
3874 while ((other = other->nextChase(&index, &step, &min, &last))) { 1315 while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
3875 if (other->fTs[min].fWindSum != SK_MinS32) { 1316 if (spanStart->windSum() != SK_MinS32) {
3876 #ifdef SK_DEBUG 1317 if (this->operand() == other->operand()) {
3877 if (!other->fTs[min].fLoop) { 1318 SkASSERT(spanStart->windSum() == winding);
3878 if (fOperand == other->fOperand) { 1319 if (spanStart->oppSum() != oppWinding) {
3879 // FIXME: this is probably a bug -- rects4 asserts here 1320 this->globalState()->setWindingFailed();
3880 // SkASSERT(other->fTs[min].fWindSum == winding); 1321 return false;
3881 // FIXME: this is probably a bug -- rects3 asserts here
3882 // SkASSERT(other->fTs[min].fOppSum == oppWinding);
3883 } else {
3884 // FIXME: this is probably a bug -- issue414409b asserts here
3885 // SkASSERT(other->fTs[min].fWindSum == oppWinding);
3886 // FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here
3887 // SkASSERT(other->fTs[min].fOppSum == winding);
3888 } 1322 }
1323 } else {
1324 SkASSERT(spanStart->windSum() == oppWinding);
1325 SkASSERT(spanStart->oppSum() == winding);
3889 } 1326 }
3890 SkASSERT(!last); 1327 SkASSERT(!last);
3891 #endif
3892 break; 1328 break;
3893 } 1329 }
3894 if (fOperand == other->fOperand) { 1330 if (this->operand() == other->operand()) {
3895 (void) other->markWinding(min, winding, oppWinding); 1331 (void) other->markWinding(spanStart, winding, oppWinding);
3896 } else { 1332 } else {
3897 (void) other->markWinding(min, oppWinding, winding); 1333 (void) other->markWinding(spanStart, oppWinding, winding);
3898 } 1334 }
3899 } 1335 }
3900 if (lastPtr) { 1336 if (lastPtr) {
3901 *lastPtr = last; 1337 *lastPtr = last;
3902 } 1338 }
3903 return success; 1339 return success;
3904 } 1340 }
3905 1341
3906 bool SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int o ppWinding, 1342 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpA ngle* angle) {
3907 SkOpSpan** lastPtr) {
3908 int start = angle->start();
3909 int end = angle->end();
3910 return markAndChaseWinding(start, end, winding, oppWinding, lastPtr);
3911 }
3912
3913 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle * angle) {
3914 SkASSERT(angle->segment() == this); 1343 SkASSERT(angle->segment() == this);
3915 if (UseInnerWinding(maxWinding, sumWinding)) { 1344 if (UseInnerWinding(maxWinding, sumWinding)) {
3916 maxWinding = sumWinding; 1345 maxWinding = sumWinding;
3917 } 1346 }
3918 SkOpSpan* last; 1347 SkOpSpanBase* last;
3919 SkAssertResult(markAndChaseWinding(angle, maxWinding, &last)); 1348 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
3920 #if DEBUG_WINDING 1349 #if DEBUG_WINDING
3921 if (last) { 1350 if (last) {
3922 SkDebugf("%s last id=%d windSum=", __FUNCTION__, 1351 SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
3923 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 1352 last->segment()->debugID(), last->debugID());
3924 SkPathOpsDebug::WindingPrintf(last->fWindSum); 1353 if (!last->final()) {
3925 SkDebugf(" small=%d\n", last->fSmall); 1354 SkDebugf(" windSum=");
1355 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1356 }
1357 SkDebugf("\n");
3926 } 1358 }
3927 #endif 1359 #endif
3928 return last; 1360 return last;
3929 } 1361 }
3930 1362
3931 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi ng, 1363 SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxW inding,
3932 int oppSumWinding, const SkOpAngle* angle) { 1364 int oppSumWinding, const SkOpAngle* angle) {
3933 SkASSERT(angle->segment() == this); 1365 SkASSERT(angle->segment() == this);
3934 if (UseInnerWinding(maxWinding, sumWinding)) { 1366 if (UseInnerWinding(maxWinding, sumWinding)) {
3935 maxWinding = sumWinding; 1367 maxWinding = sumWinding;
3936 } 1368 }
3937 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW inding)) { 1369 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW inding)) {
3938 oppMaxWinding = oppSumWinding; 1370 oppMaxWinding = oppSumWinding;
3939 } 1371 }
3940 SkOpSpan* last; 1372 SkOpSpanBase* last = NULL;
3941 // caller doesn't require that this marks anything 1373 // caller doesn't require that this marks anything
3942 (void) markAndChaseWinding(angle, maxWinding, oppMaxWinding, &last); 1374 (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxW inding, &last);
3943 #if DEBUG_WINDING 1375 #if DEBUG_WINDING
3944 if (last) { 1376 if (last) {
3945 SkDebugf("%s last id=%d windSum=", __FUNCTION__, 1377 SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
3946 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 1378 last->segment()->debugID(), last->debugID());
3947 SkPathOpsDebug::WindingPrintf(last->fWindSum); 1379 if (!last->final()) {
3948 SkDebugf(" small=%d\n", last->fSmall); 1380 SkDebugf(" windSum=");
1381 SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1382 }
1383 SkDebugf(" \n");
3949 } 1384 }
3950 #endif 1385 #endif
3951 return last; 1386 return last;
3952 } 1387 }
3953 1388
3954 // FIXME: this should also mark spans with equal (x,y) 1389 void SkOpSegment::markDone(SkOpSpan* span) {
3955 // This may be called when the segment is already marked done. While this 1390 SkASSERT(this == span->segment());
3956 // wastes time, it shouldn't do any more than spin through the T spans. 1391 if (span->done()) {
3957 // OPTIMIZATION: abort on first done found (assuming that this code is 1392 return;
3958 // always called to mark segments done).
3959 void SkOpSegment::markDone(int index, int winding) {
3960 // SkASSERT(!done());
3961 SkASSERT(winding);
3962 double referenceT = fTs[index].fT;
3963 int lesser = index;
3964 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3965 markOneDone(__FUNCTION__, lesser, winding);
3966 } 1393 }
3967 do { 1394 #if DEBUG_MARK_DONE
3968 markOneDone(__FUNCTION__, index, winding); 1395 debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
3969 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen ceT)); 1396 #endif
1397 span->setDone(true);
1398 ++fDoneCount;
3970 debugValidate(); 1399 debugValidate();
3971 } 1400 }
3972 1401
3973 void SkOpSegment::markDoneBinary(int index) { 1402 bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
3974 double referenceT = fTs[index].fT; 1403 SkASSERT(this == span->segment());
3975 int lesser = index; 1404 SkASSERT(winding);
3976 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 1405 if (span->done()) {
3977 markOneDoneBinary(__FUNCTION__, lesser);
3978 }
3979 do {
3980 markOneDoneBinary(__FUNCTION__, index);
3981 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen ceT));
3982 debugValidate();
3983 }
3984
3985 void SkOpSegment::markDoneFinal(int index) {
3986 double referenceT = fTs[index].fT;
3987 int lesser = index;
3988 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
3989 markOneDoneFinal(__FUNCTION__, lesser);
3990 }
3991 do {
3992 markOneDoneFinal(__FUNCTION__, index);
3993 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen ceT));
3994 debugValidate();
3995 }
3996
3997 void SkOpSegment::markDoneUnary(int index) {
3998 double referenceT = fTs[index].fT;
3999 int lesser = index;
4000 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
4001 markOneDoneUnary(__FUNCTION__, lesser);
4002 }
4003 do {
4004 markOneDoneUnary(__FUNCTION__, index);
4005 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen ceT));
4006 debugValidate();
4007 }
4008
4009 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
4010 SkOpSpan* span;
4011 (void) markOneWinding(funName, tIndex, winding, &span); // allowed to do no thing
4012 if (span->fDone) {
4013 return;
4014 }
4015 span->fDone = true;
4016 ++fDoneSpans;
4017 }
4018
4019 void SkOpSegment::markOneDoneFinal(const char* funName, int tIndex) {
4020 SkOpSpan* span = &fTs[tIndex];
4021 if (span->fDone) {
4022 return;
4023 }
4024 span->fDone = true;
4025 ++fDoneSpans;
4026 }
4027
4028 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
4029 SkOpSpan* span = verifyOneWinding(funName, tIndex);
4030 if (!span) {
4031 return;
4032 }
4033 SkASSERT(!span->fDone);
4034 span->fDone = true;
4035 ++fDoneSpans;
4036 }
4037
4038 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
4039 SkOpSpan* span = verifyOneWindingU(funName, tIndex);
4040 if (!span) {
4041 return;
4042 }
4043 if (span->fWindSum == SK_MinS32) {
4044 SkDebugf("%s uncomputed\n", __FUNCTION__);
4045 }
4046 SkASSERT(!span->fDone);
4047 span->fDone = true;
4048 ++fDoneSpans;
4049 }
4050
4051 bool SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding, S kOpSpan** lastPtr) {
4052 SkOpSpan* span = &fTs[tIndex];
4053 if (lastPtr) {
4054 *lastPtr = span;
4055 }
4056 if (span->fDone && !span->fSmall) {
4057 return false; 1406 return false;
4058 } 1407 }
4059 #if DEBUG_MARK_DONE 1408 #if DEBUG_MARK_DONE
4060 debugShowNewWinding(funName, *span, winding); 1409 debugShowNewWinding(__FUNCTION__, span, winding);
4061 #endif 1410 #endif
4062 SkASSERT(span->fWindSum == SK_MinS32 || span->fWindSum == winding); 1411 span->setWindSum(winding);
4063 #if DEBUG_LIMIT_WIND_SUM 1412 debugValidate();
4064 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
4065 #endif
4066 span->fWindSum = winding;
4067 return true; 1413 return true;
4068 } 1414 }
4069 1415
4070 bool SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding, 1416 bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
4071 int oppWinding, SkOpSpan** lastPtr) { 1417 SkASSERT(this == span->segment());
4072 SkOpSpan* span = &fTs[tIndex]; 1418 SkASSERT(winding || oppWinding);
4073 if (span->fDone && !span->fSmall) { 1419 if (span->done()) {
4074 return false; 1420 return false;
4075 } 1421 }
4076 #if DEBUG_MARK_DONE 1422 #if DEBUG_MARK_DONE
4077 debugShowNewWinding(funName, *span, winding, oppWinding); 1423 debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
4078 #endif 1424 #endif
4079 SkASSERT(span->fWindSum == SK_MinS32 || span->fWindSum == winding); 1425 span->setWindSum(winding);
4080 #if DEBUG_LIMIT_WIND_SUM 1426 span->setOppSum(oppWinding);
4081 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
4082 #endif
4083 span->fWindSum = winding;
4084 SkASSERT(span->fOppSum == SK_MinS32 || span->fOppSum == oppWinding);
4085 #if DEBUG_LIMIT_WIND_SUM
4086 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
4087 #endif
4088 span->fOppSum = oppWinding;
4089 debugValidate(); 1427 debugValidate();
4090 if (lastPtr) {
4091 *lastPtr = span;
4092 }
4093 return true; 1428 return true;
4094 } 1429 }
4095 1430
4096 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of -polygon-points-are-in-clockwise-order 1431 bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, doub le testT,
4097 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const { 1432 const SkPoint& testPt) const {
4098 SkASSERT(fVerb != SkPath::kLine_Verb); 1433 const SkOpSegment* baseParent = base->segment();
4099 SkPoint edge[4]; 1434 if (this == baseParent && this == testParent && precisely_equal(base->fT, te stT)) {
4100 subDivide(tStart, tEnd, edge); 1435 return true;
4101 int points = SkPathOpsVerbToPoints(fVerb);
4102 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY) ;
4103 bool sumSet = false;
4104 if (fVerb == SkPath::kCubic_Verb) {
4105 SkDCubic cubic;
4106 cubic.set(edge);
4107 double inflectionTs[2];
4108 int inflections = cubic.findInflections(inflectionTs);
4109 // FIXME: this fixes cubicOp114 and breaks cubicOp58d
4110 // the trouble is that cubics with inflections confuse whether the curve breaks towards
4111 // or away, which in turn is used to determine if it is on the far right or left.
4112 // Probably a totally different approach is in order. At one time I trie d to project a
4113 // horizontal ray to determine winding, but was confused by how to map t he vertically
4114 // oriented winding computation over.
4115 if (0 && inflections) {
4116 double tLo = this->span(tStart).fT;
4117 double tHi = this->span(tEnd).fT;
4118 double tLoStart = tLo;
4119 for (int index = 0; index < inflections; ++index) {
4120 if (between(tLo, inflectionTs[index], tHi)) {
4121 tLo = inflectionTs[index];
4122 }
4123 }
4124 if (tLo != tLoStart && tLo != tHi) {
4125 SkDPoint sub[2];
4126 sub[0] = cubic.ptAtT(tLo);
4127 sub[1].set(edge[3]);
4128 SkDPoint ctrl[2];
4129 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl);
4130 edge[0] = sub[0].asSkPoint();
4131 edge[1] = ctrl[0].asSkPoint();
4132 edge[2] = ctrl[1].asSkPoint();
4133 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY);
4134 }
4135 }
4136 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
4137 if (edge[1].fY < lesser && edge[2].fY < lesser) {
4138 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1] .fY} }};
4139 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3] .fY} }};
4140 if (SkIntersections::Test(tangent1, tangent2)) {
4141 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
4142 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
4143 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
4144 sumSet = true;
4145 }
4146 }
4147 } 1436 }
4148 if (!sumSet) { 1437 if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
4149 for (int idx = 0; idx < points; ++idx){ 1438 return false;
4150 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[ idx].fY);
4151 }
4152 } 1439 }
4153 if (fVerb == SkPath::kCubic_Verb) { 1440 return !ptsDisjoint(base->fT, base->fPt, testT, testPt);
4154 SkDCubic cubic;
4155 cubic.set(edge);
4156 *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine();
4157 } else {
4158 SkDQuad quad;
4159 quad.set(edge);
4160 *swap = sum > 0 && !quad.monotonicInY();
4161 }
4162 return sum <= 0;
4163 } 1441 }
4164 1442
4165 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { 1443 static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
4166 SkASSERT(fVerb != SkPath::kLine_Verb); 1444 if (last) {
4167 if (fVerb == SkPath::kQuad_Verb) { 1445 *last = endSpan;
4168 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
4169 return dst.monotonicInY();
4170 }
4171 SkASSERT(fVerb == SkPath::kCubic_Verb);
4172 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
4173 return dst.monotonicInY();
4174 }
4175
4176 bool SkOpSegment::serpentine(int tStart, int tEnd) const {
4177 if (fVerb != SkPath::kCubic_Verb) {
4178 return false;
4179 }
4180 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
4181 return dst.serpentine();
4182 }
4183
4184 SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
4185 SkOpSpan& span = fTs[tIndex];
4186 if (span.fDone) {
4187 return NULL;
4188 }
4189 #if DEBUG_MARK_DONE
4190 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
4191 #endif
4192 // If the prior angle in the sort is unorderable, the winding sum may not be com putable.
4193 // To enable the assert, the 'prior is unorderable' state could be
4194 // piped down to this test, but not sure it's worth it.
4195 // (Once the sort order is stored in the span, this test may be feasible.)
4196 // SkASSERT(span.fWindSum != SK_MinS32);
4197 // SkASSERT(span.fOppSum != SK_MinS32);
4198 return &span;
4199 }
4200
4201 SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
4202 SkOpSpan& span = fTs[tIndex];
4203 if (span.fDone) {
4204 return NULL;
4205 }
4206 #if DEBUG_MARK_DONE
4207 debugShowNewWinding(funName, span, span.fWindSum);
4208 #endif
4209 // If the prior angle in the sort is unorderable, the winding sum may not be com putable.
4210 // To enable the assert, the 'prior is unorderable' state could be
4211 // piped down to this test, but not sure it's worth it.
4212 // (Once the sort order is stored in the span, this test may be feasible.)
4213 // SkASSERT(span.fWindSum != SK_MinS32);
4214 return &span;
4215 }
4216
4217 bool SkOpSegment::markWinding(int index, int winding) {
4218 // SkASSERT(!done());
4219 SkASSERT(winding);
4220 double referenceT = fTs[index].fT;
4221 int lesser = index;
4222 bool success = false;
4223 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
4224 success |= markOneWinding(__FUNCTION__, lesser, winding, NULL);
4225 }
4226 do {
4227 success |= markOneWinding(__FUNCTION__, index, winding, NULL);
4228 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc eT));
4229 debugValidate();
4230 return success;
4231 }
4232
4233 bool SkOpSegment::markWinding(int index, int winding, int oppWinding) {
4234 // SkASSERT(!done());
4235 SkASSERT(winding || oppWinding);
4236 double referenceT = fTs[index].fT;
4237 int lesser = index;
4238 bool success = false;
4239 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
4240 success |= markOneWinding(__FUNCTION__, lesser, winding, oppWinding, NUL L);
4241 }
4242 do {
4243 success |= markOneWinding(__FUNCTION__, index, winding, oppWinding, NULL );
4244 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc eT));
4245 debugValidate();
4246 return success;
4247 }
4248
4249 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
4250 int nextDoorWind = SK_MaxS32;
4251 int nextOppWind = SK_MaxS32;
4252 // prefer exact matches
4253 if (tIndex > 0) {
4254 const SkOpSpan& below = fTs[tIndex - 1];
4255 if (below.fT == t) {
4256 nextDoorWind = below.fWindValue;
4257 nextOppWind = below.fOppValue;
4258 }
4259 }
4260 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
4261 const SkOpSpan& above = fTs[tIndex + 1];
4262 if (above.fT == t) {
4263 nextDoorWind = above.fWindValue;
4264 nextOppWind = above.fOppValue;
4265 }
4266 }
4267 if (nextDoorWind == SK_MaxS32 && tIndex > 0) {
4268 const SkOpSpan& below = fTs[tIndex - 1];
4269 if (approximately_negative(t - below.fT)) {
4270 nextDoorWind = below.fWindValue;
4271 nextOppWind = below.fOppValue;
4272 }
4273 }
4274 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
4275 const SkOpSpan& above = fTs[tIndex + 1];
4276 if (approximately_negative(above.fT - t)) {
4277 nextDoorWind = above.fWindValue;
4278 nextOppWind = above.fOppValue;
4279 }
4280 }
4281 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
4282 const SkOpSpan& below = fTs[tIndex - 1];
4283 nextDoorWind = below.fWindValue;
4284 nextOppWind = below.fOppValue;
4285 }
4286 if (nextDoorWind != SK_MaxS32) {
4287 SkOpSpan& newSpan = fTs[tIndex];
4288 newSpan.fWindValue = nextDoorWind;
4289 newSpan.fOppValue = nextOppWind;
4290 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
4291 newSpan.fDone = true;
4292 ++fDoneSpans;
4293 }
4294 }
4295 }
4296
4297 bool SkOpSegment::nextCandidate(int* start, int* end) const {
4298 while (fTs[*end].fDone) {
4299 if (fTs[*end].fT == 1) {
4300 return false;
4301 }
4302 ++(*end);
4303 }
4304 *start = *end;
4305 *end = nextExactSpan(*start, 1);
4306 return true;
4307 }
4308
4309 static SkOpSegment* set_last(SkOpSpan** last, const SkOpSpan* endSpan) {
4310 if (last && !endSpan->fSmall) {
4311 *last = const_cast<SkOpSpan*>(endSpan); // FIXME: get rid of cast
4312 } 1446 }
4313 return NULL; 1447 return NULL;
4314 } 1448 }
4315 1449
4316 SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, 1450 bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en d) const {
4317 SkOpSpan** last) const { 1451 SkASSERT(fVerb != SkPath::kLine_Verb);
4318 int origIndex = *indexPtr; 1452 if (fVerb == SkPath::kQuad_Verb) {
1453 SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t());
1454 return dst.monotonicInY();
1455 }
1456 SkASSERT(fVerb == SkPath::kCubic_Verb);
1457 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
1458 return dst.monotonicInY();
1459 }
1460
1461 bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start,
1462 SkOpSpanBase** end) {
1463 while (span->final() || span->upCast()->done()) {
1464 if (span->final()) {
1465 return false;
1466 }
1467 span = span->upCast()->next();
1468 }
1469 *start = span;
1470 *end = span->upCast()->next();
1471 return true;
1472 }
1473
1474 SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS pan** minPtr,
1475 SkOpSpanBase** last) const {
1476 SkOpSpanBase* origStart = *startPtr;
4319 int step = *stepPtr; 1477 int step = *stepPtr;
4320 int end = nextExactSpan(origIndex, step); 1478 SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart-> prev();
4321 SkASSERT(end >= 0); 1479 SkASSERT(endSpan);
4322 const SkOpSpan& endSpan = this->span(end); 1480 SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAn gle();
4323 SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle; 1481 SkOpSpanBase* foundSpan;
4324 int foundIndex; 1482 SkOpSpanBase* otherEnd;
4325 int otherEnd;
4326 SkOpSegment* other; 1483 SkOpSegment* other;
4327 if (angle == NULL) { 1484 if (angle == NULL) {
4328 if (endSpan.fT != 0 && endSpan.fT != 1) { 1485 if (endSpan->t() != 0 && endSpan->t() != 1) {
4329 return NULL; 1486 return NULL;
4330 } 1487 }
4331 other = endSpan.fOther; 1488 SkOpPtT* otherPtT = endSpan->ptT()->next();
4332 foundIndex = endSpan.fOtherIndex; 1489 other = otherPtT->segment();
4333 otherEnd = other->nextExactSpan(foundIndex, step); 1490 foundSpan = otherPtT->span();
1491 otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
4334 } else { 1492 } else {
4335 int loopCount = angle->loopCount(); 1493 int loopCount = angle->loopCount();
4336 if (loopCount > 2) { 1494 if (loopCount > 2) {
4337 return set_last(last, &endSpan); 1495 return set_last(last, endSpan);
4338 } 1496 }
4339 const SkOpAngle* next = angle->next(); 1497 const SkOpAngle* next = angle->next();
4340 if (NULL == next) { 1498 if (NULL == next) {
4341 return NULL; 1499 return NULL;
4342 } 1500 }
4343 if (angle->sign() != next->sign()) {
4344 #if DEBUG_WINDING 1501 #if DEBUG_WINDING
1502 if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor ()
1503 && !next->segment()->contour()->isXor()) {
4345 SkDebugf("%s mismatched signs\n", __FUNCTION__); 1504 SkDebugf("%s mismatched signs\n", __FUNCTION__);
1505 }
4346 #endif 1506 #endif
4347 // return set_last(last, &endSpan);
4348 }
4349 other = next->segment(); 1507 other = next->segment();
4350 foundIndex = end = next->start(); 1508 foundSpan = endSpan = next->start();
4351 otherEnd = next->end(); 1509 otherEnd = next->end();
4352 } 1510 }
4353 int foundStep = foundIndex < otherEnd ? 1 : -1; 1511 int foundStep = foundSpan->step(otherEnd);
4354 if (*stepPtr != foundStep) { 1512 if (*stepPtr != foundStep) {
4355 return set_last(last, &endSpan); 1513 return set_last(last, endSpan);
4356 } 1514 }
4357 SkASSERT(*indexPtr >= 0); 1515 SkASSERT(*startPtr);
4358 if (otherEnd < 0) { 1516 if (!otherEnd) {
4359 return NULL; 1517 return NULL;
4360 } 1518 }
4361 // SkASSERT(otherEnd >= 0); 1519 // SkASSERT(otherEnd >= 0);
4362 #if 1 1520 SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
4363 int origMin = origIndex + (step < 0 ? step : 0); 1521 SkOpSpan* foundMin = foundSpan->starter(otherEnd);
4364 const SkOpSpan& orig = this->span(origMin); 1522 if (foundMin->windValue() != origMin->windValue()
4365 #endif 1523 || foundMin->oppValue() != origMin->oppValue()) {
4366 int foundMin = SkMin32(foundIndex, otherEnd); 1524 return set_last(last, endSpan);
4367 #if 1
4368 const SkOpSpan& found = other->span(foundMin);
4369 if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue ) {
4370 return set_last(last, &endSpan);
4371 } 1525 }
4372 #endif 1526 *startPtr = foundSpan;
4373 *indexPtr = foundIndex;
4374 *stepPtr = foundStep; 1527 *stepPtr = foundStep;
4375 if (minPtr) { 1528 if (minPtr) {
4376 *minPtr = foundMin; 1529 *minPtr = foundMin;
4377 } 1530 }
4378 return other; 1531 return other;
4379 } 1532 }
4380 1533
4381 // This has callers for two different situations: one establishes the end 1534 static void clear_visited(SkOpSpan* span) {
4382 // of the current span, and one establishes the beginning of the next span 1535 // reset visited flag back to false
4383 // (thus the name). When this is looking for the end of the current span, 1536 do {
4384 // coincidence is found when the beginning Ts contain -step and the end 1537 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
4385 // contains step. When it is looking for the beginning of the next, the 1538 while ((ptT = ptT->next()) != stopPtT) {
4386 // first Ts found can be ignored and the last Ts should contain -step. 1539 SkOpSegment* opp = ptT->segment();
4387 // OPTIMIZATION: probably should split into two functions 1540 opp->resetVisited();
4388 int SkOpSegment::nextSpan(int from, int step) const {
4389 const SkOpSpan& fromSpan = fTs[from];
4390 int count = fTs.count();
4391 int to = from;
4392 while (step > 0 ? ++to < count : --to >= 0) {
4393 const SkOpSpan& span = fTs[to];
4394 if (approximately_zero(span.fT - fromSpan.fT)) {
4395 continue;
4396 } 1541 }
4397 return to; 1542 } while ((span = span->next()->upCastable()));
1543 }
1544
1545 // look for pairs of undetected coincident curves
1546 // assumes that segments going in have visited flag clear
1547 // curve/curve intersection should now do a pretty good job of finding coinciden t runs so
1548 // this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
1549 // the opp is not a line
1550 void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc * allocator) {
1551 if (this->verb() != SkPath::kLine_Verb) {
1552 return;
4398 } 1553 }
4399 return -1; 1554 SkOpSpan* prior = NULL;
4400 } 1555 SkOpSpan* span = &fHead;
4401 1556 do {
4402 // FIXME 1557 SkOpPtT* ptT = span->ptT(), * spanStopPtT = ptT;
4403 // this returns at any difference in T, vs. a preset minimum. It may be 1558 SkASSERT(ptT->span() == span);
4404 // that all callers to nextSpan should use this instead. 1559 while ((ptT = ptT->next()) != spanStopPtT) {
4405 int SkOpSegment::nextExactSpan(int from, int step) const { 1560 SkOpSegment* opp = ptT->span()->segment();
4406 int to = from; 1561 if (opp->setVisited()) {
4407 if (step < 0) { 1562 continue;
4408 const SkOpSpan& fromSpan = fTs[from]; 1563 }
4409 while (--to >= 0) { 1564 if (opp->verb() == SkPath::kLine_Verb) {
4410 const SkOpSpan& span = fTs[to]; 1565 continue;
4411 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) { 1566 }
4412 continue; 1567 if (span->containsCoincidence(opp)) { // FIXME: this assumes that if the opposite
4413 } 1568 // segment is coincident then no more coincidence
4414 return to; 1569 // needs to be detected. This may not be true.
1570 continue;
1571 }
1572 if (span->containsCoinEnd(opp)) {
1573 continue;
1574 }
1575 // if already visited and visited again, check for coin
1576 if (span == &fHead) {
1577 continue;
1578 }
1579 SkOpPtT* priorPtT = NULL, * priorStopPtT;
1580 // find prior span containing opp segment
1581 SkOpSegment* priorOpp = NULL;
1582 prior = span;
1583 while (!priorOpp && (prior = prior->prev())) {
1584 priorStopPtT = priorPtT = prior->ptT();
1585 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1586 SkOpSegment* segment = priorPtT->span()->segment();
1587 if (segment == opp) {
1588 priorOpp = opp;
1589 break;
1590 }
1591 }
1592 }
1593 if (!priorOpp) {
1594 continue;
1595 }
1596 SkOpPtT* oppStart = prior->ptT();
1597 SkOpPtT* oppEnd = span->ptT();
1598 bool swapped = priorPtT->fT > ptT->fT;
1599 if (swapped) {
1600 SkTSwap(priorPtT, ptT);
1601 SkTSwap(oppStart, oppEnd);
1602 }
1603 bool flipped = oppStart->fT > oppEnd->fT;
1604 bool coincident;
1605 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped) ) {
1606 goto swapBack;
1607 }
1608 {
1609 // average t, find mid pt
1610 double midT = (prior->t() + span->t()) / 2;
1611 SkPoint midPt = this->ptAtT(midT);
1612 coincident = true;
1613 // if the mid pt is not near either end pt, project perpendicula r through opp seg
1614 if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1615 && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1616 coincident = false;
1617 SkIntersections i;
1618 int ptCount = SkPathOpsVerbToPoints(this->verb());
1619 SkVector dxdy = (*CurveSlopeAtT[ptCount])(pts(), midT);
1620 SkDLine ray = {{{midPt.fX, midPt.fY},
1621 {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
1622 int oppPtCount = SkPathOpsVerbToPoints(opp->verb());
1623 (*CurveIntersectRay[oppPtCount])(opp->pts(), ray, &i);
1624 // measure distance and see if it's small enough to denote c oincidence
1625 for (int index = 0; index < i.used(); ++index) {
1626 SkDPoint oppPt = i.pt(index);
1627 if (oppPt.approximatelyEqual(midPt)) {
1628 SkVector oppDxdy = (*CurveSlopeAtT[oppPtCount])(opp- >pts(),
1629 i[index][0]);
1630 oppDxdy.normalize();
1631 dxdy.normalize();
1632 SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1633 coincident |= flatness < 5000; // FIXME: replace wi th tuned value
1634 }
1635 }
1636 }
1637 }
1638 if (coincident) {
1639 // mark coincidence
1640 coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
1641 clear_visited(&fHead);
1642 missingCoincidence(coincidences, allocator);
1643 return;
1644 }
1645 swapBack:
1646 if (swapped) {
1647 SkTSwap(priorPtT, ptT);
1648 }
4415 } 1649 }
4416 } else { 1650 } while ((span = span->next()->upCastable()));
4417 while (fTs[from].fTiny) { 1651 clear_visited(&fHead);
4418 from++; 1652 }
1653
1654 // Move nearby t values and pts so they all hang off the same span. Alignment ha ppens later.
1655 bool SkOpSegment::moveNearby() {
1656 debugValidate();
1657 SkOpSpanBase* spanS = &fHead;
1658 do {
1659 SkOpSpanBase* test = spanS->upCast()->next();
1660 SkOpSpanBase* next;
1661 if (spanS->contains(test)) {
1662 if (!test->final()) {
1663 test->upCast()->detach(spanS->ptT());
1664 continue;
1665 } else if (spanS != &fHead) {
1666 spanS->upCast()->detach(test->ptT());
1667 spanS = test;
1668 continue;
1669 }
4419 } 1670 }
4420 const SkOpSpan& fromSpan = fTs[from]; 1671 do { // iterate through all spans associated with start
4421 int count = fTs.count(); 1672 SkOpPtT* startBase = spanS->ptT();
4422 while (++to < count) { 1673 next = test->final() ? NULL : test->upCast()->next();
4423 const SkOpSpan& span = fTs[to]; 1674 do {
4424 if (precisely_negative(span.fT - fromSpan.fT)) { 1675 SkOpPtT* testBase = test->ptT();
4425 continue; 1676 do {
4426 } 1677 if (startBase == testBase) {
4427 return to; 1678 goto checkNextSpan;
4428 } 1679 }
1680 if (testBase->duplicate()) {
1681 continue;
1682 }
1683 if (this->match(startBase, testBase->segment(), testBase->fT , testBase->fPt)) {
1684 if (test == &this->fTail) {
1685 if (spanS == &fHead) {
1686 debugValidate();
1687 return true; // if this span has collapsed, rem ove it from parent
1688 }
1689 this->fTail.merge(spanS->upCast());
1690 debugValidate();
1691 return true;
1692 }
1693 spanS->merge(test->upCast());
1694 spanS->upCast()->setNext(next);
1695 goto checkNextSpan;
1696 }
1697 } while ((testBase = testBase->next()) != test->ptT());
1698 } while ((startBase = startBase->next()) != spanS->ptT());
1699 checkNextSpan:
1700 ;
1701 } while ((test = next));
1702 spanS = spanS->upCast()->next();
1703 } while (!spanS->final());
1704 debugValidate();
1705 return true;
1706 }
1707
1708 bool SkOpSegment::operand() const {
1709 return fContour->operand();
1710 }
1711
1712 bool SkOpSegment::oppXor() const {
1713 return fContour->oppXor();
1714 }
1715
1716 bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const Sk Point& pt2) const {
1717 if (fVerb == SkPath::kLine_Verb) {
1718 return false;
4429 } 1719 }
4430 return -1; 1720 // quads (and cubics) can loop back to nearly a line so that an opposite cur ve
4431 } 1721 // hits in two places with very different t values.
4432 1722 // OPTIMIZATION: curves could be preflighted so that, for example, something like
4433 void SkOpSegment::pinT(const SkPoint& pt, double* t) { 1723 // 'controls contained by ends' could avoid this check for common curves
4434 if (pt == fPts[0]) { 1724 // 'ends are extremes in x or y' is cheaper to compute and real-world common
4435 *t = 0; 1725 // on the other hand, the below check is relatively inexpensive
4436 } 1726 double midT = (t1 + t2) / 2;
4437 int count = SkPathOpsVerbToPoints(fVerb); 1727 SkPoint midPt = this->ptAtT(midT);
4438 if (pt == fPts[count]) { 1728 double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
4439 *t = 1; 1729 return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seD istSq;
4440 } 1730 }
4441 } 1731
4442 1732 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum MiWinding,
4443 bool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const { 1733 int* maxWinding, int* sumWinding) {
4444 SkASSERT(p1 != p2); 1734 int deltaSum = SpanSign(start, end);
4445 int spanCount = count(); 1735 *maxWinding = *sumMiWinding;
4446 int p1IndexMin = -1; 1736 *sumWinding = *sumMiWinding -= deltaSum;
4447 int p2IndexMax = spanCount; 1737 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
4448 for (int index = 0; index < spanCount; ++index) { 1738 }
4449 const SkOpSpan& span = fTs[index]; 1739
4450 if (span.fPt == p1) { 1740 void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sum MiWinding,
4451 if (p1IndexMin < 0) { 1741 int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
4452 p1IndexMin = index; 1742 int* oppSumWinding) {
4453 } 1743 int deltaSum = SpanSign(start, end);
4454 } else if (span.fPt == p2) { 1744 int oppDeltaSum = OppSign(start, end);
4455 p2IndexMax = index;
4456 }
4457 }
4458 return p1IndexMin > p2IndexMax;
4459 }
4460
4461 void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endP t,
4462 SkOpSegment* other) {
4463 int count = this->count();
4464 for (int index = 0; index < count; ++index) {
4465 SkOpSpan &span = fTs[index];
4466 if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) {
4467 span.fCoincident = true;
4468 }
4469 }
4470 }
4471
4472 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
4473 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding ) {
4474 int deltaSum = spanSign(index, endIndex);
4475 int oppDeltaSum = oppSign(index, endIndex);
4476 if (operand()) { 1745 if (operand()) {
4477 *maxWinding = *sumSuWinding; 1746 *maxWinding = *sumSuWinding;
4478 *sumWinding = *sumSuWinding -= deltaSum; 1747 *sumWinding = *sumSuWinding -= deltaSum;
4479 *oppMaxWinding = *sumMiWinding; 1748 *oppMaxWinding = *sumMiWinding;
4480 *oppSumWinding = *sumMiWinding -= oppDeltaSum; 1749 *oppSumWinding = *sumMiWinding -= oppDeltaSum;
4481 } else { 1750 } else {
4482 *maxWinding = *sumMiWinding; 1751 *maxWinding = *sumMiWinding;
4483 *sumWinding = *sumMiWinding -= deltaSum; 1752 *sumWinding = *sumMiWinding -= deltaSum;
4484 *oppMaxWinding = *sumSuWinding; 1753 *oppMaxWinding = *sumSuWinding;
4485 *oppSumWinding = *sumSuWinding -= oppDeltaSum; 1754 *oppSumWinding = *sumSuWinding -= oppDeltaSum;
4486 } 1755 }
4487 #if DEBUG_LIMIT_WIND_SUM 1756 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
4488 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 1757 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SU M);
4489 SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
4490 #endif
4491 }
4492
4493 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
4494 int* maxWinding, int* sumWinding) {
4495 int deltaSum = spanSign(index, endIndex);
4496 *maxWinding = *sumMiWinding;
4497 *sumWinding = *sumMiWinding -= deltaSum;
4498 #if DEBUG_LIMIT_WIND_SUM
4499 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
4500 #endif
4501 } 1758 }
4502 1759
4503 void SkOpSegment::sortAngles() { 1760 void SkOpSegment::sortAngles() {
4504 int spanCount = fTs.count(); 1761 SkOpSpanBase* span = &this->fHead;
4505 if (spanCount <= 2) {
4506 return;
4507 }
4508 int index = 0;
4509 do { 1762 do {
4510 SkOpAngle* fromAngle = fTs[index].fFromAngle; 1763 SkOpAngle* fromAngle = span->fromAngle();
4511 SkOpAngle* toAngle = fTs[index].fToAngle; 1764 SkOpAngle* toAngle = span->final() ? NULL : span->upCast()->toAngle();
4512 if (!fromAngle && !toAngle) { 1765 if (!fromAngle && !toAngle) {
4513 index += 1;
4514 continue; 1766 continue;
4515 } 1767 }
4516 SkOpAngle* baseAngle = NULL;
4517 if (fromAngle) {
4518 baseAngle = fromAngle;
4519 if (inLoop(baseAngle, spanCount, &index)) {
4520 continue;
4521 }
4522 }
4523 #if DEBUG_ANGLE 1768 #if DEBUG_ANGLE
4524 bool wroteAfterHeader = false; 1769 bool wroteAfterHeader = false;
4525 #endif 1770 #endif
4526 if (toAngle) { 1771 SkOpAngle* baseAngle = fromAngle;
4527 if (!baseAngle) { 1772 if (fromAngle && toAngle) {
4528 baseAngle = toAngle;
4529 if (inLoop(baseAngle, spanCount, &index)) {
4530 continue;
4531 }
4532 } else {
4533 SkDEBUGCODE(int newIndex = index);
4534 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index);
4535 #if DEBUG_ANGLE 1773 #if DEBUG_ANGLE
4536 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT, 1774 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), spa n->t(),
4537 index); 1775 span->debugID());
4538 wroteAfterHeader = true; 1776 wroteAfterHeader = true;
4539 #endif 1777 #endif
4540 baseAngle->insert(toAngle); 1778 fromAngle->insert(toAngle);
1779 } else if (!fromAngle) {
1780 baseAngle = toAngle;
1781 }
1782 SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1783 do {
1784 SkOpSpanBase* oSpan = ptT->span();
1785 if (oSpan == span) {
1786 continue;
4541 } 1787 }
4542 } 1788 SkOpAngle* oAngle = oSpan->fromAngle();
4543 SkOpAngle* nextFrom, * nextTo;
4544 int firstIndex = index;
4545 do {
4546 SkOpSpan& span = fTs[index];
4547 SkOpSegment* other = span.fOther;
4548 SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
4549 SkOpAngle* oAngle = oSpan.fFromAngle;
4550 if (oAngle) { 1789 if (oAngle) {
4551 #if DEBUG_ANGLE 1790 #if DEBUG_ANGLE
4552 if (!wroteAfterHeader) { 1791 if (!wroteAfterHeader) {
4553 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI D(), fTs[index].fT, 1792 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI D(),
4554 index); 1793 span->t(), span->debugID());
4555 wroteAfterHeader = true; 1794 wroteAfterHeader = true;
4556 } 1795 }
4557 #endif 1796 #endif
4558 if (!oAngle->loopContains(*baseAngle)) { 1797 if (!oAngle->loopContains(baseAngle)) {
4559 baseAngle->insert(oAngle); 1798 baseAngle->insert(oAngle);
4560 } 1799 }
4561 } 1800 }
4562 oAngle = oSpan.fToAngle; 1801 if (!oSpan->final()) {
4563 if (oAngle) { 1802 oAngle = oSpan->upCast()->toAngle();
1803 if (oAngle) {
4564 #if DEBUG_ANGLE 1804 #if DEBUG_ANGLE
4565 if (!wroteAfterHeader) { 1805 if (!wroteAfterHeader) {
4566 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI D(), fTs[index].fT, 1806 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, de bugID(),
4567 index); 1807 span->t(), span->debugID());
4568 wroteAfterHeader = true; 1808 wroteAfterHeader = true;
4569 } 1809 }
4570 #endif 1810 #endif
4571 if (!oAngle->loopContains(*baseAngle)) { 1811 if (!oAngle->loopContains(baseAngle)) {
4572 baseAngle->insert(oAngle); 1812 baseAngle->insert(oAngle);
1813 }
4573 } 1814 }
4574 } 1815 }
4575 if (++index == spanCount) { 1816 } while ((ptT = ptT->next()) != stopPtT);
4576 break; 1817 if (baseAngle->loopCount() == 1) {
1818 span->setFromAngle(NULL);
1819 if (toAngle) {
1820 span->upCast()->setToAngle(NULL);
4577 } 1821 }
4578 nextFrom = fTs[index].fFromAngle;
4579 nextTo = fTs[index].fToAngle;
4580 } while (fromAngle == nextFrom && toAngle == nextTo);
4581 if (baseAngle && baseAngle->loopCount() == 1) {
4582 index = firstIndex;
4583 do {
4584 SkOpSpan& span = fTs[index];
4585 span.fFromAngle = span.fToAngle = NULL;
4586 if (++index == spanCount) {
4587 break;
4588 }
4589 nextFrom = fTs[index].fFromAngle;
4590 nextTo = fTs[index].fToAngle;
4591 } while (fromAngle == nextFrom && toAngle == nextTo);
4592 baseAngle = NULL; 1822 baseAngle = NULL;
4593 } 1823 }
4594 #if DEBUG_SORT 1824 #if DEBUG_SORT
4595 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); 1825 SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
4596 #endif 1826 #endif
4597 } while (index < spanCount); 1827 } while (!span->final() && (span = span->upCast()->next()));
4598 } 1828 }
4599 1829
4600 // return true if midpoints were computed 1830 // return true if midpoints were computed
4601 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { 1831 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
1832 SkPoint edge[4]) const {
4602 SkASSERT(start != end); 1833 SkASSERT(start != end);
4603 edge[0] = fTs[start].fPt; 1834 const SkOpPtT& startPtT = *start->ptT();
1835 const SkOpPtT& endPtT = *end->ptT();
1836 edge[0] = startPtT.fPt;
4604 int points = SkPathOpsVerbToPoints(fVerb); 1837 int points = SkPathOpsVerbToPoints(fVerb);
4605 edge[points] = fTs[end].fPt; 1838 edge[points] = endPtT.fPt;
4606 if (fVerb == SkPath::kLine_Verb) { 1839 if (fVerb == SkPath::kLine_Verb) {
4607 return false; 1840 return false;
4608 } 1841 }
4609 double startT = fTs[start].fT; 1842 double startT = startPtT.fT;
4610 double endT = fTs[end].fT; 1843 double endT = endPtT.fT;
4611 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 1844 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4612 // don't compute midpoints if we already have them 1845 // don't compute midpoints if we already have them
4613 if (fVerb == SkPath::kQuad_Verb) { 1846 if (fVerb == SkPath::kQuad_Verb) {
4614 edge[1] = fPts[1]; 1847 edge[1] = fPts[1];
4615 return false; 1848 return false;
4616 } 1849 }
4617 SkASSERT(fVerb == SkPath::kCubic_Verb); 1850 SkASSERT(fVerb == SkPath::kCubic_Verb);
4618 if (start < end) { 1851 if (start < end) {
4619 edge[1] = fPts[1]; 1852 edge[1] = fPts[1];
4620 edge[2] = fPts[2]; 1853 edge[2] = fPts[2];
4621 return false; 1854 return false;
4622 } 1855 }
4623 edge[1] = fPts[2]; 1856 edge[1] = fPts[2];
4624 edge[2] = fPts[1]; 1857 edge[2] = fPts[1];
4625 return false; 1858 return false;
4626 } 1859 }
4627 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p oints].fY }}; 1860 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[p oints].fY }};
4628 if (fVerb == SkPath::kQuad_Verb) { 1861 if (fVerb == SkPath::kQuad_Verb) {
4629 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi nt(); 1862 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoi nt();
4630 } else { 1863 } else {
4631 SkASSERT(fVerb == SkPath::kCubic_Verb); 1864 SkASSERT(fVerb == SkPath::kCubic_Verb);
4632 SkDPoint ctrl[2]; 1865 SkDPoint ctrl[2];
4633 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); 1866 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
4634 edge[1] = ctrl[0].asSkPoint(); 1867 edge[1] = ctrl[0].asSkPoint();
4635 edge[2] = ctrl[1].asSkPoint(); 1868 edge[2] = ctrl[1].asSkPoint();
4636 } 1869 }
4637 return true; 1870 return true;
4638 } 1871 }
4639 1872
4640 // return true if midpoints were computed 1873 bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
4641 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const { 1874 SkDCubic* result) const {
4642 SkASSERT(start != end); 1875 SkASSERT(start != end);
4643 (*result)[0].set(fTs[start].fPt); 1876 const SkOpPtT& startPtT = *start->ptT();
1877 const SkOpPtT& endPtT = *end->ptT();
1878 (*result)[0].set(startPtT.fPt);
4644 int points = SkPathOpsVerbToPoints(fVerb); 1879 int points = SkPathOpsVerbToPoints(fVerb);
4645 (*result)[points].set(fTs[end].fPt); 1880 (*result)[points].set(endPtT.fPt);
4646 if (fVerb == SkPath::kLine_Verb) { 1881 if (fVerb == SkPath::kLine_Verb) {
4647 return false; 1882 return false;
4648 } 1883 }
4649 double startT = fTs[start].fT; 1884 double startT = startPtT.fT;
4650 double endT = fTs[end].fT; 1885 double endT = endPtT.fT;
4651 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 1886 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4652 // don't compute midpoints if we already have them 1887 // don't compute midpoints if we already have them
4653 if (fVerb == SkPath::kQuad_Verb) { 1888 if (fVerb == SkPath::kQuad_Verb) {
4654 (*result)[1].set(fPts[1]); 1889 (*result)[1].set(fPts[1]);
4655 return false; 1890 return false;
4656 } 1891 }
4657 SkASSERT(fVerb == SkPath::kCubic_Verb); 1892 SkASSERT(fVerb == SkPath::kCubic_Verb);
4658 if (start < end) { 1893 if (startT == 0) {
4659 (*result)[1].set(fPts[1]); 1894 (*result)[1].set(fPts[1]);
4660 (*result)[2].set(fPts[2]); 1895 (*result)[2].set(fPts[2]);
4661 return false; 1896 return false;
4662 } 1897 }
4663 (*result)[1].set(fPts[2]); 1898 (*result)[1].set(fPts[2]);
4664 (*result)[2].set(fPts[1]); 1899 (*result)[2].set(fPts[1]);
4665 return false; 1900 return false;
4666 } 1901 }
4667 if (fVerb == SkPath::kQuad_Verb) { 1902 if (fVerb == SkPath::kQuad_Verb) {
4668 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star tT, endT); 1903 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], star tT, endT);
4669 } else { 1904 } else {
4670 SkASSERT(fVerb == SkPath::kCubic_Verb); 1905 SkASSERT(fVerb == SkPath::kCubic_Verb);
4671 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r esult)[1]); 1906 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*r esult)[1]);
4672 } 1907 }
4673 return true; 1908 return true;
4674 } 1909 }
4675 1910
4676 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c onst { 1911 void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
1912 SkPathOpsBounds* bounds) const {
4677 SkPoint edge[4]; 1913 SkPoint edge[4];
4678 subDivide(start, end, edge); 1914 subDivide(start, end, edge);
4679 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); 1915 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
4680 } 1916 }
4681 1917
4682 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const Sk Point& endPt, 1918 void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
4683 const SkPoint& startPt) { 1919 SkOpSpan* span = this->head();
4684 int outCount = outsidePts->count(); 1920 do {
4685 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) { 1921 if (!span->done()) {
4686 outsidePts->push_back(endPt); 1922 break;
4687 outsidePts->push_back(startPt); 1923 }
4688 } 1924 } while ((span = span->next()->upCastable()));
1925 SkASSERT(span);
1926 *start = span;
1927 *end = span->next();
4689 } 1928 }
4690 1929
4691 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin t& startPt) { 1930 int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
4692 int outCount = outsidePts->count(); 1931 const SkOpSpan* lesser = start->starter(end);
4693 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { 1932 int oppWinding = lesser->oppSum();
4694 outsidePts->push_back(startPt); 1933 int oppSpanWinding = SkOpSegment::OppSign(start, end);
4695 }
4696 }
4697
4698 void SkOpSegment::undoneSpan(int* start, int* end) {
4699 int tCount = fTs.count();
4700 int index;
4701 for (index = 0; index < tCount; ++index) {
4702 if (!fTs[index].fDone) {
4703 break;
4704 }
4705 }
4706 SkASSERT(index < tCount - 1);
4707 *start = index;
4708 double startT = fTs[index].fT;
4709 while (approximately_negative(fTs[++index].fT - startT))
4710 SkASSERT(index < tCount);
4711 SkASSERT(index < tCount);
4712 *end = index;
4713 }
4714
4715 int SkOpSegment::updateOppWinding(int index, int endIndex) const {
4716 int lesser = SkMin32(index, endIndex);
4717 int oppWinding = oppSum(lesser);
4718 int oppSpanWinding = oppSign(index, endIndex);
4719 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWindin g) 1934 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWindin g)
4720 && oppWinding != SK_MaxS32) { 1935 && oppWinding != SK_MaxS32) {
4721 oppWinding -= oppSpanWinding; 1936 oppWinding -= oppSpanWinding;
4722 } 1937 }
4723 return oppWinding; 1938 return oppWinding;
4724 } 1939 }
4725 1940
4726 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { 1941 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
4727 int startIndex = angle->start(); 1942 const SkOpSpanBase* startSpan = angle->start();
4728 int endIndex = angle->end(); 1943 const SkOpSpanBase* endSpan = angle->end();
4729 return updateOppWinding(endIndex, startIndex); 1944 return updateOppWinding(endSpan, startSpan);
4730 } 1945 }
4731 1946
4732 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { 1947 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
4733 int startIndex = angle->start(); 1948 const SkOpSpanBase* startSpan = angle->start();
4734 int endIndex = angle->end(); 1949 const SkOpSpanBase* endSpan = angle->end();
4735 return updateOppWinding(startIndex, endIndex); 1950 return updateOppWinding(startSpan, endSpan);
4736 } 1951 }
4737 1952
4738 int SkOpSegment::updateWinding(int index, int endIndex) const { 1953 int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* en d) const {
4739 int lesser = SkMin32(index, endIndex); 1954 const SkOpSpan* lesser = start->starter(end);
4740 int winding = windSum(lesser); 1955 int winding = lesser->windSum();
4741 if (winding == SK_MinS32) { 1956 if (winding == SK_MinS32) {
4742 return winding; 1957 return winding;
4743 } 1958 }
4744 int spanWinding = spanSign(index, endIndex); 1959 int spanWinding = SkOpSegment::SpanSign(start, end);
4745 if (winding && UseInnerWinding(winding - spanWinding, winding) 1960 if (winding && UseInnerWinding(winding - spanWinding, winding)
4746 && winding != SK_MaxS32) { 1961 && winding != SK_MaxS32) {
4747 winding -= spanWinding; 1962 winding -= spanWinding;
4748 } 1963 }
4749 return winding; 1964 return winding;
4750 } 1965 }
4751 1966
4752 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { 1967 int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
4753 int startIndex = angle->start(); 1968 const SkOpSpanBase* startSpan = angle->start();
4754 int endIndex = angle->end(); 1969 const SkOpSpanBase* endSpan = angle->end();
4755 return updateWinding(endIndex, startIndex); 1970 return updateWinding(endSpan, startSpan);
4756 }
4757
4758 int SkOpSegment::updateWindingReverse(int index, int endIndex) const {
4759 int lesser = SkMin32(index, endIndex);
4760 int winding = windSum(lesser);
4761 int spanWinding = spanSign(endIndex, index);
4762 if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
4763 && winding != SK_MaxS32) {
4764 winding -= spanWinding;
4765 }
4766 return winding;
4767 } 1971 }
4768 1972
4769 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { 1973 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
4770 int startIndex = angle->start(); 1974 const SkOpSpanBase* startSpan = angle->start();
4771 int endIndex = angle->end(); 1975 const SkOpSpanBase* endSpan = angle->end();
4772 return updateWindingReverse(endIndex, startIndex); 1976 return updateWinding(startSpan, endSpan);
4773 } 1977 }
4774 1978
4775 // OPTIMIZATION: does the following also work, and is it any faster? 1979 // OPTIMIZATION: does the following also work, and is it any faster?
4776 // return outerWinding * innerWinding > 0 1980 // return outerWinding * innerWinding > 0
4777 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 1981 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
4778 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { 1982 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
4779 SkASSERT(outerWinding != SK_MaxS32); 1983 SkASSERT(outerWinding != SK_MaxS32);
4780 SkASSERT(innerWinding != SK_MaxS32); 1984 SkASSERT(innerWinding != SK_MaxS32);
4781 int absOut = abs(outerWinding); 1985 int absOut = abs(outerWinding);
4782 int absIn = abs(innerWinding); 1986 int absIn = abs(innerWinding);
4783 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1987 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
4784 return result; 1988 return result;
4785 } 1989 }
4786 1990
4787 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) { 1991 int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp,
4788 SkASSERT(outerWinding != SK_MaxS32); 1992 SkScalar* dx) const {
4789 SkASSERT(innerWinding != SK_MaxS32); 1993 if (approximately_zero(tHit - span->t())) { // if we hit the end of a span, disregard
4790 int absOut = abs(outerWinding);
4791 int absIn = abs(innerWinding);
4792 bool result = absOut == absIn ? true : absOut < absIn;
4793 return result;
4794 }
4795
4796 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx ) const {
4797 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
4798 return SK_MinS32; 1994 return SK_MinS32;
4799 } 1995 }
4800 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); 1996 int winding = crossOpp ? span->oppSum() : span->windSum();
4801 SkASSERT(winding != SK_MinS32); 1997 SkASSERT(winding != SK_MinS32);
4802 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); 1998 int windVal = crossOpp ? span->oppValue() : span->windValue();
4803 #if DEBUG_WINDING_AT_T 1999 #if DEBUG_WINDING_AT_T
4804 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __ FUNCTION__, 2000 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __ FUNCTION__,
4805 debugID(), crossOpp, tHit, t(tIndex), winding, windVal); 2001 debugID(), crossOpp, tHit, span->t(), winding, windVal);
4806 #endif 2002 #endif
4807 // see if a + change in T results in a +/- change in X (compute x'(T)) 2003 // see if a + change in T results in a +/- change in X (compute x'(T))
4808 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; 2004 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
4809 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { 2005 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
4810 *dx = fPts[2].fX - fPts[1].fX - *dx; 2006 *dx = fPts[2].fX - fPts[1].fX - *dx;
4811 } 2007 }
4812 if (*dx == 0) { 2008 if (*dx == 0) {
4813 #if DEBUG_WINDING_AT_T 2009 #if DEBUG_WINDING_AT_T
4814 SkDebugf(" dx=0 winding=SK_MinS32\n"); 2010 SkDebugf(" dx=0 winding=SK_MinS32\n");
4815 #endif 2011 #endif
4816 return SK_MinS32; 2012 return SK_MinS32;
4817 } 2013 }
4818 if (windVal < 0) { // reverse sign if opp contour traveled in reverse 2014 if (windVal < 0) { // reverse sign if opp contour traveled in reverse
4819 *dx = -*dx; 2015 *dx = -*dx;
4820 } 2016 }
4821 if (winding * *dx > 0) { // if same signs, result is negative 2017 if (winding * *dx > 0) { // if same signs, result is negative
4822 winding += *dx > 0 ? -windVal : windVal; 2018 winding += *dx > 0 ? -windVal : windVal;
4823 } 2019 }
4824 #if DEBUG_WINDING_AT_T 2020 #if DEBUG_WINDING_AT_T
4825 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); 2021 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
4826 #endif 2022 #endif
4827 return winding; 2023 return winding;
4828 } 2024 }
4829 2025
4830 int SkOpSegment::windSum(const SkOpAngle* angle) const { 2026 int SkOpSegment::windSum(const SkOpAngle* angle) const {
4831 int start = angle->start(); 2027 const SkOpSpan* minSpan = angle->start()->starter(angle->end());
4832 int end = angle->end(); 2028 return minSpan->windSum();
4833 int index = SkMin32(start, end);
4834 return windSum(index);
4835 } 2029 }
4836
4837 void SkOpSegment::zeroSpan(SkOpSpan* span) {
4838 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
4839 span->fWindValue = 0;
4840 span->fOppValue = 0;
4841 if (span->fTiny || span->fSmall) {
4842 return;
4843 }
4844 SkASSERT(!span->fDone);
4845 span->fDone = true;
4846 ++fDoneSpans;
4847 }
OLDNEW
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698