OLD | NEW |
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 "SkIntersections.h" |
8 #include "SkOpSegment.h" | 8 #include "SkOpSegment.h" |
9 #include "SkPathWriter.h" | 9 #include "SkPathWriter.h" |
10 #include "SkTSort.h" | 10 #include "SkTSort.h" |
11 | 11 |
12 #define F (false) // discard the edge | 12 #define F (false) // discard the edge |
13 #define T (true) // keep the edge | 13 #define T (true) // keep the edge |
14 | 14 |
15 static const bool gUnaryActiveEdge[2][2] = { | 15 static const bool gUnaryActiveEdge[2][2] = { |
16 // from=0 from=1 | 16 // from=0 from=1 |
17 // to=0,1 to=0,1 | 17 // to=0,1 to=0,1 |
18 {F, T}, {T, F}, | 18 {F, T}, {T, F}, |
19 }; | 19 }; |
20 | 20 |
21 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { | 21 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { |
22 // miFrom=0 miFrom=1 | 22 // miFrom=0 miFrom=1 |
23 // miTo=0 miTo=1 miTo=0 miTo=1 | 23 // miTo=0 miTo=1 miTo=0 miTo=1 |
24 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 | 24 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 |
25 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 | 25 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 |
26 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}
, // mi - su | 26 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}
, // mi - su |
27 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}
, // mi & su | 27 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}
, // mi & su |
28 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}
, // mi | su | 28 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}
, // mi | su |
29 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}
, // mi ^ su | 29 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}
, // mi ^ su |
30 }; | 30 }; |
31 | 31 |
32 #undef F | 32 #undef F |
33 #undef T | 33 #undef T |
34 | 34 |
35 enum { | 35 enum { |
36 kOutsideTrackedTCount = 16, // FIXME: determine what this should be | 36 kOutsideTrackedTCount = 16, // FIXME: determine what this should be |
37 kMissingSpanCount = 4, // FIXME: determine what this should be | 37 kMissingSpanCount = 4, // FIXME: determine what this should be |
38 }; | 38 }; |
39 | 39 |
40 // note that this follows the same logic flow as build angles | 40 const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool*
done, |
41 bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* a
ngles) { | 41 bool* sortable) const { |
42 if (activeAngleInner(index, done, angles)) { | 42 if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sort
able)) { |
43 return true; | 43 return result; |
44 } | 44 } |
45 double referenceT = fTs[index].fT; | 45 double referenceT = fTs[index].fT; |
46 int lesser = index; | 46 int lesser = index; |
47 while (--lesser >= 0 | 47 while (--lesser >= 0 |
48 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { | 48 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { |
49 if (activeAngleOther(lesser, done, angles)) { | 49 if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done,
sortable)) { |
50 return true; | 50 return result; |
51 } | 51 } |
52 } | 52 } |
53 do { | 53 do { |
54 if (activeAngleOther(index, done, angles)) { | 54 if (const SkOpAngle* result = activeAngleOther(index, start, end, done,
sortable)) { |
55 return true; | 55 return result; |
56 } | 56 } |
57 if (++index == fTs.count()) { | 57 if (++index == fTs.count()) { |
58 break; | 58 break; |
59 } | 59 } |
60 if (fTs[index - 1].fTiny) { | 60 if (fTs[index - 1].fTiny) { |
61 referenceT = fTs[index].fT; | 61 referenceT = fTs[index].fT; |
62 continue; | 62 continue; |
63 } | 63 } |
64 } while (precisely_negative(fTs[index].fT - referenceT)); | 64 } while (precisely_negative(fTs[index].fT - referenceT)); |
65 return false; | 65 return NULL; |
66 } | 66 } |
67 | 67 |
68 bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, tru
e>* angles) { | 68 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end,
bool* done, |
69 SkOpSpan* span = &fTs[index]; | 69 bool* sortable) const { |
70 SkOpSegment* other = span->fOther; | |
71 int oIndex = span->fOtherIndex; | |
72 return other->activeAngleInner(oIndex, done, angles); | |
73 } | |
74 | |
75 bool SkOpSegment::activeAngleInner(int index, int* done, SkTArray<SkOpAngle, tru
e>* angles) { | |
76 int next = nextExactSpan(index, 1); | 70 int next = nextExactSpan(index, 1); |
77 if (next > 0) { | 71 if (next > 0) { |
78 SkOpSpan& upSpan = fTs[index]; | 72 const SkOpSpan& upSpan = fTs[index]; |
| 73 if (upSpan.fUnsortableStart) { |
| 74 *sortable = false; |
| 75 return NULL; |
| 76 } |
79 if (upSpan.fWindValue || upSpan.fOppValue) { | 77 if (upSpan.fWindValue || upSpan.fOppValue) { |
80 addAngle(angles, index, next); | 78 if (*end < 0) { |
81 if (upSpan.fDone || upSpan.fUnsortableEnd) { | 79 *start = index; |
82 (*done)++; | 80 *end = next; |
83 } else if (upSpan.fWindSum != SK_MinS32) { | |
84 return true; | |
85 } | 81 } |
86 } else if (!upSpan.fDone) { | 82 if (!upSpan.fDone && !upSpan.fUnsortableEnd) { |
87 upSpan.fDone = true; | 83 if (upSpan.fWindSum != SK_MinS32) { |
88 fDoneSpans++; | 84 return spanToAngle(index, next); |
| 85 } |
| 86 *done = false; |
| 87 } |
| 88 } else { |
| 89 SkASSERT(upSpan.fDone); |
89 } | 90 } |
90 } | 91 } |
91 int prev = nextExactSpan(index, -1); | 92 int prev = nextExactSpan(index, -1); |
92 // edge leading into junction | 93 // edge leading into junction |
93 if (prev >= 0) { | 94 if (prev >= 0) { |
94 SkOpSpan& downSpan = fTs[prev]; | 95 const SkOpSpan& downSpan = fTs[prev]; |
| 96 if (downSpan.fUnsortableEnd) { |
| 97 *sortable = false; |
| 98 return NULL; |
| 99 } |
95 if (downSpan.fWindValue || downSpan.fOppValue) { | 100 if (downSpan.fWindValue || downSpan.fOppValue) { |
96 addAngle(angles, index, prev); | 101 if (*end < 0) { |
97 if (downSpan.fDone) { | 102 *start = index; |
98 (*done)++; | 103 *end = prev; |
99 } else if (downSpan.fWindSum != SK_MinS32) { | |
100 return true; | |
101 } | 104 } |
102 } else if (!downSpan.fDone) { | 105 if (!downSpan.fDone) { |
103 downSpan.fDone = true; | 106 if (downSpan.fWindSum != SK_MinS32) { |
104 fDoneSpans++; | 107 return spanToAngle(index, prev); |
| 108 } |
| 109 *done = false; |
| 110 } |
| 111 } else { |
| 112 SkASSERT(downSpan.fDone); |
105 } | 113 } |
106 } | 114 } |
107 return false; | 115 return NULL; |
| 116 } |
| 117 |
| 118 const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end,
bool* done, |
| 119 bool* sortable) const { |
| 120 const SkOpSpan* span = &fTs[index]; |
| 121 SkOpSegment* other = span->fOther; |
| 122 int oIndex = span->fOtherIndex; |
| 123 return other->activeAngleInner(oIndex, start, end, done, sortable); |
108 } | 124 } |
109 | 125 |
110 SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const { | 126 SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const { |
111 SkASSERT(!done()); | 127 SkASSERT(!done()); |
112 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; | 128 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; |
113 int count = fTs.count(); | 129 int count = fTs.count(); |
114 // see if either end is not done since we want smaller Y of the pair | 130 // see if either end is not done since we want smaller Y of the pair |
115 bool lastDone = true; | 131 bool lastDone = true; |
116 bool lastUnsortable = false; | 132 bool lastUnsortable = false; |
117 double lastT = -1; | 133 double lastT = -1; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 } | 168 } |
153 return topPt; | 169 return topPt; |
154 } | 170 } |
155 | 171 |
156 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask
, SkPathOp op) { | 172 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask
, SkPathOp op) { |
157 int sumMiWinding = updateWinding(endIndex, index); | 173 int sumMiWinding = updateWinding(endIndex, index); |
158 int sumSuWinding = updateOppWinding(endIndex, index); | 174 int sumSuWinding = updateOppWinding(endIndex, index); |
159 if (fOperand) { | 175 if (fOperand) { |
160 SkTSwap<int>(sumMiWinding, sumSuWinding); | 176 SkTSwap<int>(sumMiWinding, sumSuWinding); |
161 } | 177 } |
162 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | 178 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &s
umSuWinding); |
163 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &s
umSuWinding, | |
164 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | |
165 } | 179 } |
166 | 180 |
167 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex
, SkPathOp op, | 181 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex
, SkPathOp op, |
168 int* sumMiWinding, int* sumSuWinding, | 182 int* sumMiWinding, int* sumSuWinding) { |
169 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding
) { | 183 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; |
170 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, | 184 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, |
171 maxWinding, sumWinding, oppMaxWinding, oppSumWinding); | 185 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
172 bool miFrom; | 186 bool miFrom; |
173 bool miTo; | 187 bool miTo; |
174 bool suFrom; | 188 bool suFrom; |
175 bool suTo; | 189 bool suTo; |
176 if (operand()) { | 190 if (operand()) { |
177 miFrom = (*oppMaxWinding & xorMiMask) != 0; | 191 miFrom = (oppMaxWinding & xorMiMask) != 0; |
178 miTo = (*oppSumWinding & xorMiMask) != 0; | 192 miTo = (oppSumWinding & xorMiMask) != 0; |
179 suFrom = (*maxWinding & xorSuMask) != 0; | 193 suFrom = (maxWinding & xorSuMask) != 0; |
180 suTo = (*sumWinding & xorSuMask) != 0; | 194 suTo = (sumWinding & xorSuMask) != 0; |
181 } else { | 195 } else { |
182 miFrom = (*maxWinding & xorMiMask) != 0; | 196 miFrom = (maxWinding & xorMiMask) != 0; |
183 miTo = (*sumWinding & xorMiMask) != 0; | 197 miTo = (sumWinding & xorMiMask) != 0; |
184 suFrom = (*oppMaxWinding & xorSuMask) != 0; | 198 suFrom = (oppMaxWinding & xorSuMask) != 0; |
185 suTo = (*oppSumWinding & xorSuMask) != 0; | 199 suTo = (oppSumWinding & xorSuMask) != 0; |
186 } | 200 } |
187 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; | 201 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; |
188 #if DEBUG_ACTIVE_OP | 202 #if DEBUG_ACTIVE_OP |
189 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCT
ION__, | 203 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCT
ION__, |
190 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); | 204 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); |
191 #endif | 205 #endif |
192 return result; | 206 return result; |
193 } | 207 } |
194 | 208 |
195 bool SkOpSegment::activeWinding(int index, int endIndex) { | 209 bool SkOpSegment::activeWinding(int index, int endIndex) { |
196 int sumWinding = updateWinding(endIndex, index); | 210 int sumWinding = updateWinding(endIndex, index); |
197 int maxWinding; | 211 return activeWinding(index, endIndex, &sumWinding); |
198 return activeWinding(index, endIndex, &maxWinding, &sumWinding); | |
199 } | 212 } |
200 | 213 |
201 bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* s
umWinding) { | 214 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) { |
202 setUpWinding(index, endIndex, maxWinding, sumWinding); | 215 int maxWinding; |
203 bool from = *maxWinding != 0; | 216 setUpWinding(index, endIndex, &maxWinding, sumWinding); |
| 217 bool from = maxWinding != 0; |
204 bool to = *sumWinding != 0; | 218 bool to = *sumWinding != 0; |
205 bool result = gUnaryActiveEdge[from][to]; | 219 bool result = gUnaryActiveEdge[from][to]; |
206 return result; | 220 return result; |
207 } | 221 } |
208 | 222 |
209 void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int
end) const { | |
210 SkASSERT(start != end); | |
211 SkOpAngle& angle = anglesPtr->push_back(); | |
212 angle.set(this, start, end); | |
213 } | |
214 | |
215 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt
, | 223 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt
, |
216 SkOpSegment* other) { | 224 SkOpSegment* other) { |
217 int tIndex = -1; | 225 int tIndex = -1; |
218 int tCount = fTs.count(); | 226 int tCount = fTs.count(); |
219 int oIndex = -1; | 227 int oIndex = -1; |
220 int oCount = other->fTs.count(); | 228 int oCount = other->fTs.count(); |
221 do { | 229 do { |
222 ++tIndex; | 230 ++tIndex; |
223 } while (startPt != fTs[tIndex].fPt && tIndex < tCount); | 231 } while (startPt != fTs[tIndex].fPt && tIndex < tCount); |
224 int tIndexStart = tIndex; | 232 int tIndexStart = tIndex; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, | 300 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, |
293 SkOpSegment* other) { | 301 SkOpSegment* other) { |
294 // walk this to startPt | 302 // walk this to startPt |
295 // walk other to startPt | 303 // walk other to startPt |
296 // if either is > 0, add a pointer to the other, copying adjacent winding | 304 // if either is > 0, add a pointer to the other, copying adjacent winding |
297 int tIndex = -1; | 305 int tIndex = -1; |
298 int oIndex = -1; | 306 int oIndex = -1; |
299 do { | 307 do { |
300 ++tIndex; | 308 ++tIndex; |
301 } while (startPt != fTs[tIndex].fPt); | 309 } while (startPt != fTs[tIndex].fPt); |
| 310 int ttIndex = tIndex; |
| 311 bool checkOtherTMatch = false; |
| 312 do { |
| 313 const SkOpSpan& span = fTs[ttIndex]; |
| 314 if (startPt != span.fPt) { |
| 315 break; |
| 316 } |
| 317 if (span.fOther == other && span.fPt == startPt) { |
| 318 checkOtherTMatch = true; |
| 319 break; |
| 320 } |
| 321 } while (++ttIndex < count()); |
302 do { | 322 do { |
303 ++oIndex; | 323 ++oIndex; |
304 } while (startPt != other->fTs[oIndex].fPt); | 324 } while (startPt != other->fTs[oIndex].fPt); |
305 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) { | 325 bool skipAdd = false; |
| 326 if (checkOtherTMatch) { |
| 327 int ooIndex = oIndex; |
| 328 do { |
| 329 const SkOpSpan& oSpan = other->fTs[ooIndex]; |
| 330 if (startPt != oSpan.fPt) { |
| 331 break; |
| 332 } |
| 333 if (oSpan.fT == fTs[ttIndex].fOtherT) { |
| 334 skipAdd = true; |
| 335 break; |
| 336 } |
| 337 } while (++ooIndex < other->count()); |
| 338 } |
| 339 if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) { |
306 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt); | 340 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt); |
307 } | 341 } |
308 SkPoint nextPt = startPt; | 342 SkPoint nextPt = startPt; |
309 do { | 343 do { |
310 const SkPoint* workPt; | 344 const SkPoint* workPt; |
311 do { | 345 do { |
312 workPt = &fTs[++tIndex].fPt; | 346 workPt = &fTs[++tIndex].fPt; |
313 } while (nextPt == *workPt); | 347 } while (nextPt == *workPt); |
314 do { | 348 do { |
315 workPt = &other->fTs[++oIndex].fPt; | 349 workPt = &other->fTs[++oIndex].fPt; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); | 405 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); |
372 break; | 406 break; |
373 default: | 407 default: |
374 SkASSERT(0); | 408 SkASSERT(0); |
375 } | 409 } |
376 } | 410 } |
377 } | 411 } |
378 // return ePtr[SkPathOpsVerbToPoints(fVerb)]; | 412 // return ePtr[SkPathOpsVerbToPoints(fVerb)]; |
379 } | 413 } |
380 | 414 |
| 415 void SkOpSegment::addEndSpan(int endIndex) { |
| 416 int spanCount = fTs.count(); |
| 417 int angleIndex = fAngles.count(); |
| 418 int startIndex = endIndex - 1; |
| 419 while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) { |
| 420 ++startIndex; |
| 421 SkASSERT(startIndex < spanCount - 1); |
| 422 ++endIndex; |
| 423 } |
| 424 fAngles.push_back().set(this, spanCount - 1, startIndex); |
| 425 #if DEBUG_ANGLE |
| 426 fAngles.back().setID(angleIndex); |
| 427 debugCheckPointsEqualish(endIndex, spanCount); |
| 428 #endif |
| 429 setFromAngleIndex(endIndex, angleIndex); |
| 430 } |
| 431 |
| 432 void SkOpSegment::setFromAngleIndex(int endIndex, int angleIndex) { |
| 433 int spanCount = fTs.count(); |
| 434 do { |
| 435 fTs[endIndex].fFromAngleIndex = angleIndex; |
| 436 } while (++endIndex < spanCount); |
| 437 } |
| 438 |
381 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { | 439 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { |
382 init(pts, SkPath::kLine_Verb, operand, evenOdd); | 440 init(pts, SkPath::kLine_Verb, operand, evenOdd); |
383 fBounds.set(pts, 2); | 441 fBounds.set(pts, 2); |
384 } | 442 } |
385 | 443 |
386 // add 2 to edge or out of range values to get T extremes | 444 // add 2 to edge or out of range values to get T extremes |
387 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) { | 445 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) { |
388 SkOpSpan& span = fTs[index]; | 446 SkOpSpan& span = fTs[index]; |
389 if (precisely_zero(otherT)) { | 447 if (precisely_zero(otherT)) { |
390 otherT = 0; | 448 otherT = 0; |
391 } else if (precisely_equal(otherT, 1)) { | 449 } else if (precisely_equal(otherT, 1)) { |
392 otherT = 1; | 450 otherT = 1; |
393 } | 451 } |
394 span.fOtherT = otherT; | 452 span.fOtherT = otherT; |
395 span.fOtherIndex = otherIndex; | 453 span.fOtherIndex = otherIndex; |
396 } | 454 } |
397 | 455 |
398 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { | 456 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { |
399 init(pts, SkPath::kQuad_Verb, operand, evenOdd); | 457 init(pts, SkPath::kQuad_Verb, operand, evenOdd); |
400 fBounds.setQuadBounds(pts); | 458 fBounds.setQuadBounds(pts); |
401 } | 459 } |
402 | 460 |
| 461 int SkOpSegment::addSingletonAngleDown(int endIndex, SkOpSegment** otherPtr) { |
| 462 int startIndex = findEndSpan(endIndex); |
| 463 SkASSERT(startIndex > 0); |
| 464 int spanIndex = endIndex - 1; |
| 465 fSingletonAngles.push_back().set(this, spanIndex, startIndex - 1); |
| 466 setFromAngleIndex(startIndex, fAngles.count() + fSingletonAngles.count() - 1
); |
| 467 SkOpSegment* other; |
| 468 do { |
| 469 other = fTs[spanIndex].fOther; |
| 470 if (other->fTs[0].fWindValue) { |
| 471 break; |
| 472 } |
| 473 --spanIndex; |
| 474 SkASSERT(fTs[spanIndex].fT == 1); |
| 475 } while (true); |
| 476 int oEndIndex = other->findStartSpan(0); |
| 477 SkASSERT(oEndIndex > 0); |
| 478 int otherIndex = other->fSingletonAngles.count(); |
| 479 other->fSingletonAngles.push_back().set(other, 0, oEndIndex); |
| 480 other->setToAngleIndex(oEndIndex, other->fAngles.count() + otherIndex); |
| 481 *otherPtr = other; |
| 482 return otherIndex; |
| 483 } |
| 484 |
| 485 int SkOpSegment::addSingletonAngleUp(int start, SkOpSegment** otherPtr) { |
| 486 int endIndex = findStartSpan(start); |
| 487 SkASSERT(endIndex > 0); |
| 488 int thisIndex = fSingletonAngles.count(); |
| 489 fSingletonAngles.push_back().set(this, start, endIndex); |
| 490 setToAngleIndex(endIndex, fAngles.count() + thisIndex); |
| 491 int spanIndex = start; |
| 492 SkOpSegment* other; |
| 493 int oCount, oStartIndex; |
| 494 do { |
| 495 other = fTs[spanIndex].fOther; |
| 496 oCount = other->count(); |
| 497 oStartIndex = other->findEndSpan(oCount); |
| 498 SkASSERT(oStartIndex > 0); |
| 499 if (other->fTs[oStartIndex - 1].fWindValue) { |
| 500 break; |
| 501 } |
| 502 ++spanIndex; |
| 503 SkASSERT(fTs[spanIndex].fT == 0); |
| 504 } while (true); |
| 505 int otherIndex = other->fSingletonAngles.count(); |
| 506 other->fSingletonAngles.push_back().set(other, oCount - 1, oStartIndex - 1); |
| 507 other->setFromAngleIndex(oStartIndex, other->fAngles.count() + otherIndex); |
| 508 *otherPtr = other; |
| 509 return otherIndex; |
| 510 } |
| 511 |
| 512 SkOpAngle* SkOpSegment::addSingletonAngles(int start, int step) { |
| 513 int thisIndex = fSingletonAngles.count(); |
| 514 SkOpSegment* other; |
| 515 int otherIndex; |
| 516 if (step > 0) { |
| 517 otherIndex = addSingletonAngleUp(start, &other); |
| 518 } else { |
| 519 otherIndex = addSingletonAngleDown(start + 1, &other); |
| 520 } |
| 521 fSingletonAngles[thisIndex].insert(&other->fSingletonAngles[otherIndex]); |
| 522 #if DEBUG_ANGLE |
| 523 fSingletonAngles[thisIndex].setID(fAngles.count() + thisIndex); |
| 524 other->fSingletonAngles[otherIndex].setID(other->fAngles.count() + otherInde
x); |
| 525 #endif |
| 526 return &fSingletonAngles[thisIndex]; |
| 527 } |
| 528 |
| 529 void SkOpSegment::addStartSpan(int endIndex) { |
| 530 int angleIndex = fAngles.count(); |
| 531 int index = 0; |
| 532 fAngles.push_back().set(this, index, endIndex); |
| 533 #if DEBUG_ANGLE |
| 534 fAngles.back().setID(angleIndex); |
| 535 debugCheckPointsEqualish(index, endIndex); |
| 536 #endif |
| 537 setToAngleIndex(endIndex, angleIndex); |
| 538 } |
| 539 |
| 540 void SkOpSegment::setToAngleIndex(int endIndex, int angleIndex) { |
| 541 int index = 0; |
| 542 do { |
| 543 fTs[index].fToAngleIndex = angleIndex; |
| 544 } while (++index < endIndex); |
| 545 } |
| 546 |
403 // Defer all coincident edge processing until | 547 // Defer all coincident edge processing until |
404 // after normal intersections have been computed | 548 // after normal intersections have been computed |
405 | 549 |
406 // no need to be tricky; insert in normal T order | 550 // no need to be tricky; insert in normal T order |
407 // resolve overlapping ts when considering coincidence later | 551 // resolve overlapping ts when considering coincidence later |
408 | 552 |
409 // add non-coincident intersection. Resulting edges are sorted in T. | 553 // add non-coincident intersection. Resulting edges are sorted in T. |
410 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { | 554 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { |
| 555 SkASSERT(this != other || fVerb == SkPath::kCubic_Verb); |
| 556 #if 0 // this needs an even rougher association to be useful |
| 557 SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt)); |
| 558 #endif |
411 if (precisely_zero(newT)) { | 559 if (precisely_zero(newT)) { |
412 newT = 0; | 560 newT = 0; |
413 } else if (precisely_equal(newT, 1)) { | 561 } else if (precisely_equal(newT, 1)) { |
414 newT = 1; | 562 newT = 1; |
415 } | 563 } |
416 // FIXME: in the pathological case where there is a ton of intercepts, | 564 // FIXME: in the pathological case where there is a ton of intercepts, |
417 // binary search? | 565 // binary search? |
418 int insertedAt = -1; | 566 int insertedAt = -1; |
419 size_t tCount = fTs.count(); | 567 int tCount = fTs.count(); |
420 const SkPoint& firstPt = fPts[0]; | 568 const SkPoint& firstPt = fPts[0]; |
421 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; | 569 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; |
422 for (size_t index = 0; index < tCount; ++index) { | 570 for (int index = 0; index < tCount; ++index) { |
423 // OPTIMIZATION: if there are three or more identical Ts, then | 571 // OPTIMIZATION: if there are three or more identical Ts, then |
424 // the fourth and following could be further insertion-sorted so | 572 // the fourth and following could be further insertion-sorted so |
425 // that all the edges are clockwise or counterclockwise. | 573 // that all the edges are clockwise or counterclockwise. |
426 // This could later limit segment tests to the two adjacent | 574 // This could later limit segment tests to the two adjacent |
427 // neighbors, although it doesn't help with determining which | 575 // neighbors, although it doesn't help with determining which |
428 // circular direction to go in. | 576 // circular direction to go in. |
429 const SkOpSpan& span = fTs[index]; | 577 const SkOpSpan& span = fTs[index]; |
430 if (newT < span.fT) { | 578 if (newT < span.fT) { |
431 insertedAt = index; | 579 insertedAt = index; |
432 break; | 580 break; |
(...skipping 17 matching lines...) Expand all Loading... |
450 span = fTs.append(); | 598 span = fTs.append(); |
451 } | 599 } |
452 span->fT = newT; | 600 span->fT = newT; |
453 span->fOther = other; | 601 span->fOther = other; |
454 span->fPt = pt; | 602 span->fPt = pt; |
455 #if 0 | 603 #if 0 |
456 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) | 604 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) |
457 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) | 605 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) |
458 && approximately_equal(xyAtT(newT).fY, pt.fY)); | 606 && approximately_equal(xyAtT(newT).fY, pt.fY)); |
459 #endif | 607 #endif |
| 608 span->fFromAngleIndex = -1; |
| 609 span->fToAngleIndex = -1; |
460 span->fWindSum = SK_MinS32; | 610 span->fWindSum = SK_MinS32; |
461 span->fOppSum = SK_MinS32; | 611 span->fOppSum = SK_MinS32; |
462 span->fWindValue = 1; | 612 span->fWindValue = 1; |
463 span->fOppValue = 0; | 613 span->fOppValue = 0; |
464 span->fSmall = false; | 614 span->fChased = false; |
465 span->fTiny = false; | |
466 span->fLoop = false; | |
467 if ((span->fDone = newT == 1)) { | 615 if ((span->fDone = newT == 1)) { |
468 ++fDoneSpans; | 616 ++fDoneSpans; |
469 } | 617 } |
| 618 span->fLoop = false; |
| 619 span->fSmall = false; |
| 620 span->fTiny = false; |
470 span->fUnsortableStart = false; | 621 span->fUnsortableStart = false; |
471 span->fUnsortableEnd = false; | 622 span->fUnsortableEnd = false; |
472 int less = -1; | 623 int less = -1; |
473 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt,
span->fPt)) { | 624 // find range of spans with nearly the same point as this one |
474 if (span[less].fDone) { | 625 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt,
pt)) { |
475 break; | |
476 } | |
477 double tInterval = newT - span[less].fT; | |
478 if (precisely_negative(tInterval)) { | |
479 break; | |
480 } | |
481 if (fVerb == SkPath::kCubic_Verb) { | 626 if (fVerb == SkPath::kCubic_Verb) { |
| 627 double tInterval = newT - span[less].fT; |
482 double tMid = newT - tInterval / 2; | 628 double tMid = newT - tInterval / 2; |
483 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); | 629 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); |
484 if (!midPt.approximatelyEqual(xyAtT(span))) { | 630 if (!midPt.approximatelyEqual(xyAtT(span))) { |
485 break; | 631 break; |
486 } | 632 } |
487 } | 633 } |
488 span[less].fSmall = true; | |
489 bool tiny = span[less].fPt == span->fPt; | |
490 span[less].fTiny = tiny; | |
491 span[less].fDone = true; | |
492 if (approximately_negative(newT - span[less].fT) && tiny) { | |
493 if (approximately_greater_than_one(newT)) { | |
494 SkASSERT(&span[less] - fTs.begin() < fTs.count()); | |
495 span[less].fUnsortableStart = true; | |
496 if (&span[less - 1] - fTs.begin() >= 0) { | |
497 span[less - 1].fUnsortableEnd = true; | |
498 } | |
499 } | |
500 if (approximately_less_than_zero(span[less].fT)) { | |
501 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count()); | |
502 SkASSERT(&span[less] - fTs.begin() >= 0); | |
503 span[less + 1].fUnsortableStart = true; | |
504 span[less].fUnsortableEnd = true; | |
505 } | |
506 } | |
507 ++fDoneSpans; | |
508 --less; | 634 --less; |
509 } | 635 } |
510 int more = 1; | 636 int more = 1; |
511 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, sp
an->fPt)) { | 637 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt
)) { |
512 if (span[more - 1].fDone) { | |
513 break; | |
514 } | |
515 double tEndInterval = span[more].fT - newT; | |
516 if (precisely_negative(tEndInterval)) { | |
517 if ((span->fTiny = span[more].fTiny)) { | |
518 span->fDone = true; | |
519 ++fDoneSpans; | |
520 } | |
521 break; | |
522 } | |
523 if (fVerb == SkPath::kCubic_Verb) { | 638 if (fVerb == SkPath::kCubic_Verb) { |
| 639 double tEndInterval = span[more].fT - newT; |
524 double tMid = newT - tEndInterval / 2; | 640 double tMid = newT - tEndInterval / 2; |
525 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); | 641 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); |
526 if (!midEndPt.approximatelyEqual(xyAtT(span))) { | 642 if (!midEndPt.approximatelyEqual(xyAtT(span))) { |
527 break; | 643 break; |
528 } | 644 } |
529 } | 645 } |
530 span[more - 1].fSmall = true; | |
531 bool tiny = span[more].fPt == span->fPt; | |
532 span[more - 1].fTiny = tiny; | |
533 span[more - 1].fDone = true; | |
534 if (approximately_negative(span[more].fT - newT) && tiny) { | |
535 if (approximately_greater_than_one(span[more].fT)) { | |
536 span[more + 1].fUnsortableStart = true; | |
537 span[more].fUnsortableEnd = true; | |
538 } | |
539 if (approximately_less_than_zero(newT)) { | |
540 span[more].fUnsortableStart = true; | |
541 span[more - 1].fUnsortableEnd = true; | |
542 } | |
543 } | |
544 ++fDoneSpans; | |
545 ++more; | 646 ++more; |
546 } | 647 } |
| 648 ++less; |
| 649 --more; |
| 650 while (more - 1 > less && span[more].fPt == span[more - 1].fPt |
| 651 && span[more].fT == span[more - 1].fT) { |
| 652 --more; |
| 653 } |
| 654 if (less == more) { |
| 655 return insertedAt; |
| 656 } |
| 657 if (precisely_negative(span[more].fT - span[less].fT)) { |
| 658 return insertedAt; |
| 659 } |
| 660 // if the total range of t values is big enough, mark all tiny |
| 661 bool tiny = span[less].fPt == span[more].fPt; |
| 662 int index = less; |
| 663 do { |
| 664 fSmall = span[index].fSmall = true; |
| 665 fTiny |= span[index].fTiny = tiny; |
| 666 if (!span[index].fDone) { |
| 667 span[index].fDone = true; |
| 668 ++fDoneSpans; |
| 669 } |
| 670 } while (++index < more); |
547 return insertedAt; | 671 return insertedAt; |
548 } | 672 } |
549 | 673 |
550 // set spans from start to end to decrement by one | 674 // set spans from start to end to decrement by one |
551 // note this walks other backwards | 675 // note this walks other backwards |
552 // FIXME: there's probably an edge case that can be constructed where | 676 // FIXME: there's probably an edge case that can be constructed where |
553 // two span in one segment are separated by float epsilon on one span but | 677 // two span in one segment are separated by float epsilon on one span but |
554 // not the other, if one segment is very small. For this | 678 // not the other, if one segment is very small. For this |
555 // case the counts asserted below may or may not be enough to separate the | 679 // case the counts asserted below may or may not be enough to separate the |
556 // spans. Even if the counts work out, what if the spans aren't correctly | 680 // spans. Even if the counts work out, what if the spans aren't correctly |
557 // sorted? It feels better in such a case to match the span's other span | 681 // sorted? It feels better in such a case to match the span's other span |
558 // pointer since both coincident segments must contain the same spans. | 682 // pointer since both coincident segments must contain the same spans. |
559 // FIXME? It seems that decrementing by one will fail for complex paths that | 683 // FIXME? It seems that decrementing by one will fail for complex paths that |
560 // have three or more coincident edges. Shouldn't this subtract the difference | 684 // have three or more coincident edges. Shouldn't this subtract the difference |
561 // between the winding values? | 685 // between the winding values? |
562 /* |--> |--> | 686 /* |--> |--> |
563 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>
4 | 687 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>
4 |
564 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0 | 688 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0 |
565 ^ ^ <--| <--| | 689 ^ ^ <--| <--| |
566 startPt endPt test/oTest first pos test/oTest final po
s | 690 startPt endPt test/oTest first pos test/oTest final po
s |
567 */ | 691 */ |
568 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { | 692 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { |
569 bool binary = fOperand != other->fOperand; | 693 bool binary = fOperand != other->fOperand; |
570 int index = 0; | 694 int index = 0; |
571 while (startPt != fTs[index].fPt) { | 695 while (startPt != fTs[index].fPt) { |
572 SkASSERT(index < fTs.count()); | 696 SkASSERT(index < fTs.count()); |
573 ++index; | 697 ++index; |
574 } | 698 } |
575 while (index > 0 && fTs[index].fT == fTs[index - 1].fT) { | 699 while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) { |
576 --index; | 700 --index; |
577 } | 701 } |
578 int oIndex = other->fTs.count(); | 702 int oIndex = other->fTs.count(); |
579 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match | 703 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match |
580 SkASSERT(oIndex > 0); | 704 SkASSERT(oIndex > 0); |
581 } | 705 } |
582 double oStartT = other->fTs[oIndex].fT; | 706 double oStartT = other->fTs[oIndex].fT; |
583 // look for first point beyond match | 707 // look for first point beyond match |
584 while (startPt == other->fTs[--oIndex].fPt || oStartT == other->fTs[oIndex].
fT) { | 708 while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other
->fTs[oIndex].fT)) { |
585 SkASSERT(oIndex > 0); | 709 SkASSERT(oIndex > 0); |
586 } | 710 } |
587 SkOpSpan* test = &fTs[index]; | 711 SkOpSpan* test = &fTs[index]; |
588 SkOpSpan* oTest = &other->fTs[oIndex]; | 712 SkOpSpan* oTest = &other->fTs[oIndex]; |
589 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | 713 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
590 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | 714 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
591 do { | 715 do { |
592 SkASSERT(test->fT < 1); | 716 SkASSERT(test->fT < 1); |
593 SkASSERT(oTest->fT < 1); | 717 SkASSERT(oTest->fT < 1); |
594 bool decrement = test->fWindValue && oTest->fWindValue; | 718 bool decrement = test->fWindValue && oTest->fWindValue; |
595 bool track = test->fWindValue || oTest->fWindValue; | 719 bool track = test->fWindValue || oTest->fWindValue; |
596 bool bigger = test->fWindValue >= oTest->fWindValue; | 720 bool bigger = test->fWindValue >= oTest->fWindValue; |
597 const SkPoint& testPt = test->fPt; | 721 const SkPoint& testPt = test->fPt; |
598 double testT = test->fT; | 722 double testT = test->fT; |
599 const SkPoint& oTestPt = oTest->fPt; | 723 const SkPoint& oTestPt = oTest->fPt; |
600 double oTestT = oTest->fT; | 724 double oTestT = oTest->fT; |
601 do { | 725 do { |
602 if (decrement) { | 726 if (decrement) { |
603 if (binary && bigger) { | 727 if (binary && bigger) { |
604 test->fOppValue--; | 728 test->fOppValue--; |
605 } else { | 729 } else { |
606 decrementSpan(test); | 730 decrementSpan(test); |
607 } | 731 } |
608 } else if (track) { | 732 } else if (track) { |
609 TrackOutsidePair(&outsidePts, testPt, oTestPt); | 733 TrackOutsidePair(&outsidePts, testPt, oTestPt); |
610 } | 734 } |
611 SkASSERT(index < fTs.count() - 1); | 735 SkASSERT(index < fTs.count() - 1); |
612 test = &fTs[++index]; | 736 test = &fTs[++index]; |
613 } while (testPt == test->fPt || testT == test->fT); | 737 } while (testPt == test->fPt || precisely_equal(testT, test->fT)); |
614 SkDEBUGCODE(int originalWindValue = oTest->fWindValue); | 738 SkDEBUGCODE(int originalWindValue = oTest->fWindValue); |
615 do { | 739 do { |
616 SkASSERT(oTest->fT < 1); | 740 SkASSERT(oTest->fT < 1); |
617 SkASSERT(originalWindValue == oTest->fWindValue); | 741 SkASSERT(originalWindValue == oTest->fWindValue); |
618 if (decrement) { | 742 if (decrement) { |
619 if (binary && !bigger) { | 743 if (binary && !bigger) { |
620 oTest->fOppValue--; | 744 oTest->fOppValue--; |
621 } else { | 745 } else { |
622 other->decrementSpan(oTest); | 746 other->decrementSpan(oTest); |
623 } | 747 } |
624 } else if (track) { | 748 } else if (track) { |
625 TrackOutsidePair(&oOutsidePts, oTestPt, testPt); | 749 TrackOutsidePair(&oOutsidePts, oTestPt, testPt); |
626 } | 750 } |
627 if (!oIndex) { | 751 if (!oIndex) { |
628 break; | 752 break; |
629 } | 753 } |
630 oTest = &other->fTs[--oIndex]; | 754 oTest = &other->fTs[--oIndex]; |
631 } while (oTestPt == oTest->fPt || oTestT == oTest->fT); | 755 } while (oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT)); |
632 } while (endPt != test->fPt && test->fT < 1); | 756 } while (endPt != test->fPt && test->fT < 1); |
633 // FIXME: determine if canceled edges need outside ts added | 757 // FIXME: determine if canceled edges need outside ts added |
634 int outCount = outsidePts.count(); | 758 int outCount = outsidePts.count(); |
635 if (!done() && outCount) { | 759 if (!done() && outCount) { |
636 addCancelOutsides(outsidePts[0], outsidePts[1], other); | 760 addCancelOutsides(outsidePts[0], outsidePts[1], other); |
637 if (outCount > 2) { | 761 if (outCount > 2) { |
638 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); | 762 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); |
639 } | 763 } |
640 } | 764 } |
641 if (!other->done() && oOutsidePts.count()) { | 765 if (!other->done() && oOutsidePts.count()) { |
642 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); | 766 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); |
643 } | 767 } |
644 } | 768 } |
645 | 769 |
646 int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) { | 770 int SkOpSegment::addSelfT(const SkPoint& pt, double newT) { |
647 // if the tail nearly intersects itself but not quite, the caller records th
is separately | 771 // if the tail nearly intersects itself but not quite, the caller records th
is separately |
648 int result = addT(other, pt, newT); | 772 int result = addT(this, pt, newT); |
649 SkOpSpan* span = &fTs[result]; | 773 SkOpSpan* span = &fTs[result]; |
650 span->fLoop = true; | 774 fLoop = span->fLoop = true; |
651 return result; | 775 return result; |
652 } | 776 } |
653 | 777 |
| 778 void SkOpSegment::addSimpleAngle(int index) { |
| 779 if (index == 0) { |
| 780 SkASSERT(!fTs[index].fTiny && fTs[index + 1].fT > 0); |
| 781 addStartSpan(1); |
| 782 } else { |
| 783 SkASSERT(!fTs[index - 1].fTiny && fTs[index - 1].fT < 1); |
| 784 addEndSpan(index); |
| 785 } |
| 786 SkOpSpan& span = fTs[index]; |
| 787 SkOpSegment* other = span.fOther; |
| 788 SkOpSpan& oSpan = other->fTs[span.fOtherIndex]; |
| 789 SkOpAngle* angle, * oAngle; |
| 790 if (index == 0) { |
| 791 SkASSERT(span.fOtherIndex - 1 >= 0); |
| 792 SkASSERT(span.fOtherT == 1); |
| 793 SkDEBUGCODE(SkOpSpan& oPrior = other->fTs[span.fOtherIndex - 1]); |
| 794 SkASSERT(!oPrior.fTiny && oPrior.fT < 1); |
| 795 other->addEndSpan(span.fOtherIndex); |
| 796 angle = &this->angle(span.fToAngleIndex); |
| 797 oAngle = &other->angle(oSpan.fFromAngleIndex); |
| 798 } else { |
| 799 SkASSERT(span.fOtherIndex + 1 < other->count()); |
| 800 SkASSERT(span.fOtherT == 0); |
| 801 SkASSERT(!oSpan.fTiny && (other->fTs[span.fOtherIndex + 1].fT > 0 |
| 802 || (other->fTs[span.fOtherIndex + 1].fFromAngleIndex < 0 |
| 803 && other->fTs[span.fOtherIndex + 1].fToAngleIndex < 0))); |
| 804 int oIndex = 1; |
| 805 do { |
| 806 const SkOpSpan& osSpan = other->span(oIndex); |
| 807 if (osSpan.fFromAngleIndex >= 0 || osSpan.fT > 0) { |
| 808 break; |
| 809 } |
| 810 ++oIndex; |
| 811 SkASSERT(oIndex < other->count()); |
| 812 } while (true); |
| 813 other->addStartSpan(oIndex); |
| 814 angle = &this->angle(span.fFromAngleIndex); |
| 815 oAngle = &other->angle(oSpan.fToAngleIndex); |
| 816 } |
| 817 angle->insert(oAngle); |
| 818 } |
| 819 |
| 820 bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) { |
| 821 bool aligned = false; |
| 822 SkOpSpan* span = &fTs[index]; |
| 823 SkOpSegment* other = span->fOther; |
| 824 int oIndex = span->fOtherIndex; |
| 825 SkOpSpan* oSpan = &other->fTs[oIndex]; |
| 826 if (span->fT != thisT) { |
| 827 span->fT = thisT; |
| 828 oSpan->fOtherT = thisT; |
| 829 aligned = true; |
| 830 } |
| 831 if (span->fPt != thisPt) { |
| 832 span->fPt = thisPt; |
| 833 oSpan->fPt = thisPt; |
| 834 aligned = true; |
| 835 } |
| 836 double oT = oSpan->fT; |
| 837 if (oT == 0 || oT == 1) { |
| 838 return aligned; |
| 839 } |
| 840 int oStart = other->nextSpan(oIndex, -1) + 1; |
| 841 int oEnd = other->nextSpan(oIndex, 1); |
| 842 oSpan = &other->fTs[oStart]; |
| 843 oT = oSpan->fT; |
| 844 bool oAligned = false; |
| 845 if (oSpan->fPt != thisPt) { |
| 846 oAligned |= other->alignSpan(oStart, oT, thisPt); |
| 847 } |
| 848 int otherIndex = oStart; |
| 849 while (++otherIndex < oEnd) { |
| 850 SkOpSpan* oNextSpan = &other->fTs[otherIndex]; |
| 851 if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) { |
| 852 oAligned |= other->alignSpan(otherIndex, oT, thisPt); |
| 853 } |
| 854 } |
| 855 if (oAligned) { |
| 856 other->alignSpanState(oStart, oEnd); |
| 857 } |
| 858 return aligned; |
| 859 } |
| 860 |
| 861 void SkOpSegment::alignSpanState(int start, int end) { |
| 862 SkOpSpan* lastSpan = &fTs[--end]; |
| 863 bool allSmall = lastSpan->fSmall; |
| 864 bool allTiny = lastSpan->fTiny; |
| 865 bool allDone = lastSpan->fDone; |
| 866 SkDEBUGCODE(int winding = lastSpan->fWindValue); |
| 867 SkDEBUGCODE(int oppWinding = lastSpan->fOppValue); |
| 868 int index = start; |
| 869 while (index < end) { |
| 870 SkOpSpan* span = &fTs[index]; |
| 871 span->fSmall = allSmall; |
| 872 span->fTiny = allTiny; |
| 873 if (span->fDone != allDone) { |
| 874 span->fDone = allDone; |
| 875 fDoneSpans += allDone ? 1 : -1; |
| 876 } |
| 877 SkASSERT(span->fWindValue == winding); |
| 878 SkASSERT(span->fOppValue == oppWinding); |
| 879 ++index; |
| 880 } |
| 881 } |
| 882 |
654 void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in
dexPtr, | 883 void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in
dexPtr, |
655 SkTArray<SkPoint, true>* outsideTs) { | 884 SkTArray<SkPoint, true>* outsideTs) { |
656 int index = *indexPtr; | 885 int index = *indexPtr; |
657 int oWindValue = oTest.fWindValue; | 886 int oWindValue = oTest.fWindValue; |
658 int oOppValue = oTest.fOppValue; | 887 int oOppValue = oTest.fOppValue; |
659 if (binary) { | 888 if (binary) { |
660 SkTSwap<int>(oWindValue, oOppValue); | 889 SkTSwap<int>(oWindValue, oOppValue); |
661 } | 890 } |
662 SkOpSpan* const test = &fTs[index]; | 891 SkOpSpan* const test = &fTs[index]; |
663 SkOpSpan* end = test; | 892 SkOpSpan* end = test; |
664 const SkPoint& oStartPt = oTest.fPt; | 893 const SkPoint& oStartPt = oTest.fPt; |
665 do { | 894 do { |
666 if (bumpSpan(end, oWindValue, oOppValue)) { | 895 if (bumpSpan(end, oWindValue, oOppValue)) { |
667 TrackOutside(outsideTs, oStartPt); | 896 TrackOutside(outsideTs, oStartPt); |
668 } | 897 } |
669 end = &fTs[++index]; | 898 end = &fTs[++index]; |
670 } while ((end->fPt == test->fPt || end->fT == test->fT) && end->fT < 1); | 899 } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && en
d->fT < 1); |
671 *indexPtr = index; | 900 *indexPtr = index; |
672 } | 901 } |
673 | 902 |
674 // because of the order in which coincidences are resolved, this and other | 903 // because of the order in which coincidences are resolved, this and other |
675 // may not have the same intermediate points. Compute the corresponding | 904 // may not have the same intermediate points. Compute the corresponding |
676 // intermediate T values (using this as the master, other as the follower) | 905 // intermediate T values (using this as the master, other as the follower) |
677 // and walk other conditionally -- hoping that it catches up in the end | 906 // and walk other conditionally -- hoping that it catches up in the end |
678 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, | 907 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, |
679 SkTArray<SkPoint, true>* oOutsidePts) { | 908 SkTArray<SkPoint, true>* oOutsidePts) { |
680 int oIndex = *oIndexPtr; | 909 int oIndex = *oIndexPtr; |
681 SkOpSpan* const oTest = &fTs[oIndex]; | 910 SkOpSpan* const oTest = &fTs[oIndex]; |
682 SkOpSpan* oEnd = oTest; | 911 SkOpSpan* oEnd = oTest; |
683 const SkPoint& startPt = test.fPt; | |
684 const SkPoint& oStartPt = oTest->fPt; | 912 const SkPoint& oStartPt = oTest->fPt; |
685 double oStartT = oTest->fT; | 913 double oStartT = oTest->fT; |
686 if (oStartPt == oEnd->fPt || oStartT == oEnd->fT) { | 914 #if 0 // FIXME : figure out what disabling this breaks |
| 915 const SkPoint& startPt = test.fPt; |
| 916 // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find
proper condition |
| 917 if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { |
687 TrackOutside(oOutsidePts, startPt); | 918 TrackOutside(oOutsidePts, startPt); |
688 } | 919 } |
689 while (oStartPt == oEnd->fPt || oStartT == oEnd->fT) { | 920 #endif |
| 921 while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { |
690 zeroSpan(oEnd); | 922 zeroSpan(oEnd); |
691 oEnd = &fTs[++oIndex]; | 923 oEnd = &fTs[++oIndex]; |
692 } | 924 } |
693 *oIndexPtr = oIndex; | 925 *oIndexPtr = oIndex; |
694 } | 926 } |
695 | 927 |
696 // FIXME: need to test this case: | 928 // FIXME: need to test this case: |
697 // contourA has two segments that are coincident | 929 // contourA has two segments that are coincident |
698 // contourB has two segments that are coincident in the same place | 930 // contourB has two segments that are coincident in the same place |
699 // each ends up with +2/0 pairs for winding count | 931 // each ends up with +2/0 pairs for winding count |
700 // since logic below doesn't transfer count (only increments/decrements) can thi
s be | 932 // since logic below doesn't transfer count (only increments/decrements) can thi
s be |
701 // resolved to +4/0 ? | 933 // resolved to +4/0 ? |
702 | 934 |
703 // set spans from start to end to increment the greater by one and decrement | 935 // set spans from start to end to increment the greater by one and decrement |
704 // the lesser | 936 // the lesser |
705 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, | 937 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, |
706 SkOpSegment* other) { | 938 SkOpSegment* other) { |
707 bool binary = fOperand != other->fOperand; | 939 bool binary = fOperand != other->fOperand; |
708 int index = 0; | 940 int index = 0; |
709 while (startPt != fTs[index].fPt) { | 941 while (startPt != fTs[index].fPt) { |
710 SkASSERT(index < fTs.count()); | 942 SkASSERT(index < fTs.count()); |
711 ++index; | 943 ++index; |
712 } | 944 } |
713 double startT = fTs[index].fT; | 945 double startT = fTs[index].fT; |
714 while (index > 0 && fTs[index - 1].fT == startT) { | 946 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) { |
715 --index; | 947 --index; |
716 } | 948 } |
717 int oIndex = 0; | 949 int oIndex = 0; |
718 while (startPt != other->fTs[oIndex].fPt) { | 950 while (startPt != other->fTs[oIndex].fPt) { |
719 SkASSERT(oIndex < other->fTs.count()); | 951 SkASSERT(oIndex < other->fTs.count()); |
720 ++oIndex; | 952 ++oIndex; |
721 } | 953 } |
722 double oStartT = other->fTs[oIndex].fT; | 954 double oStartT = other->fTs[oIndex].fT; |
723 while (oIndex > 0 && other->fTs[oIndex - 1].fT == oStartT) { | 955 while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) { |
724 --oIndex; | 956 --oIndex; |
725 } | 957 } |
726 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | 958 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
727 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | 959 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
728 SkOpSpan* test = &fTs[index]; | 960 SkOpSpan* test = &fTs[index]; |
729 const SkPoint* testPt = &test->fPt; | 961 const SkPoint* testPt = &test->fPt; |
730 double testT = test->fT; | 962 double testT = test->fT; |
731 SkOpSpan* oTest = &other->fTs[oIndex]; | 963 SkOpSpan* oTest = &other->fTs[oIndex]; |
732 const SkPoint* oTestPt = &oTest->fPt; | 964 const SkPoint* oTestPt = &oTest->fPt; |
733 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | 965 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
734 do { | 966 do { |
735 SkASSERT(test->fT < 1); | 967 SkASSERT(test->fT < 1); |
736 SkASSERT(oTest->fT < 1); | 968 SkASSERT(oTest->fT < 1); |
737 #if 0 | 969 |
738 if (test->fDone || oTest->fDone) { | 970 // consolidate the winding count even if done |
739 #else // consolidate the winding count even if done | |
740 if ((test->fWindValue == 0 && test->fOppValue == 0) | 971 if ((test->fWindValue == 0 && test->fOppValue == 0) |
741 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { | 972 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { |
742 #endif | |
743 SkDEBUGCODE(int firstWind = test->fWindValue); | 973 SkDEBUGCODE(int firstWind = test->fWindValue); |
744 SkDEBUGCODE(int firstOpp = test->fOppValue); | 974 SkDEBUGCODE(int firstOpp = test->fOppValue); |
745 do { | 975 do { |
746 SkASSERT(firstWind == fTs[index].fWindValue); | 976 SkASSERT(firstWind == fTs[index].fWindValue); |
747 SkASSERT(firstOpp == fTs[index].fOppValue); | 977 SkASSERT(firstOpp == fTs[index].fOppValue); |
748 ++index; | 978 ++index; |
749 SkASSERT(index < fTs.count()); | 979 SkASSERT(index < fTs.count()); |
750 } while (*testPt == fTs[index].fPt); | 980 } while (*testPt == fTs[index].fPt); |
751 SkDEBUGCODE(firstWind = oTest->fWindValue); | 981 SkDEBUGCODE(firstWind = oTest->fWindValue); |
752 SkDEBUGCODE(firstOpp = oTest->fOppValue); | 982 SkDEBUGCODE(firstOpp = oTest->fOppValue); |
753 do { | 983 do { |
754 SkASSERT(firstWind == other->fTs[oIndex].fWindValue); | 984 SkASSERT(firstWind == other->fTs[oIndex].fWindValue); |
755 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue); | 985 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue); |
756 ++oIndex; | 986 ++oIndex; |
757 SkASSERT(oIndex < other->fTs.count()); | 987 SkASSERT(oIndex < other->fTs.count()); |
758 } while (*oTestPt == other->fTs[oIndex].fPt); | 988 } while (*oTestPt == other->fTs[oIndex].fPt); |
759 } else { | 989 } else { |
760 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { | 990 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { |
761 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); | 991 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); |
762 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); | 992 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); |
763 } else { | 993 } else { |
764 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); | 994 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); |
765 bumpCoincidentOther(*oTest, &index, &outsidePts); | 995 bumpCoincidentOther(*oTest, &index, &outsidePts); |
766 } | 996 } |
767 } | 997 } |
768 test = &fTs[index]; | 998 test = &fTs[index]; |
769 testPt = &test->fPt; | 999 testPt = &test->fPt; |
770 testT = test->fT; | 1000 testT = test->fT; |
771 if (endPt == *testPt || endT == testT) { | 1001 oTest = &other->fTs[oIndex]; |
| 1002 oTestPt = &oTest->fPt; |
| 1003 if (endPt == *testPt || precisely_equal(endT, testT)) { |
772 break; | 1004 break; |
773 } | 1005 } |
774 oTest = &other->fTs[oIndex]; | 1006 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
775 oTestPt = &oTest->fPt; | |
776 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | |
777 } while (endPt != *oTestPt); | 1007 } while (endPt != *oTestPt); |
778 if (endPt != *testPt && endT != testT) { // in rare cases, one may have end
ed before the other | 1008 // in rare cases, one may have ended before the other |
| 1009 if (endPt != *testPt && !precisely_equal(endT, testT)) { |
779 int lastWind = test[-1].fWindValue; | 1010 int lastWind = test[-1].fWindValue; |
780 int lastOpp = test[-1].fOppValue; | 1011 int lastOpp = test[-1].fOppValue; |
781 bool zero = lastWind == 0 && lastOpp == 0; | 1012 bool zero = lastWind == 0 && lastOpp == 0; |
782 do { | 1013 do { |
783 if (test->fWindValue || test->fOppValue) { | 1014 if (test->fWindValue || test->fOppValue) { |
784 test->fWindValue = lastWind; | 1015 test->fWindValue = lastWind; |
785 test->fOppValue = lastOpp; | 1016 test->fOppValue = lastOpp; |
786 if (zero) { | 1017 if (zero) { |
787 test->fDone = true; | 1018 test->fDone = true; |
788 ++fDoneSpans; | 1019 ++fDoneSpans; |
789 } | 1020 } |
790 } | 1021 } |
791 test = &fTs[++index]; | 1022 test = &fTs[++index]; |
792 testPt = &test->fPt; | 1023 testPt = &test->fPt; |
793 } while (endPt != *testPt); | 1024 } while (endPt != *testPt); |
794 } | 1025 } |
| 1026 if (endPt != *oTestPt) { |
| 1027 // look ahead to see if zeroing more spans will allows us to catch up |
| 1028 int oPeekIndex = oIndex; |
| 1029 bool success = true; |
| 1030 SkOpSpan* oPeek; |
| 1031 do { |
| 1032 oPeek = &other->fTs[oPeekIndex]; |
| 1033 if (oPeek->fT == 1) { |
| 1034 success = false; |
| 1035 break; |
| 1036 } |
| 1037 ++oPeekIndex; |
| 1038 } while (endPt != oPeek->fPt); |
| 1039 if (success) { |
| 1040 // make sure the matching point completes the coincidence span |
| 1041 success = false; |
| 1042 do { |
| 1043 if (oPeek->fOther == this) { |
| 1044 success = true; |
| 1045 break; |
| 1046 } |
| 1047 oPeek = &other->fTs[++oPeekIndex]; |
| 1048 } while (endPt == oPeek->fPt); |
| 1049 } |
| 1050 if (success) { |
| 1051 do { |
| 1052 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { |
| 1053 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); |
| 1054 } else { |
| 1055 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsideP
ts); |
| 1056 } |
| 1057 oTest = &other->fTs[oIndex]; |
| 1058 oTestPt = &oTest->fPt; |
| 1059 } while (endPt != *oTestPt); |
| 1060 } |
| 1061 } |
795 int outCount = outsidePts.count(); | 1062 int outCount = outsidePts.count(); |
796 if (!done() && outCount) { | 1063 if (!done() && outCount) { |
797 addCoinOutsides(outsidePts[0], endPt, other); | 1064 addCoinOutsides(outsidePts[0], endPt, other); |
798 } | 1065 } |
799 if (!other->done() && oOutsidePts.count()) { | 1066 if (!other->done() && oOutsidePts.count()) { |
800 other->addCoinOutsides(oOutsidePts[0], endPt, this); | 1067 other->addCoinOutsides(oOutsidePts[0], endPt, this); |
801 } | 1068 } |
802 } | 1069 } |
803 | 1070 |
804 // FIXME: this doesn't prevent the same span from being added twice | 1071 // FIXME: this doesn't prevent the same span from being added twice |
805 // fix in caller, SkASSERT here? | 1072 // fix in caller, SkASSERT here? |
806 void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool bor
rowWind, | 1073 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
T, bool borrowWind, |
807 const SkPoint& pt) { | 1074 const SkPoint& pt) { |
808 int tCount = fTs.count(); | 1075 int tCount = fTs.count(); |
809 for (int tIndex = 0; tIndex < tCount; ++tIndex) { | 1076 for (int tIndex = 0; tIndex < tCount; ++tIndex) { |
810 const SkOpSpan& span = fTs[tIndex]; | 1077 const SkOpSpan& span = fTs[tIndex]; |
811 if (!approximately_negative(span.fT - t)) { | 1078 if (!approximately_negative(span.fT - t)) { |
812 break; | 1079 break; |
813 } | 1080 } |
814 if (approximately_negative(span.fT - t) && span.fOther == other | 1081 if (approximately_negative(span.fT - t) && span.fOther == other |
815 && approximately_equal(span.fOtherT, otherT)) { | 1082 && approximately_equal(span.fOtherT, otherT)) { |
816 #if DEBUG_ADD_T_PAIR | 1083 #if DEBUG_ADD_T_PAIR |
817 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", | 1084 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", |
818 __FUNCTION__, fID, t, other->fID, otherT); | 1085 __FUNCTION__, fID, t, other->fID, otherT); |
819 #endif | 1086 #endif |
820 return; | 1087 return NULL; |
821 } | 1088 } |
822 } | 1089 } |
823 #if DEBUG_ADD_T_PAIR | 1090 #if DEBUG_ADD_T_PAIR |
824 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", | 1091 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", |
825 __FUNCTION__, fID, t, other->fID, otherT); | 1092 __FUNCTION__, fID, t, other->fID, otherT); |
826 #endif | 1093 #endif |
827 int insertedAt = addT(other, pt, t); | 1094 int insertedAt = addT(other, pt, t); |
828 int otherInsertedAt = other->addT(this, pt, otherT); | 1095 int otherInsertedAt = other->addT(this, pt, otherT); |
829 addOtherT(insertedAt, otherT, otherInsertedAt); | 1096 addOtherT(insertedAt, otherT, otherInsertedAt); |
830 other->addOtherT(otherInsertedAt, t, insertedAt); | 1097 other->addOtherT(otherInsertedAt, t, insertedAt); |
831 matchWindingValue(insertedAt, t, borrowWind); | 1098 matchWindingValue(insertedAt, t, borrowWind); |
832 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); | 1099 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); |
| 1100 return &span(insertedAt); |
833 } | 1101 } |
834 | 1102 |
835 void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* an
gles) const { | 1103 const SkOpAngle& SkOpSegment::angle(int index) const { |
836 // add edge leading into junction | 1104 SkASSERT(index >= 0); |
837 int min = SkMin32(end, start); | 1105 int count = fAngles.count(); |
838 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) { | 1106 if (index < count) { |
839 addAngle(angles, end, start); | 1107 return fAngles[index]; |
840 } | 1108 } |
841 // add edge leading away from junction | 1109 index -= count; |
842 int step = SkSign32(end - start); | 1110 count = fSingletonAngles.count(); |
843 int tIndex = nextExactSpan(end, step); | 1111 SkASSERT(index < count); |
844 min = SkMin32(end, tIndex); | 1112 return fSingletonAngles[index]; |
845 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) { | |
846 addAngle(angles, end, tIndex); | |
847 } | |
848 } | 1113 } |
849 | 1114 |
850 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint&
pt2) const { | 1115 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint&
pt2) const { |
851 const SkPoint midPt = ptAtT(midT); | 1116 const SkPoint midPt = ptAtT(midT); |
852 SkPathOpsBounds bounds; | 1117 SkPathOpsBounds bounds; |
853 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY); | 1118 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY); |
854 bounds.sort(); | 1119 bounds.sort(); |
855 return bounds.almostContains(midPt); | 1120 return bounds.almostContains(midPt); |
856 } | 1121 } |
857 | 1122 |
858 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { | 1123 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { |
859 if (lesser > greater) { | 1124 if (lesser > greater) { |
860 SkTSwap<int>(lesser, greater); | 1125 SkTSwap<int>(lesser, greater); |
861 } | 1126 } |
862 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); | 1127 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); |
863 } | 1128 } |
864 | 1129 |
865 // note that this follows the same logic flow as active angle | 1130 // in extreme cases (like the buffer overflow test) return false to abort |
866 bool SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool
allowOpp) const { | 1131 // for now, if one t value represents two different points, then the values are
too extreme |
867 double referenceT = fTs[index].fT; | 1132 // to generate meaningful results |
868 const SkPoint& referencePt = fTs[index].fPt; | 1133 bool SkOpSegment::calcAngles() { |
869 int lesser = index; | 1134 int spanCount = fTs.count(); |
870 while (--lesser >= 0 && (allowOpp || fTs[lesser].fOther->fOperand == fOperan
d) | 1135 if (spanCount <= 2) { |
871 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { | 1136 return spanCount == 2; |
872 buildAnglesInner(lesser, angles); | |
873 } | 1137 } |
874 do { | 1138 int index = 1; |
875 buildAnglesInner(index, angles); | 1139 const SkOpSpan* firstSpan = &fTs[index]; |
876 if (++index == fTs.count()) { | 1140 int activePrior = checkSetAngle(0); |
877 break; | 1141 const SkOpSpan* span = &fTs[0]; |
878 } | 1142 if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther-
>multipleEnds()) { |
879 if (!allowOpp && fTs[index].fOther->fOperand != fOperand) { | 1143 index = findStartSpan(0); // curve start intersects |
880 break; | 1144 if (index < 0) { |
881 } | |
882 if (fTs[index - 1].fTiny) { | |
883 referenceT = fTs[index].fT; | |
884 continue; | |
885 } | |
886 if (!precisely_negative(fTs[index].fT - referenceT) && fTs[index].fPt ==
referencePt) { | |
887 // FIXME | |
888 // testQuad8 generates the wrong output unless false is returned her
e. Other tests will | |
889 // take this path although they aren't required to. This means that
many go much slower | |
890 // because of this sort fail. | |
891 // SkDebugf("!!!\n"); | |
892 return false; | 1145 return false; |
893 } | 1146 } |
894 } while (precisely_negative(fTs[index].fT - referenceT)); | 1147 if (activePrior >= 0) { |
| 1148 addStartSpan(index); |
| 1149 } |
| 1150 } |
| 1151 bool addEnd; |
| 1152 int endIndex = spanCount - 1; |
| 1153 span = &fTs[endIndex - 1]; |
| 1154 if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects |
| 1155 endIndex = findEndSpan(endIndex); |
| 1156 if (endIndex < 0) { |
| 1157 return false; |
| 1158 } |
| 1159 } else { |
| 1160 addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleSta
rts(); |
| 1161 } |
| 1162 SkASSERT(endIndex >= index); |
| 1163 int prior = 0; |
| 1164 while (index < endIndex) { |
| 1165 const SkOpSpan& fromSpan = fTs[index]; // for each intermediate interse
ction |
| 1166 const SkOpSpan* lastSpan; |
| 1167 span = &fromSpan; |
| 1168 int start = index; |
| 1169 do { |
| 1170 lastSpan = span; |
| 1171 span = &fTs[++index]; |
| 1172 SkASSERT(index < spanCount); |
| 1173 if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny
) { |
| 1174 break; |
| 1175 } |
| 1176 if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) { |
| 1177 return false; |
| 1178 } |
| 1179 } while (true); |
| 1180 int angleIndex = fAngles.count(); |
| 1181 int priorAngleIndex; |
| 1182 if (activePrior >= 0) { |
| 1183 int pActive = firstActive(prior); |
| 1184 SkASSERT(pActive < start); |
| 1185 fAngles.push_back().set(this, start, pActive); |
| 1186 priorAngleIndex = angleIndex++; |
| 1187 #if DEBUG_ANGLE |
| 1188 fAngles.back().setID(priorAngleIndex); |
| 1189 #endif |
| 1190 } |
| 1191 int active = checkSetAngle(start); |
| 1192 if (active >= 0) { |
| 1193 SkASSERT(active < index); |
| 1194 fAngles.push_back().set(this, active, index); |
| 1195 #if DEBUG_ANGLE |
| 1196 fAngles.back().setID(angleIndex); |
| 1197 #endif |
| 1198 } |
| 1199 #if DEBUG_ANGLE |
| 1200 debugCheckPointsEqualish(start, index); |
| 1201 #endif |
| 1202 prior = start; |
| 1203 do { |
| 1204 const SkOpSpan* startSpan = &fTs[start - 1]; |
| 1205 if (!startSpan->fSmall || startSpan->fFromAngleIndex >= 0 |
| 1206 || startSpan->fToAngleIndex >= 0) { |
| 1207 break; |
| 1208 } |
| 1209 --start; |
| 1210 } while (start > 0); |
| 1211 do { |
| 1212 if (activePrior >= 0) { |
| 1213 SkASSERT(fTs[start].fFromAngleIndex == -1); |
| 1214 fTs[start].fFromAngleIndex = priorAngleIndex; |
| 1215 } |
| 1216 if (active >= 0) { |
| 1217 SkASSERT(fTs[start].fToAngleIndex == -1); |
| 1218 fTs[start].fToAngleIndex = angleIndex; |
| 1219 } |
| 1220 } while (++start < index); |
| 1221 activePrior = active; |
| 1222 } |
| 1223 if (addEnd && activePrior >= 0) { |
| 1224 addEndSpan(endIndex); |
| 1225 } |
895 return true; | 1226 return true; |
896 } | 1227 } |
897 | 1228 |
898 void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles)
const { | 1229 int SkOpSegment::checkSetAngle(int tIndex) const { |
899 const SkOpSpan* span = &fTs[index]; | 1230 const SkOpSpan* span = &fTs[tIndex]; |
900 SkOpSegment* other = span->fOther; | 1231 while (span->fTiny /* || span->fSmall */) { |
901 // if there is only one live crossing, and no coincidence, continue | 1232 span = &fTs[++tIndex]; |
902 // in the same direction | |
903 // if there is coincidence, the only choice may be to reverse direction | |
904 // find edge on either side of intersection | |
905 int oIndex = span->fOtherIndex; | |
906 // if done == -1, prior span has already been processed | |
907 int step = 1; | |
908 int next = other->nextExactSpan(oIndex, step); | |
909 if (next < 0) { | |
910 step = -step; | |
911 next = other->nextExactSpan(oIndex, step); | |
912 } | 1233 } |
913 // add candidate into and away from junction | 1234 return isCanceled(tIndex) ? -1 : tIndex; |
914 other->addTwoAngles(next, oIndex, angles); | |
915 } | 1235 } |
916 | 1236 |
917 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType
includeType, | 1237 // at this point, the span is already ordered, or unorderable, or unsortable |
918 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted) { | 1238 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType
includeType) { |
919 addTwoAngles(startIndex, endIndex, angles); | 1239 SkASSERT(includeType != SkOpAngle::kUnaryXor); |
920 if (!buildAngles(endIndex, angles, includeType == SkOpAngle::kBinaryOpp)) { | 1240 SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex); |
| 1241 if (NULL == firstAngle) { |
921 return SK_NaN32; | 1242 return SK_NaN32; |
922 } | 1243 } |
923 int angleCount = angles->count(); | |
924 // abort early before sorting if an unsortable (not an unorderable) angle is
found | |
925 if (includeType != SkOpAngle::kUnaryXor) { | |
926 int firstIndex = -1; | |
927 while (++firstIndex < angleCount) { | |
928 const SkOpAngle& angle = (*angles)[firstIndex]; | |
929 if (angle.segment()->windSum(&angle) != SK_MinS32) { | |
930 break; | |
931 } | |
932 } | |
933 if (firstIndex == angleCount) { | |
934 return SK_MinS32; | |
935 } | |
936 } | |
937 bool sortable = SortAngles2(*angles, sorted); | |
938 #if DEBUG_SORT_RAW | |
939 if (sorted->count() > 0) { | |
940 (*sorted)[0]->segment()->debugShowSort(__FUNCTION__, *sorted, 0, 0, 0, s
ortable); | |
941 } | |
942 #endif | |
943 if (!sortable) { | |
944 return SK_NaN32; | |
945 } | |
946 if (includeType == SkOpAngle::kUnaryXor) { | |
947 return SK_MinS32; | |
948 } | |
949 // if all angles have a computed winding, | 1244 // if all angles have a computed winding, |
950 // or if no adjacent angles are orderable, | 1245 // or if no adjacent angles are orderable, |
951 // or if adjacent orderable angles have no computed winding, | 1246 // or if adjacent orderable angles have no computed winding, |
952 // there's nothing to do | 1247 // there's nothing to do |
953 // if two orderable angles are adjacent, and one has winding computed, trans
fer to the other | 1248 // if two orderable angles are adjacent, and one has winding computed, trans
fer to the other |
954 const SkOpAngle* baseAngle = NULL; | 1249 SkOpAngle* baseAngle = NULL; |
955 int last = angleCount; | |
956 int finalInitialOrderable = -1; | |
957 bool tryReverse = false; | 1250 bool tryReverse = false; |
958 // look for counterclockwise transfers | 1251 // look for counterclockwise transfers |
| 1252 SkOpAngle* angle = firstAngle; |
959 do { | 1253 do { |
960 int index = 0; | 1254 int testWinding = angle->segment()->windSum(angle); |
| 1255 if (SK_MinS32 != testWinding && !angle->unorderable()) { |
| 1256 baseAngle = angle; |
| 1257 continue; |
| 1258 } |
| 1259 if (angle->unorderable()) { |
| 1260 baseAngle = NULL; |
| 1261 tryReverse = true; |
| 1262 continue; |
| 1263 } |
| 1264 if (baseAngle) { |
| 1265 ComputeOneSum(baseAngle, angle, includeType); |
| 1266 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle :
NULL; |
| 1267 tryReverse |= !baseAngle; |
| 1268 } |
| 1269 } while ((angle = angle->next()) != firstAngle); |
| 1270 if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(angle)) { |
| 1271 firstAngle = baseAngle; |
| 1272 tryReverse = true; |
| 1273 } |
| 1274 if (tryReverse) { |
| 1275 baseAngle = NULL; |
| 1276 angle = firstAngle; |
961 do { | 1277 do { |
962 SkOpAngle* testAngle = (*sorted)[index]; | 1278 int testWinding = angle->segment()->windSum(angle); |
963 int testWinding = testAngle->segment()->windSum(testAngle); | 1279 if (SK_MinS32 != testWinding) { |
964 if (SK_MinS32 != testWinding && !testAngle->unorderable()) { | 1280 baseAngle = angle; |
965 baseAngle = testAngle; | |
966 continue; | 1281 continue; |
967 } | 1282 } |
968 if (testAngle->unorderable()) { | 1283 if (angle->unorderable()) { |
969 baseAngle = NULL; | 1284 baseAngle = NULL; |
970 tryReverse = true; | |
971 continue; | 1285 continue; |
972 } | 1286 } |
973 if (baseAngle) { | 1287 if (baseAngle) { |
974 ComputeOneSum(baseAngle, testAngle, includeType); | 1288 ComputeOneSumReverse(baseAngle, angle, includeType); |
975 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle
) ? testAngle | 1289 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angl
e : NULL; |
976 : NULL; | |
977 tryReverse |= !baseAngle; | |
978 continue; | |
979 } | 1290 } |
980 if (finalInitialOrderable + 1 == index) { | 1291 } while ((angle = angle->previous()) != firstAngle); |
981 finalInitialOrderable = index; | |
982 } | |
983 } while (++index != last); | |
984 if (finalInitialOrderable < 0) { | |
985 break; | |
986 } | |
987 last = finalInitialOrderable + 1; | |
988 finalInitialOrderable = -2; // make this always negative the second tim
e through | |
989 } while (baseAngle); | |
990 if (tryReverse) { | |
991 baseAngle = NULL; | |
992 last = 0; | |
993 finalInitialOrderable = angleCount; | |
994 do { | |
995 int index = angleCount; | |
996 while (--index >= last) { | |
997 SkOpAngle* testAngle = (*sorted)[index]; | |
998 int testWinding = testAngle->segment()->windSum(testAngle); | |
999 if (SK_MinS32 != testWinding) { | |
1000 baseAngle = testAngle; | |
1001 continue; | |
1002 } | |
1003 if (testAngle->unorderable()) { | |
1004 baseAngle = NULL; | |
1005 continue; | |
1006 } | |
1007 if (baseAngle) { | |
1008 ComputeOneSumReverse(baseAngle, testAngle, includeType); | |
1009 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testA
ngle) ? testAngle | |
1010 : NULL; | |
1011 continue; | |
1012 } | |
1013 if (finalInitialOrderable - 1 == index) { | |
1014 finalInitialOrderable = index; | |
1015 } | |
1016 } | |
1017 if (finalInitialOrderable >= angleCount) { | |
1018 break; | |
1019 } | |
1020 last = finalInitialOrderable; | |
1021 finalInitialOrderable = angleCount + 1; // make this inactive 2nd t
ime through | |
1022 } while (baseAngle); | |
1023 } | 1292 } |
1024 int minIndex = SkMin32(startIndex, endIndex); | 1293 int minIndex = SkMin32(startIndex, endIndex); |
1025 return windSum(minIndex); | 1294 return windSum(minIndex); |
1026 } | 1295 } |
1027 | 1296 |
1028 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 1297 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
1029 SkOpAngle::IncludeType includeType) { | 1298 SkOpAngle::IncludeType includeType) { |
1030 const SkOpSegment* baseSegment = baseAngle->segment(); | 1299 const SkOpSegment* baseSegment = baseAngle->segment(); |
1031 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 1300 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
1032 int sumSuWinding; | 1301 int sumSuWinding; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, | 1345 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
1077 nextAngle); | 1346 nextAngle); |
1078 } else { | 1347 } else { |
1079 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, | 1348 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, |
1080 &maxWinding, &sumWinding); | 1349 &maxWinding, &sumWinding); |
1081 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); | 1350 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); |
1082 } | 1351 } |
1083 nextAngle->setLastMarked(last); | 1352 nextAngle->setLastMarked(last); |
1084 } | 1353 } |
1085 | 1354 |
| 1355 void SkOpSegment::constructLine(SkPoint shortLine[2]) { |
| 1356 addLine(shortLine, false, false); |
| 1357 addT(NULL, shortLine[0], 0); |
| 1358 addT(NULL, shortLine[1], 1); |
| 1359 addStartSpan(1); |
| 1360 addEndSpan(1); |
| 1361 SkOpAngle& angle = fAngles.push_back(); |
| 1362 angle.set(this, 0, 1); |
| 1363 } |
| 1364 |
1086 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, | 1365 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, |
1087 bool* hitSomething, double mid, bool opp, bool cur
rent) const { | 1366 bool* hitSomething, double mid, bool opp, bool cur
rent) const { |
1088 SkScalar bottom = fBounds.fBottom; | 1367 SkScalar bottom = fBounds.fBottom; |
1089 int bestTIndex = -1; | 1368 int bestTIndex = -1; |
1090 if (bottom <= *bestY) { | 1369 if (bottom <= *bestY) { |
1091 return bestTIndex; | 1370 return bestTIndex; |
1092 } | 1371 } |
1093 SkScalar top = fBounds.fTop; | 1372 SkScalar top = fBounds.fTop; |
1094 if (top >= basePt.fY) { | 1373 if (top >= basePt.fY) { |
1095 return bestTIndex; | 1374 return bestTIndex; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1199 span->fOppValue &= 1; | 1478 span->fOppValue &= 1; |
1200 } | 1479 } |
1201 if (!span->fWindValue && !span->fOppValue) { | 1480 if (!span->fWindValue && !span->fOppValue) { |
1202 span->fDone = true; | 1481 span->fDone = true; |
1203 ++fDoneSpans; | 1482 ++fDoneSpans; |
1204 return true; | 1483 return true; |
1205 } | 1484 } |
1206 return false; | 1485 return false; |
1207 } | 1486 } |
1208 | 1487 |
| 1488 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const { |
| 1489 const SkOpSpan* firstSpan = &thisSpan; // rewind to the start |
| 1490 const SkOpSpan* beginSpan = fTs.begin(); |
| 1491 const SkPoint& testPt = thisSpan.fPt; |
| 1492 while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) { |
| 1493 --firstSpan; |
| 1494 } |
| 1495 return *firstSpan; |
| 1496 } |
| 1497 |
| 1498 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const { |
| 1499 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small |
| 1500 const SkOpSpan* lastSpan = &thisSpan; // find the end |
| 1501 const SkPoint& testPt = thisSpan.fPt; |
| 1502 while (lastSpan < endSpan && lastSpan[1].fPt == testPt) { |
| 1503 ++lastSpan; |
| 1504 } |
| 1505 return *lastSpan; |
| 1506 } |
| 1507 |
| 1508 // with a loop, the comparison is move involved |
| 1509 // scan backwards and forwards to count all matching points |
| 1510 // (verify that there are twp scans marked as loops) |
| 1511 // compare that against 2 matching scans for loop plus other results |
| 1512 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts)
{ |
| 1513 const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the star
t |
| 1514 const SkOpSpan& lastSpan = this->lastSpan(thisSpan); // find the end |
| 1515 double firstLoopT = -1, lastLoopT = -1; |
| 1516 const SkOpSpan* testSpan = &firstSpan - 1; |
| 1517 while (++testSpan <= &lastSpan) { |
| 1518 if (testSpan->fLoop) { |
| 1519 firstLoopT = testSpan->fT; |
| 1520 break; |
| 1521 } |
| 1522 } |
| 1523 testSpan = &lastSpan + 1; |
| 1524 while (--testSpan >= &firstSpan) { |
| 1525 if (testSpan->fLoop) { |
| 1526 lastLoopT = testSpan->fT; |
| 1527 break; |
| 1528 } |
| 1529 } |
| 1530 SkASSERT((firstLoopT == -1) == (lastLoopT == -1)); |
| 1531 if (firstLoopT == -1) { |
| 1532 return false; |
| 1533 } |
| 1534 SkASSERT(firstLoopT < lastLoopT); |
| 1535 testSpan = &firstSpan - 1; |
| 1536 smallCounts[0] = smallCounts[1] = 0; |
| 1537 while (++testSpan <= &lastSpan) { |
| 1538 SkASSERT(approximately_equal(testSpan->fT, firstLoopT) + |
| 1539 approximately_equal(testSpan->fT, lastLoopT) == 1); |
| 1540 smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++; |
| 1541 } |
| 1542 return true; |
| 1543 } |
| 1544 |
| 1545 // see if spans with two or more intersections have the same number on the other
end |
| 1546 void SkOpSegment::checkDuplicates() { |
| 1547 debugValidate(); |
| 1548 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
| 1549 int index; |
| 1550 int endIndex = 0; |
| 1551 bool endFound; |
| 1552 do { |
| 1553 index = endIndex; |
| 1554 endIndex = nextExactSpan(index, 1); |
| 1555 if ((endFound = endIndex < 0)) { |
| 1556 endIndex = count(); |
| 1557 } |
| 1558 int dupCount = endIndex - index; |
| 1559 if (dupCount < 2) { |
| 1560 continue; |
| 1561 } |
| 1562 do { |
| 1563 const SkOpSpan* thisSpan = &fTs[index]; |
| 1564 SkOpSegment* other = thisSpan->fOther; |
| 1565 int oIndex = thisSpan->fOtherIndex; |
| 1566 int oStart = other->nextExactSpan(oIndex, -1) + 1; |
| 1567 int oEnd = other->nextExactSpan(oIndex, 1); |
| 1568 if (oEnd < 0) { |
| 1569 oEnd = other->count(); |
| 1570 } |
| 1571 int oCount = oEnd - oStart; |
| 1572 // force the other to match its t and this pt if not on an end point |
| 1573 if (oCount != dupCount) { |
| 1574 MissingSpan& missing = missingSpans.push_back(); |
| 1575 missing.fOther = NULL; |
| 1576 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); |
| 1577 missing.fPt = thisSpan->fPt; |
| 1578 const SkOpSpan& oSpan = other->span(oIndex); |
| 1579 if (oCount > dupCount) { |
| 1580 missing.fSegment = this; |
| 1581 missing.fT = thisSpan->fT; |
| 1582 other->checkLinks(&oSpan, &missingSpans); |
| 1583 } else { |
| 1584 missing.fSegment = other; |
| 1585 missing.fT = oSpan.fT; |
| 1586 checkLinks(thisSpan, &missingSpans); |
| 1587 } |
| 1588 if (!missingSpans.back().fOther) { |
| 1589 missingSpans.pop_back(); |
| 1590 } |
| 1591 } |
| 1592 } while (++index < endIndex); |
| 1593 } while (!endFound); |
| 1594 int missingCount = missingSpans.count(); |
| 1595 if (missingCount == 0) { |
| 1596 return; |
| 1597 } |
| 1598 SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence; |
| 1599 for (index = 0; index < missingCount; ++index) { |
| 1600 MissingSpan& missing = missingSpans[index]; |
| 1601 SkOpSegment* missingOther = missing.fOther; |
| 1602 if (missing.fSegment == missing.fOther) { |
| 1603 continue; |
| 1604 } |
| 1605 const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOt
her, |
| 1606 missing.fOtherT, false, missing.fPt); |
| 1607 if (added && added->fSmall) { |
| 1608 missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence)
; |
| 1609 } |
| 1610 } |
| 1611 for (index = 0; index < missingCount; ++index) { |
| 1612 MissingSpan& missing = missingSpans[index]; |
| 1613 missing.fSegment->fixOtherTIndex(); |
| 1614 missing.fOther->fixOtherTIndex(); |
| 1615 } |
| 1616 for (index = 0; index < missingCoincidence.count(); ++index) { |
| 1617 MissingSpan& missing = missingCoincidence[index]; |
| 1618 missing.fSegment->fixOtherTIndex(); |
| 1619 } |
| 1620 debugValidate(); |
| 1621 } |
| 1622 |
1209 // look to see if the curve end intersects an intermediary that intersects the o
ther | 1623 // look to see if the curve end intersects an intermediary that intersects the o
ther |
1210 void SkOpSegment::checkEnds() { | 1624 void SkOpSegment::checkEnds() { |
1211 debugValidate(); | 1625 debugValidate(); |
1212 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | 1626 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
1213 int count = fTs.count(); | 1627 int count = fTs.count(); |
1214 for (int index = 0; index < count; ++index) { | 1628 for (int index = 0; index < count; ++index) { |
1215 const SkOpSpan& span = fTs[index]; | 1629 const SkOpSpan& span = fTs[index]; |
1216 double otherT = span.fOtherT; | 1630 double otherT = span.fOtherT; |
1217 if (otherT != 0 && otherT != 1) { // only check ends | 1631 if (otherT != 0 && otherT != 1) { // only check ends |
1218 continue; | 1632 continue; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1306 } | 1720 } |
1307 } | 1721 } |
1308 if (missingSpans.count() == 0) { | 1722 if (missingSpans.count() == 0) { |
1309 debugValidate(); | 1723 debugValidate(); |
1310 return; | 1724 return; |
1311 } | 1725 } |
1312 debugValidate(); | 1726 debugValidate(); |
1313 int missingCount = missingSpans.count(); | 1727 int missingCount = missingSpans.count(); |
1314 for (int index = 0; index < missingCount; ++index) { | 1728 for (int index = 0; index < missingCount; ++index) { |
1315 MissingSpan& missing = missingSpans[index]; | 1729 MissingSpan& missing = missingSpans[index]; |
1316 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt
); | 1730 if (this != missing.fOther) { |
| 1731 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing
.fPt); |
| 1732 } |
1317 } | 1733 } |
1318 fixOtherTIndex(); | 1734 fixOtherTIndex(); |
1319 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to | 1735 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to |
1320 // avoid this | 1736 // avoid this |
1321 for (int index = 0; index < missingCount; ++index) { | 1737 for (int index = 0; index < missingCount; ++index) { |
1322 missingSpans[index].fOther->fixOtherTIndex(); | 1738 missingSpans[index].fOther->fixOtherTIndex(); |
1323 } | 1739 } |
1324 debugValidate(); | 1740 debugValidate(); |
1325 } | 1741 } |
1326 | 1742 |
| 1743 void SkOpSegment::checkLinks(const SkOpSpan* base, |
| 1744 SkTArray<MissingSpan, true>* missingSpans) const { |
| 1745 const SkOpSpan* first = fTs.begin(); |
| 1746 const SkOpSpan* last = fTs.end() - 1; |
| 1747 SkASSERT(base >= first && last >= base); |
| 1748 const SkOpSegment* other = base->fOther; |
| 1749 const SkOpSpan* oFirst = other->fTs.begin(); |
| 1750 const SkOpSpan* oLast = other->fTs.end() - 1; |
| 1751 const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex]; |
| 1752 const SkOpSpan* test = base; |
| 1753 const SkOpSpan* missing = NULL; |
| 1754 while (test > first && (--test)->fPt == base->fPt) { |
| 1755 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); |
| 1756 } |
| 1757 test = base; |
| 1758 while (test < last && (++test)->fPt == base->fPt) { |
| 1759 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); |
| 1760 } |
| 1761 } |
| 1762 |
| 1763 // see if spans with two or more intersections all agree on common t and point v
alues |
| 1764 void SkOpSegment::checkMultiples() { |
| 1765 debugValidate(); |
| 1766 int index; |
| 1767 int end = 0; |
| 1768 while (fTs[++end].fT == 0) |
| 1769 ; |
| 1770 while (fTs[end].fT < 1) { |
| 1771 int start = index = end; |
| 1772 end = nextExactSpan(index, 1); |
| 1773 if (end <= index) { |
| 1774 return; // buffer overflow example triggers this |
| 1775 } |
| 1776 if (index + 1 == end) { |
| 1777 continue; |
| 1778 } |
| 1779 // force the duplicates to agree on t and pt if not on the end |
| 1780 double thisT = fTs[index].fT; |
| 1781 const SkPoint& thisPt = fTs[index].fPt; |
| 1782 bool aligned = false; |
| 1783 while (++index < end) { |
| 1784 aligned |= alignSpan(index, thisT, thisPt); |
| 1785 } |
| 1786 if (aligned) { |
| 1787 alignSpanState(start, end); |
| 1788 } |
| 1789 } |
| 1790 debugValidate(); |
| 1791 } |
| 1792 |
| 1793 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan, |
| 1794 const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingP
tr, |
| 1795 SkTArray<MissingSpan, true>* missingSpans) { |
| 1796 SkASSERT(oSpan->fPt == test->fPt); |
| 1797 const SkOpSpan* oTest = oSpan; |
| 1798 while (oTest > oFirst && (--oTest)->fPt == test->fPt) { |
| 1799 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { |
| 1800 return; |
| 1801 } |
| 1802 } |
| 1803 oTest = oSpan; |
| 1804 while (oTest < oLast && (++oTest)->fPt == test->fPt) { |
| 1805 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { |
| 1806 return; |
| 1807 } |
| 1808 } |
| 1809 if (*missingPtr) { |
| 1810 missingSpans->push_back(); |
| 1811 } |
| 1812 MissingSpan& lastMissing = missingSpans->back(); |
| 1813 if (*missingPtr) { |
| 1814 lastMissing = missingSpans->end()[-2]; |
| 1815 } |
| 1816 *missingPtr = test; |
| 1817 lastMissing.fOther = test->fOther; |
| 1818 lastMissing.fOtherT = test->fOtherT; |
| 1819 } |
| 1820 |
1327 bool SkOpSegment::checkSmall(int index) const { | 1821 bool SkOpSegment::checkSmall(int index) const { |
1328 if (fTs[index].fSmall) { | 1822 if (fTs[index].fSmall) { |
1329 return true; | 1823 return true; |
1330 } | 1824 } |
1331 double tBase = fTs[index].fT; | 1825 double tBase = fTs[index].fT; |
1332 while (index > 0 && precisely_negative(tBase - fTs[--index].fT)) | 1826 while (index > 0 && precisely_negative(tBase - fTs[--index].fT)) |
1333 ; | 1827 ; |
1334 return fTs[index].fSmall; | 1828 return fTs[index].fSmall; |
1335 } | 1829 } |
1336 | 1830 |
| 1831 // a pair of curves may turn into coincident lines -- small may be a hint that t
hat happened |
| 1832 // if a cubic contains a loop, the counts must be adjusted |
| 1833 void SkOpSegment::checkSmall() { |
| 1834 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
| 1835 const SkOpSpan* beginSpan = fTs.begin(); |
| 1836 const SkOpSpan* thisSpan = beginSpan - 1; |
| 1837 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small |
| 1838 while (++thisSpan < endSpan) { |
| 1839 if (!thisSpan->fSmall) { |
| 1840 continue; |
| 1841 } |
| 1842 if (!thisSpan->fWindValue) { |
| 1843 continue; |
| 1844 } |
| 1845 const SkOpSpan& firstSpan = this->firstSpan(*thisSpan); |
| 1846 const SkOpSpan& lastSpan = this->lastSpan(*thisSpan); |
| 1847 ptrdiff_t smallCount = &lastSpan - &firstSpan + 1; |
| 1848 SkASSERT(1 <= smallCount && smallCount < count()); |
| 1849 if (smallCount <= 1) { |
| 1850 SkASSERT(1 == smallCount); |
| 1851 checkSmallCoincidence(firstSpan, NULL); |
| 1852 continue; |
| 1853 } |
| 1854 // at this point, check for missing computed intersections |
| 1855 const SkPoint& testPt = firstSpan.fPt; |
| 1856 thisSpan = &firstSpan - 1; |
| 1857 SkOpSegment* other = NULL; |
| 1858 while (++thisSpan <= &lastSpan) { |
| 1859 other = thisSpan->fOther; |
| 1860 if (other != this) { |
| 1861 break; |
| 1862 } |
| 1863 } |
| 1864 SkASSERT(other != this); |
| 1865 int oIndex = thisSpan->fOtherIndex; |
| 1866 const SkOpSpan& oSpan = other->span(oIndex); |
| 1867 const SkOpSpan& oFirstSpan = other->firstSpan(oSpan); |
| 1868 const SkOpSpan& oLastSpan = other->lastSpan(oSpan); |
| 1869 ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1; |
| 1870 if (fLoop) { |
| 1871 int smallCounts[2]; |
| 1872 SkASSERT(!other->fLoop); // FIXME: we need more complicated logic f
or pair of loops |
| 1873 if (calcLoopSpanCount(*thisSpan, smallCounts)) { |
| 1874 if (smallCounts[0] && oCount != smallCounts[0]) { |
| 1875 SkASSERT(0); // FIXME: need a working test case to properly
code & debug |
| 1876 } |
| 1877 if (smallCounts[1] && oCount != smallCounts[1]) { |
| 1878 SkASSERT(0); // FIXME: need a working test case to properly
code & debug |
| 1879 } |
| 1880 goto nextSmallCheck; |
| 1881 } |
| 1882 } |
| 1883 if (other->fLoop) { |
| 1884 int otherCounts[2]; |
| 1885 if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) { |
| 1886 if (otherCounts[0] && otherCounts[0] != smallCount) { |
| 1887 SkASSERT(0); // FIXME: need a working test case to properly
code & debug |
| 1888 } |
| 1889 if (otherCounts[1] && otherCounts[1] != smallCount) { |
| 1890 SkASSERT(0); // FIXME: need a working test case to properly
code & debug |
| 1891 } |
| 1892 goto nextSmallCheck; |
| 1893 } |
| 1894 } |
| 1895 if (oCount != smallCount) { // check if number of pts in this match oth
er |
| 1896 MissingSpan& missing = missingSpans.push_back(); |
| 1897 missing.fOther = NULL; |
| 1898 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); |
| 1899 missing.fPt = testPt; |
| 1900 const SkOpSpan& oSpan = other->span(oIndex); |
| 1901 if (oCount > smallCount) { |
| 1902 missing.fSegment = this; |
| 1903 missing.fT = thisSpan->fT; |
| 1904 other->checkLinks(&oSpan, &missingSpans); |
| 1905 } else { |
| 1906 missing.fSegment = other; |
| 1907 missing.fT = oSpan.fT; |
| 1908 checkLinks(thisSpan, &missingSpans); |
| 1909 } |
| 1910 if (!missingSpans.back().fOther || missing.fSegment->done()) { |
| 1911 missingSpans.pop_back(); |
| 1912 } |
| 1913 } |
| 1914 nextSmallCheck: |
| 1915 thisSpan = &lastSpan; |
| 1916 } |
| 1917 int missingCount = missingSpans.count(); |
| 1918 for (int index = 0; index < missingCount; ++index) { |
| 1919 MissingSpan& missing = missingSpans[index]; |
| 1920 SkOpSegment* missingOther = missing.fOther; |
| 1921 // note that add t pair may edit span arrays, so prior pointers to spans
are no longer valid |
| 1922 if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOther
T, false, |
| 1923 missing.fPt)) { |
| 1924 continue; |
| 1925 } |
| 1926 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fSegment)
; |
| 1927 const SkOpSpan& otherSpan = missingOther->span(otherTIndex); |
| 1928 if (otherSpan.fSmall) { |
| 1929 const SkOpSpan* nextSpan = &otherSpan; |
| 1930 do { |
| 1931 ++nextSpan; |
| 1932 } while (nextSpan->fSmall); |
| 1933 missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt, nextSpa
n->fT, |
| 1934 missingOther); |
| 1935 } else if (otherSpan.fT > 0) { |
| 1936 const SkOpSpan* priorSpan = &otherSpan; |
| 1937 do { |
| 1938 --priorSpan; |
| 1939 } while (priorSpan->fT == otherSpan.fT); |
| 1940 if (priorSpan->fSmall) { |
| 1941 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missin
gOther); |
| 1942 } |
| 1943 } |
| 1944 } |
| 1945 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to |
| 1946 // avoid this |
| 1947 for (int index = 0; index < missingCount; ++index) { |
| 1948 MissingSpan& missing = missingSpans[index]; |
| 1949 missing.fSegment->fixOtherTIndex(); |
| 1950 missing.fOther->fixOtherTIndex(); |
| 1951 } |
| 1952 debugValidate(); |
| 1953 } |
| 1954 |
| 1955 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span, |
| 1956 SkTArray<MissingSpan, true>* checkMultiple) { |
| 1957 SkASSERT(span.fSmall); |
| 1958 SkASSERT(span.fWindValue); |
| 1959 SkASSERT(&span < fTs.end() - 1); |
| 1960 const SkOpSpan* next = &span + 1; |
| 1961 SkASSERT(!next->fSmall || checkMultiple); |
| 1962 if (checkMultiple) { |
| 1963 while (next->fSmall) { |
| 1964 ++next; |
| 1965 SkASSERT(next < fTs.end()); |
| 1966 } |
| 1967 } |
| 1968 SkOpSegment* other = span.fOther; |
| 1969 while (other != next->fOther) { |
| 1970 if (!checkMultiple) { |
| 1971 return; |
| 1972 } |
| 1973 const SkOpSpan* test = next + 1; |
| 1974 if (test == fTs.end()) { |
| 1975 return; |
| 1976 } |
| 1977 if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) { |
| 1978 return; |
| 1979 } |
| 1980 next = test; |
| 1981 } |
| 1982 SkASSERT(span.fT < next->fT); |
| 1983 int oStartIndex = other->findExactT(span.fOtherT, this); |
| 1984 int oEndIndex = other->findExactT(next->fOtherT, this); |
| 1985 // FIXME: be overly conservative by limiting this to the caller that allows
multiple smalls |
| 1986 if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath:
:kLine_Verb) { |
| 1987 SkPoint mid = ptAtT((span.fT + next->fT) / 2); |
| 1988 const SkOpSpan& oSpanStart = other->fTs[oStartIndex]; |
| 1989 const SkOpSpan& oSpanEnd = other->fTs[oEndIndex]; |
| 1990 SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2); |
| 1991 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { |
| 1992 return; |
| 1993 } |
| 1994 } |
| 1995 // FIXME: again, be overly conservative to avoid breaking existing tests |
| 1996 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex] |
| 1997 : other->fTs[oEndIndex]; |
| 1998 if (checkMultiple && !oSpan.fSmall) { |
| 1999 return; |
| 2000 } |
| 2001 SkASSERT(oSpan.fSmall); |
| 2002 if (oStartIndex < oEndIndex) { |
| 2003 addTCoincident(span.fPt, next->fPt, next->fT, other); |
| 2004 } else { |
| 2005 addTCancel(span.fPt, next->fPt, other); |
| 2006 } |
| 2007 if (!checkMultiple) { |
| 2008 return; |
| 2009 } |
| 2010 // check to see if either segment is coincident with a third segment -- if i
t is, and if |
| 2011 // the opposite segment is not already coincident with the third, make it so |
| 2012 // OPTIMIZE: to make this check easier, add coincident and cancel could set
a coincident bit |
| 2013 if (span.fWindValue != 1 || span.fOppValue != 0) { |
| 2014 // start here; |
| 2015 // iterate through the spans, looking for the third coincident case |
| 2016 // if we find one, we need to return state to the caller so that the ind
ices can be fixed |
| 2017 // this also suggests that all of this function is fragile since it reli
es on a valid index |
| 2018 } |
| 2019 // probably should make this a common function rather than copy/paste code |
| 2020 if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) { |
| 2021 const SkOpSpan* oTest = &oSpan; |
| 2022 while (--oTest >= other->fTs.begin()) { |
| 2023 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)
) { |
| 2024 break; |
| 2025 } |
| 2026 SkOpSegment* testOther = oTest->fOther; |
| 2027 SkASSERT(testOther != this); |
| 2028 // look in both directions to see if there is a coincident span |
| 2029 const SkOpSpan* tTest = testOther->fTs.begin(); |
| 2030 for (int testIndex = 0; testIndex < testOther->count(); ++testIndex)
{ |
| 2031 if (tTest->fPt != span.fPt) { |
| 2032 ++tTest; |
| 2033 continue; |
| 2034 } |
| 2035 if (testOther->verb() != SkPath::kLine_Verb |
| 2036 || other->verb() != SkPath::kLine_Verb) { |
| 2037 SkPoint mid = ptAtT((span.fT + next->fT) / 2); |
| 2038 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2
); |
| 2039 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { |
| 2040 continue; |
| 2041 } |
| 2042 } |
| 2043 #if DEBUG_CONCIDENT |
| 2044 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, t
estOther->fID, |
| 2045 oTest->fOtherT, tTest->fT); |
| 2046 #endif |
| 2047 if (tTest->fT < oTest->fOtherT) { |
| 2048 addTCoincident(span.fPt, next->fPt, next->fT, testOther); |
| 2049 } else { |
| 2050 addTCancel(span.fPt, next->fPt, testOther); |
| 2051 } |
| 2052 MissingSpan missing; |
| 2053 missing.fSegment = testOther; |
| 2054 checkMultiple->push_back(missing); |
| 2055 break; |
| 2056 } |
| 2057 } |
| 2058 oTest = &oSpan; |
| 2059 while (++oTest < other->fTs.end()) { |
| 2060 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)
) { |
| 2061 break; |
| 2062 } |
| 2063 |
| 2064 } |
| 2065 } |
| 2066 } |
| 2067 |
1337 // if pair of spans on either side of tiny have the same end point and mid point
, mark | 2068 // if pair of spans on either side of tiny have the same end point and mid point
, mark |
1338 // them as parallel | 2069 // them as parallel |
1339 // OPTIMIZATION : mark the segment to note that some span is tiny | |
1340 void SkOpSegment::checkTiny() { | 2070 void SkOpSegment::checkTiny() { |
1341 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; | 2071 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
1342 SkOpSpan* thisSpan = fTs.begin() - 1; | 2072 SkOpSpan* thisSpan = fTs.begin() - 1; |
1343 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny | 2073 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny |
1344 while (++thisSpan < endSpan) { | 2074 while (++thisSpan < endSpan) { |
1345 if (!thisSpan->fTiny) { | 2075 if (!thisSpan->fTiny) { |
1346 continue; | 2076 continue; |
1347 } | 2077 } |
1348 SkOpSpan* nextSpan = thisSpan + 1; | 2078 SkOpSpan* nextSpan = thisSpan + 1; |
1349 double thisT = thisSpan->fT; | 2079 double thisT = thisSpan->fT; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1394 missing.fPt = thisSpan->fPt; | 2124 missing.fPt = thisSpan->fPt; |
1395 } | 2125 } |
1396 } | 2126 } |
1397 } | 2127 } |
1398 int missingCount = missingSpans.count(); | 2128 int missingCount = missingSpans.count(); |
1399 if (!missingCount) { | 2129 if (!missingCount) { |
1400 return; | 2130 return; |
1401 } | 2131 } |
1402 for (int index = 0; index < missingCount; ++index) { | 2132 for (int index = 0; index < missingCount; ++index) { |
1403 MissingSpan& missing = missingSpans[index]; | 2133 MissingSpan& missing = missingSpans[index]; |
1404 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT,
false, missing.fPt); | 2134 if (missing.fSegment != missing.fOther) { |
| 2135 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOthe
rT, false, |
| 2136 missing.fPt); |
| 2137 } |
1405 } | 2138 } |
| 2139 // OPTIMIZE: consolidate to avoid multiple calls to fix index |
1406 for (int index = 0; index < missingCount; ++index) { | 2140 for (int index = 0; index < missingCount; ++index) { |
1407 MissingSpan& missing = missingSpans[index]; | 2141 MissingSpan& missing = missingSpans[index]; |
1408 missing.fSegment->fixOtherTIndex(); | 2142 missing.fSegment->fixOtherTIndex(); |
1409 missing.fOther->fixOtherTIndex(); | 2143 missing.fOther->fixOtherTIndex(); |
1410 } | 2144 } |
1411 } | 2145 } |
1412 | 2146 |
1413 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* o
ther, int oStart, | 2147 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* o
ther, int oStart, |
1414 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) cons
t { | 2148 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) cons
t { |
1415 SkASSERT(span->fT == 0 || span->fT == 1); | 2149 SkASSERT(span->fT == 0 || span->fT == 1); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1467 return false; | 2201 return false; |
1468 } | 2202 } |
1469 if (otherSpan == lastSpan) { | 2203 if (otherSpan == lastSpan) { |
1470 break; | 2204 break; |
1471 } | 2205 } |
1472 otherSpan += step; | 2206 otherSpan += step; |
1473 } while (otherSpan->fT == refT || otherSpan->fPt == refPt); | 2207 } while (otherSpan->fT == refT || otherSpan->fPt == refPt); |
1474 return false; | 2208 return false; |
1475 } | 2209 } |
1476 | 2210 |
| 2211 int SkOpSegment::findEndSpan(int endIndex) const { |
| 2212 const SkOpSpan* span = &fTs[--endIndex]; |
| 2213 const SkPoint& lastPt = span->fPt; |
| 2214 double endT = span->fT; |
| 2215 do { |
| 2216 span = &fTs[--endIndex]; |
| 2217 } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == end
T || span->fTiny)); |
| 2218 return endIndex + 1; |
| 2219 } |
| 2220 |
1477 /* | 2221 /* |
1478 The M and S variable name parts stand for the operators. | 2222 The M and S variable name parts stand for the operators. |
1479 Mi stands for Minuend (see wiki subtraction, analogous to difference) | 2223 Mi stands for Minuend (see wiki subtraction, analogous to difference) |
1480 Su stands for Subtrahend | 2224 Su stands for Subtrahend |
1481 The Opp variable name part designates that the value is for the Opposite operat
or. | 2225 The Opp variable name part designates that the value is for the Opposite operat
or. |
1482 Opposite values result from combining coincident spans. | 2226 Opposite values result from combining coincident spans. |
1483 */ | 2227 */ |
1484 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
, int* nextEnd, | 2228 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
, int* nextEnd, |
1485 bool* unsortable, SkPathOp op, const int xo
rMiMask, | 2229 bool* unsortable, SkPathOp op, const int xo
rMiMask, |
1486 const int xorSuMask) { | 2230 const int xorSuMask) { |
(...skipping 25 matching lines...) Expand all Loading... |
1512 do { | 2256 do { |
1513 *nextEnd += step; | 2257 *nextEnd += step; |
1514 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | 2258 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
1515 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 2259 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
1516 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { | 2260 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { |
1517 *unsortable = true; | 2261 *unsortable = true; |
1518 return NULL; | 2262 return NULL; |
1519 } | 2263 } |
1520 return other; | 2264 return other; |
1521 } | 2265 } |
1522 // more than one viable candidate -- measure angles to find best | |
1523 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | |
1524 SkASSERT(startIndex - endIndex != 0); | 2266 SkASSERT(startIndex - endIndex != 0); |
1525 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 2267 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1526 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 2268 // more than one viable candidate -- measure angles to find best |
1527 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles
, &sorted); | 2269 |
| 2270 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp); |
1528 bool sortable = calcWinding != SK_NaN32; | 2271 bool sortable = calcWinding != SK_NaN32; |
1529 if (sortable && sorted.count() == 0) { | |
1530 // if no edge has a computed winding sum, we can go no further | |
1531 *unsortable = true; | |
1532 return NULL; | |
1533 } | |
1534 int angleCount = angles.count(); | |
1535 int firstIndex = findStartingEdge(sorted, startIndex, end); | |
1536 SkASSERT(!sortable || firstIndex >= 0); | |
1537 #if DEBUG_SORT | |
1538 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | |
1539 #endif | |
1540 if (!sortable) { | 2272 if (!sortable) { |
1541 *unsortable = true; | 2273 *unsortable = true; |
1542 return NULL; | 2274 return NULL; |
1543 } | 2275 } |
1544 SkASSERT(sorted[firstIndex]->segment() == this); | 2276 SkOpAngle* angle = spanToAngle(end, startIndex); |
1545 #if DEBUG_WINDING | 2277 if (angle->unorderable()) { |
1546 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, | 2278 *unsortable = true; |
1547 sorted[firstIndex]->sign()); | 2279 return NULL; |
| 2280 } |
| 2281 #if DEBUG_SORT |
| 2282 SkDebugf("%s\n", __FUNCTION__); |
| 2283 angle->debugLoop(); |
1548 #endif | 2284 #endif |
1549 int sumMiWinding = updateWinding(endIndex, startIndex); | 2285 int sumMiWinding = updateWinding(endIndex, startIndex); |
1550 int sumSuWinding = updateOppWinding(endIndex, startIndex); | 2286 int sumSuWinding = updateOppWinding(endIndex, startIndex); |
1551 if (operand()) { | 2287 if (operand()) { |
1552 SkTSwap<int>(sumMiWinding, sumSuWinding); | 2288 SkTSwap<int>(sumMiWinding, sumSuWinding); |
1553 } | 2289 } |
1554 int nextIndex = firstIndex + 1; | 2290 SkOpAngle* nextAngle = angle->next(); |
1555 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
1556 const SkOpAngle* foundAngle = NULL; | 2291 const SkOpAngle* foundAngle = NULL; |
1557 bool foundDone = false; | 2292 bool foundDone = false; |
1558 // iterate through the angle, and compute everyone's winding | 2293 // iterate through the angle, and compute everyone's winding |
1559 SkOpSegment* nextSegment; | 2294 SkOpSegment* nextSegment; |
1560 int activeCount = 0; | 2295 int activeCount = 0; |
1561 do { | 2296 do { |
1562 SkASSERT(nextIndex != firstIndex); | |
1563 if (nextIndex == angleCount) { | |
1564 nextIndex = 0; | |
1565 } | |
1566 const SkOpAngle* nextAngle = sorted[nextIndex]; | |
1567 nextSegment = nextAngle->segment(); | 2297 nextSegment = nextAngle->segment(); |
1568 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; | |
1569 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), | 2298 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle
->start(), |
1570 nextAngle->end(), op, &sumMiWinding, &sumSuWinding, | 2299 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); |
1571 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | |
1572 if (activeAngle) { | 2300 if (activeAngle) { |
1573 ++activeCount; | 2301 ++activeCount; |
1574 if (!foundAngle || (foundDone && activeCount & 1)) { | 2302 if (!foundAngle || (foundDone && activeCount & 1)) { |
1575 if (nextSegment->isTiny(nextAngle)) { | 2303 if (nextSegment->isTiny(nextAngle)) { |
1576 *unsortable = true; | 2304 *unsortable = true; |
1577 return NULL; | 2305 return NULL; |
1578 } | 2306 } |
1579 foundAngle = nextAngle; | 2307 foundAngle = nextAngle; |
1580 foundDone = nextSegment->done(nextAngle); | 2308 foundDone = nextSegment->done(nextAngle); |
1581 } | 2309 } |
1582 } | 2310 } |
1583 if (nextSegment->done()) { | 2311 if (nextSegment->done()) { |
1584 continue; | 2312 continue; |
1585 } | 2313 } |
1586 if (nextSegment->isTiny(nextAngle)) { | 2314 if (nextSegment->isTiny(nextAngle)) { |
1587 continue; | 2315 continue; |
1588 } | 2316 } |
1589 if (!activeAngle) { | 2317 if (!activeAngle) { |
1590 nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->e
nd()); | 2318 nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->e
nd()); |
1591 } | 2319 } |
1592 SkOpSpan* last = nextAngle->lastMarked(); | 2320 SkOpSpan* last = nextAngle->lastMarked(); |
1593 if (last) { | 2321 if (last) { |
| 2322 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); |
1594 *chase->append() = last; | 2323 *chase->append() = last; |
1595 #if DEBUG_WINDING | 2324 #if DEBUG_WINDING |
1596 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, | 2325 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, |
1597 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, | 2326 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, |
1598 last->fSmall); | 2327 last->fSmall); |
1599 #endif | 2328 #endif |
1600 } | 2329 } |
1601 } while (++nextIndex != lastIndex); | 2330 } while ((nextAngle = nextAngle->next()) != angle); |
| 2331 #if DEBUG_ANGLE |
| 2332 if (foundAngle) { |
| 2333 foundAngle->debugSameAs(foundAngle); |
| 2334 } |
| 2335 #endif |
| 2336 |
1602 markDoneBinary(SkMin32(startIndex, endIndex)); | 2337 markDoneBinary(SkMin32(startIndex, endIndex)); |
1603 if (!foundAngle) { | 2338 if (!foundAngle) { |
1604 return NULL; | 2339 return NULL; |
1605 } | 2340 } |
1606 *nextStart = foundAngle->start(); | 2341 *nextStart = foundAngle->start(); |
1607 *nextEnd = foundAngle->end(); | 2342 *nextEnd = foundAngle->end(); |
1608 nextSegment = foundAngle->segment(); | 2343 nextSegment = foundAngle->segment(); |
1609 #if DEBUG_WINDING | 2344 #if DEBUG_WINDING |
1610 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 2345 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
1611 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 2346 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1643 do { | 2378 do { |
1644 *nextEnd += step; | 2379 *nextEnd += step; |
1645 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | 2380 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
1646 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 2381 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
1647 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { | 2382 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { |
1648 *unsortable = true; | 2383 *unsortable = true; |
1649 return NULL; | 2384 return NULL; |
1650 } | 2385 } |
1651 return other; | 2386 return other; |
1652 } | 2387 } |
1653 // more than one viable candidate -- measure angles to find best | |
1654 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | |
1655 SkASSERT(startIndex - endIndex != 0); | 2388 SkASSERT(startIndex - endIndex != 0); |
1656 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 2389 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1657 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 2390 // more than one viable candidate -- measure angles to find best |
1658 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding, &ang
les, &sorted); | 2391 |
| 2392 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding); |
1659 bool sortable = calcWinding != SK_NaN32; | 2393 bool sortable = calcWinding != SK_NaN32; |
1660 int angleCount = angles.count(); | |
1661 int firstIndex = findStartingEdge(sorted, startIndex, end); | |
1662 SkASSERT(!sortable || firstIndex >= 0); | |
1663 #if DEBUG_SORT | |
1664 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | |
1665 #endif | |
1666 if (!sortable) { | 2394 if (!sortable) { |
1667 *unsortable = true; | 2395 *unsortable = true; |
1668 return NULL; | 2396 return NULL; |
1669 } | 2397 } |
1670 SkASSERT(sorted[firstIndex]->segment() == this); | 2398 SkOpAngle* angle = spanToAngle(end, startIndex); |
1671 #if DEBUG_WINDING | 2399 #if DEBUG_SORT |
1672 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, | 2400 SkDebugf("%s\n", __FUNCTION__); |
1673 sorted[firstIndex]->sign()); | 2401 angle->debugLoop(); |
1674 #endif | 2402 #endif |
1675 int sumWinding = updateWinding(endIndex, startIndex); | 2403 int sumWinding = updateWinding(endIndex, startIndex); |
1676 int nextIndex = firstIndex + 1; | 2404 SkOpAngle* nextAngle = angle->next(); |
1677 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
1678 const SkOpAngle* foundAngle = NULL; | 2405 const SkOpAngle* foundAngle = NULL; |
1679 bool foundDone = false; | 2406 bool foundDone = false; |
1680 // iterate through the angle, and compute everyone's winding | |
1681 SkOpSegment* nextSegment; | 2407 SkOpSegment* nextSegment; |
1682 int activeCount = 0; | 2408 int activeCount = 0; |
1683 do { | 2409 do { |
1684 SkASSERT(nextIndex != firstIndex); | |
1685 if (nextIndex == angleCount) { | |
1686 nextIndex = 0; | |
1687 } | |
1688 const SkOpAngle* nextAngle = sorted[nextIndex]; | |
1689 nextSegment = nextAngle->segment(); | 2410 nextSegment = nextAngle->segment(); |
1690 int maxWinding; | |
1691 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), | 2411 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAn
gle->end(), |
1692 &maxWinding, &sumWinding); | 2412 &sumWinding); |
1693 if (activeAngle) { | 2413 if (activeAngle) { |
1694 ++activeCount; | 2414 ++activeCount; |
1695 if (!foundAngle || (foundDone && activeCount & 1)) { | 2415 if (!foundAngle || (foundDone && activeCount & 1)) { |
1696 if (nextSegment->isTiny(nextAngle)) { | 2416 if (nextSegment->isTiny(nextAngle)) { |
1697 *unsortable = true; | 2417 *unsortable = true; |
1698 return NULL; | 2418 return NULL; |
1699 } | 2419 } |
1700 foundAngle = nextAngle; | 2420 foundAngle = nextAngle; |
1701 foundDone = nextSegment->done(nextAngle); | 2421 foundDone = nextSegment->done(nextAngle); |
1702 } | 2422 } |
1703 } | 2423 } |
1704 if (nextSegment->done()) { | 2424 if (nextSegment->done()) { |
1705 continue; | 2425 continue; |
1706 } | 2426 } |
1707 if (nextSegment->isTiny(nextAngle)) { | 2427 if (nextSegment->isTiny(nextAngle)) { |
1708 continue; | 2428 continue; |
1709 } | 2429 } |
1710 if (!activeAngle) { | 2430 if (!activeAngle) { |
1711 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->en
d()); | 2431 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->en
d()); |
1712 } | 2432 } |
1713 SkOpSpan* last = nextAngle->lastMarked(); | 2433 SkOpSpan* last = nextAngle->lastMarked(); |
1714 if (last) { | 2434 if (last) { |
| 2435 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); |
| 2436 // assert here that span isn't already in array |
1715 *chase->append() = last; | 2437 *chase->append() = last; |
1716 #if DEBUG_WINDING | 2438 #if DEBUG_WINDING |
1717 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, | 2439 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, |
1718 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, | 2440 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, |
1719 last->fSmall); | 2441 last->fSmall); |
1720 #endif | 2442 #endif |
1721 } | 2443 } |
1722 } while (++nextIndex != lastIndex); | 2444 } while ((nextAngle = nextAngle->next()) != angle); |
1723 markDoneUnary(SkMin32(startIndex, endIndex)); | 2445 markDoneUnary(SkMin32(startIndex, endIndex)); |
1724 if (!foundAngle) { | 2446 if (!foundAngle) { |
1725 return NULL; | 2447 return NULL; |
1726 } | 2448 } |
1727 *nextStart = foundAngle->start(); | 2449 *nextStart = foundAngle->start(); |
1728 *nextEnd = foundAngle->end(); | 2450 *nextEnd = foundAngle->end(); |
1729 nextSegment = foundAngle->segment(); | 2451 nextSegment = foundAngle->segment(); |
1730 #if DEBUG_WINDING | 2452 #if DEBUG_WINDING |
1731 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 2453 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
1732 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 2454 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
1733 #endif | 2455 #endif |
1734 return nextSegment; | 2456 return nextSegment; |
1735 } | 2457 } |
1736 | 2458 |
1737 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
able) { | 2459 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
able) { |
1738 const int startIndex = *nextStart; | 2460 const int startIndex = *nextStart; |
1739 const int endIndex = *nextEnd; | 2461 const int endIndex = *nextEnd; |
1740 SkASSERT(startIndex != endIndex); | 2462 SkASSERT(startIndex != endIndex); |
1741 SkDEBUGCODE(int count = fTs.count()); | 2463 SkDEBUGCODE(int count = fTs.count()); |
1742 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); | 2464 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); |
1743 int step = SkSign32(endIndex - startIndex); | 2465 int step = SkSign32(endIndex - startIndex); |
1744 int end = nextExactSpan(startIndex, step); | 2466 int end = nextExactSpan(startIndex, step); |
1745 SkASSERT(end >= 0); | 2467 SkASSERT(end >= 0); |
1746 SkOpSpan* endSpan = &fTs[end]; | 2468 SkOpSpan* endSpan = &fTs[end]; |
1747 SkOpSegment* other; | 2469 SkOpSegment* other; |
1748 if (isSimple(end)) { | 2470 // Detect cases where all the ends canceled out (e.g., |
| 2471 // there is no angle) and therefore there's only one valid connection |
| 2472 if (isSimple(end) || !spanToAngle(end, startIndex)) { |
1749 #if DEBUG_WINDING | 2473 #if DEBUG_WINDING |
1750 SkDebugf("%s simple\n", __FUNCTION__); | 2474 SkDebugf("%s simple\n", __FUNCTION__); |
1751 #endif | 2475 #endif |
1752 int min = SkMin32(startIndex, endIndex); | 2476 int min = SkMin32(startIndex, endIndex); |
1753 if (fTs[min].fDone) { | 2477 if (fTs[min].fDone) { |
1754 return NULL; | 2478 return NULL; |
1755 } | 2479 } |
1756 markDone(min, 1); | 2480 markDone(min, 1); |
1757 other = endSpan->fOther; | 2481 other = endSpan->fOther; |
1758 *nextStart = endSpan->fOtherIndex; | 2482 *nextStart = endSpan->fOtherIndex; |
(...skipping 13 matching lines...) Expand all Loading... |
1772 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { | 2496 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { |
1773 break; | 2497 break; |
1774 } | 2498 } |
1775 SkASSERT(firstLoop); | 2499 SkASSERT(firstLoop); |
1776 SkDEBUGCODE(firstLoop = false;) | 2500 SkDEBUGCODE(firstLoop = false;) |
1777 step = -step; | 2501 step = -step; |
1778 } while (true); | 2502 } while (true); |
1779 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 2503 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
1780 return other; | 2504 return other; |
1781 } | 2505 } |
1782 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | |
1783 SkASSERT(startIndex - endIndex != 0); | 2506 SkASSERT(startIndex - endIndex != 0); |
1784 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 2507 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1785 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 2508 // parallel block above with presorted version |
1786 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryXor, &angles,
&sorted); | 2509 SkOpAngle* angle = spanToAngle(end, startIndex); |
1787 bool sortable = calcWinding != SK_NaN32; | 2510 SkASSERT(angle); |
1788 int angleCount = angles.count(); | |
1789 int firstIndex = findStartingEdge(sorted, startIndex, end); | |
1790 SkASSERT(!sortable || firstIndex >= 0); | |
1791 #if DEBUG_SORT | 2511 #if DEBUG_SORT |
1792 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable); | 2512 SkDebugf("%s\n", __FUNCTION__); |
| 2513 angle->debugLoop(); |
1793 #endif | 2514 #endif |
1794 if (!sortable) { | 2515 SkOpAngle* nextAngle = angle->next(); |
1795 *unsortable = true; | |
1796 return NULL; | |
1797 } | |
1798 SkASSERT(sorted[firstIndex]->segment() == this); | |
1799 #if DEBUG_WINDING | |
1800 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, | |
1801 sorted[firstIndex]->sign()); | |
1802 #endif | |
1803 int nextIndex = firstIndex + 1; | |
1804 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
1805 const SkOpAngle* foundAngle = NULL; | 2516 const SkOpAngle* foundAngle = NULL; |
1806 bool foundDone = false; | 2517 bool foundDone = false; |
1807 SkOpSegment* nextSegment; | 2518 SkOpSegment* nextSegment; |
1808 int activeCount = 0; | 2519 int activeCount = 0; |
1809 do { | 2520 do { |
1810 SkASSERT(nextIndex != firstIndex); | |
1811 if (nextIndex == angleCount) { | |
1812 nextIndex = 0; | |
1813 } | |
1814 const SkOpAngle* nextAngle = sorted[nextIndex]; | |
1815 nextSegment = nextAngle->segment(); | 2521 nextSegment = nextAngle->segment(); |
1816 ++activeCount; | 2522 ++activeCount; |
1817 if (!foundAngle || (foundDone && activeCount & 1)) { | 2523 if (!foundAngle || (foundDone && activeCount & 1)) { |
1818 if (nextSegment->isTiny(nextAngle)) { | 2524 if (nextSegment->isTiny(nextAngle)) { |
1819 *unsortable = true; | 2525 *unsortable = true; |
1820 return NULL; | 2526 return NULL; |
1821 } | 2527 } |
1822 foundAngle = nextAngle; | 2528 foundAngle = nextAngle; |
1823 foundDone = nextSegment->done(nextAngle); | 2529 if (!(foundDone = nextSegment->done(nextAngle))) { |
| 2530 break; |
| 2531 } |
1824 } | 2532 } |
1825 if (nextSegment->done()) { | 2533 nextAngle = nextAngle->next(); |
1826 continue; | 2534 } while (nextAngle != angle); |
1827 } | |
1828 } while (++nextIndex != lastIndex); | |
1829 markDone(SkMin32(startIndex, endIndex), 1); | 2535 markDone(SkMin32(startIndex, endIndex), 1); |
1830 if (!foundAngle) { | 2536 if (!foundAngle) { |
1831 return NULL; | 2537 return NULL; |
1832 } | 2538 } |
1833 *nextStart = foundAngle->start(); | 2539 *nextStart = foundAngle->start(); |
1834 *nextEnd = foundAngle->end(); | 2540 *nextEnd = foundAngle->end(); |
1835 nextSegment = foundAngle->segment(); | 2541 nextSegment = foundAngle->segment(); |
1836 #if DEBUG_WINDING | 2542 #if DEBUG_WINDING |
1837 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 2543 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
1838 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 2544 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
1839 #endif | 2545 #endif |
1840 return nextSegment; | 2546 return nextSegment; |
1841 } | 2547 } |
1842 | 2548 |
1843 int SkOpSegment::findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int
start, int end) { | 2549 int SkOpSegment::findStartSpan(int startIndex) const { |
1844 int angleCount = sorted.count(); | 2550 int index = startIndex; |
1845 int firstIndex = -1; | 2551 const SkOpSpan* span = &fTs[index]; |
1846 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2552 const SkPoint& firstPt = span->fPt; |
1847 const SkOpAngle* angle = sorted[angleIndex]; | 2553 double firstT = span->fT; |
1848 if (angle->segment() == this && angle->start() == end && | 2554 do { |
1849 angle->end() == start) { | 2555 if (index > 0) { |
1850 firstIndex = angleIndex; | 2556 if (span->fT != firstT) { |
1851 break; | 2557 break; |
| 2558 } |
| 2559 if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) { |
| 2560 return -1; |
| 2561 } |
1852 } | 2562 } |
1853 } | 2563 ++index; |
1854 return firstIndex; | 2564 if (span->fTiny) { |
| 2565 if (!SkDPoint::ApproximatelyEqual(firstPt, fTs[index].fPt)) { |
| 2566 return -1; |
| 2567 } |
| 2568 firstT = fTs[index++].fT; |
| 2569 } |
| 2570 span = &fTs[index]; |
| 2571 } while (true); |
| 2572 return index; |
1855 } | 2573 } |
1856 | 2574 |
1857 int SkOpSegment::findT(double t, const SkOpSegment* match) const { | 2575 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const { |
1858 int count = this->count(); | 2576 int count = this->count(); |
1859 for (int index = 0; index < count; ++index) { | 2577 for (int index = 0; index < count; ++index) { |
1860 const SkOpSpan& span = fTs[index]; | 2578 const SkOpSpan& span = fTs[index]; |
1861 if (span.fT == t && span.fOther == match) { | 2579 if (span.fT == t && span.fOther == match) { |
1862 return index; | 2580 return index; |
1863 } | 2581 } |
1864 } | 2582 } |
1865 SkASSERT(0); | 2583 SkASSERT(0); |
1866 return -1; | 2584 return -1; |
1867 } | 2585 } |
1868 | 2586 |
1869 // FIXME: either: | 2587 int SkOpSegment::findT(double t, const SkOpSegment* match) const { |
1870 // a) mark spans with either end unsortable as done, or | 2588 int count = this->count(); |
1871 // b) rewrite findTop / findTopSegment / findTopContour to iterate further | 2589 for (int index = 0; index < count; ++index) { |
1872 // when encountering an unsortable span | 2590 const SkOpSpan& span = fTs[index]; |
| 2591 if (approximately_equal_orderable(span.fT, t) && span.fOther == match) { |
| 2592 return index; |
| 2593 } |
| 2594 } |
| 2595 SkASSERT(0); |
| 2596 return -1; |
| 2597 } |
1873 | 2598 |
1874 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) | 2599 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
able) { |
1875 // and use more concise logic like the old edge walker code? | |
1876 // FIXME: this needs to deal with coincident edges | |
1877 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
able, | |
1878 bool onlySortable) { | |
1879 // iterate through T intersections and return topmost | 2600 // iterate through T intersections and return topmost |
1880 // topmost tangent from y-min to first pt is closer to horizontal | 2601 // topmost tangent from y-min to first pt is closer to horizontal |
1881 SkASSERT(!done()); | 2602 SkASSERT(!done()); |
1882 int firstT = -1; | 2603 int firstT = -1; |
1883 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT); | 2604 /* SkPoint topPt = */ activeLeftTop(true, &firstT); |
1884 if (firstT < 0) { | 2605 if (firstT < 0) { |
1885 *unsortable = true; | 2606 *unsortable = true; |
1886 firstT = 0; | 2607 firstT = 0; |
1887 while (fTs[firstT].fDone) { | 2608 while (fTs[firstT].fDone) { |
1888 SkASSERT(firstT < fTs.count()); | 2609 SkASSERT(firstT < fTs.count()); |
1889 ++firstT; | 2610 ++firstT; |
1890 } | 2611 } |
1891 *tIndexPtr = firstT; | 2612 *tIndexPtr = firstT; |
1892 *endIndexPtr = nextExactSpan(firstT, 1); | 2613 *endIndexPtr = nextExactSpan(firstT, 1); |
1893 return this; | 2614 return this; |
1894 } | 2615 } |
1895 // sort the edges to find the leftmost | 2616 // sort the edges to find the leftmost |
1896 int step = 1; | 2617 int step = 1; |
1897 int end = nextSpan(firstT, step); | 2618 int end; |
1898 if (end == -1) { | 2619 if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) { |
1899 step = -1; | 2620 step = -1; |
1900 end = nextSpan(firstT, step); | 2621 end = nextSpan(firstT, step); |
1901 SkASSERT(end != -1); | 2622 SkASSERT(end != -1); |
1902 } | 2623 } |
1903 // if the topmost T is not on end, or is three-way or more, find left | 2624 // if the topmost T is not on end, or is three-way or more, find left |
1904 // look for left-ness from tLeft to firstT (matching y of other) | 2625 // look for left-ness from tLeft to firstT (matching y of other) |
1905 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | |
1906 SkASSERT(firstT - end != 0); | 2626 SkASSERT(firstT - end != 0); |
1907 addTwoAngles(end, firstT, &angles); | 2627 SkOpAngle* markAngle = spanToAngle(firstT, end); |
1908 if (!buildAngles(firstT, &angles, true) && onlySortable) { | 2628 if (!markAngle) { |
1909 // *unsortable = true; | 2629 markAngle = addSingletonAngles(firstT, step); |
1910 // return NULL; | |
1911 } | 2630 } |
1912 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 2631 markAngle->markStops(); |
1913 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_Sor
tAngleKind); | 2632 const SkOpAngle* baseAngle = markAngle->findFirst(); |
1914 if (onlySortable && !sortable) { | 2633 if (!baseAngle) { |
1915 *unsortable = true; | 2634 return NULL; // nothing to do |
1916 return NULL; | |
1917 } | 2635 } |
1918 int first = SK_MaxS32; | |
1919 SkScalar top = SK_ScalarMax; | 2636 SkScalar top = SK_ScalarMax; |
1920 int count = sorted.count(); | 2637 const SkOpAngle* firstAngle = NULL; |
1921 for (int index = 0; index < count; ++index) { | 2638 const SkOpAngle* angle = baseAngle; |
1922 const SkOpAngle* angle = sorted[index]; | 2639 do { |
1923 if (onlySortable && angle->unorderable()) { | 2640 if (!angle->unorderable()) { |
1924 continue; | 2641 SkOpSegment* next = angle->segment(); |
| 2642 SkPathOpsBounds bounds; |
| 2643 next->subDivideBounds(angle->end(), angle->start(), &bounds); |
| 2644 if (approximately_greater(top, bounds.fTop)) { |
| 2645 top = bounds.fTop; |
| 2646 firstAngle = angle; |
| 2647 } |
1925 } | 2648 } |
1926 SkOpSegment* next = angle->segment(); | 2649 angle = angle->next(); |
1927 SkPathOpsBounds bounds; | 2650 } while (angle != baseAngle); |
1928 next->subDivideBounds(angle->end(), angle->start(), &bounds); | 2651 SkASSERT(firstAngle); |
1929 if (approximately_greater(top, bounds.fTop)) { | 2652 #if DEBUG_SORT |
1930 top = bounds.fTop; | 2653 SkDebugf("%s\n", __FUNCTION__); |
1931 first = index; | 2654 firstAngle->debugLoop(); |
1932 } | |
1933 } | |
1934 SkASSERT(first < SK_MaxS32); | |
1935 #if DEBUG_SORT // || DEBUG_SWAP_TOP | |
1936 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, s
ortable); | |
1937 #endif | 2655 #endif |
1938 // skip edges that have already been processed | 2656 // skip edges that have already been processed |
1939 firstT = first - 1; | 2657 angle = firstAngle; |
1940 SkOpSegment* leftSegment; | 2658 SkOpSegment* leftSegment; |
1941 do { | 2659 do { |
1942 if (++firstT == count) { | 2660 // SkASSERT(!angle->unsortable()); |
1943 firstT = 0; | |
1944 } | |
1945 const SkOpAngle* angle = sorted[firstT]; | |
1946 SkASSERT(!onlySortable || !angle->unsortable()); | |
1947 leftSegment = angle->segment(); | 2661 leftSegment = angle->segment(); |
1948 *tIndexPtr = angle->end(); | 2662 *tIndexPtr = angle->end(); |
1949 *endIndexPtr = angle->start(); | 2663 *endIndexPtr = angle->start(); |
| 2664 angle = angle->next(); |
1950 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone); | 2665 } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone); |
1951 if (leftSegment->verb() >= SkPath::kQuad_Verb) { | 2666 if (leftSegment->verb() >= SkPath::kQuad_Verb) { |
1952 const int tIndex = *tIndexPtr; | 2667 const int tIndex = *tIndexPtr; |
1953 const int endIndex = *endIndexPtr; | 2668 const int endIndex = *endIndexPtr; |
1954 if (!leftSegment->clockwise(tIndex, endIndex)) { | 2669 if (!leftSegment->clockwise(tIndex, endIndex)) { |
1955 bool swap = !leftSegment->monotonicInY(tIndex, endIndex) | 2670 bool swap = !leftSegment->monotonicInY(tIndex, endIndex) |
1956 && !leftSegment->serpentine(tIndex, endIndex); | 2671 && !leftSegment->serpentine(tIndex, endIndex); |
1957 #if DEBUG_SWAP_TOP | 2672 #if DEBUG_SWAP_TOP |
1958 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n
", __FUNCTION__, | 2673 SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n
", __FUNCTION__, |
1959 swap, | 2674 swap, |
1960 leftSegment->serpentine(tIndex, endIndex), | 2675 leftSegment->serpentine(tIndex, endIndex), |
1961 leftSegment->controlsContainedByEnds(tIndex, endIndex), | 2676 leftSegment->controlsContainedByEnds(tIndex, endIndex), |
1962 leftSegment->monotonicInY(tIndex, endIndex)); | 2677 leftSegment->monotonicInY(tIndex, endIndex)); |
1963 #endif | 2678 #endif |
1964 if (swap) { | 2679 if (swap) { |
1965 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | 2680 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first |
1966 // sorted but merely the first not already processed (i.e., not done) | 2681 // sorted but merely the first not already processed (i.e., not done) |
1967 SkTSwap(*tIndexPtr, *endIndexPtr); | 2682 SkTSwap(*tIndexPtr, *endIndexPtr); |
1968 } | 2683 } |
1969 } | 2684 } |
1970 } | 2685 } |
1971 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); | 2686 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); |
1972 return leftSegment; | 2687 return leftSegment; |
1973 } | 2688 } |
1974 | 2689 |
| 2690 int SkOpSegment::firstActive(int tIndex) const { |
| 2691 while (fTs[tIndex].fTiny) { |
| 2692 SkASSERT(!isCanceled(tIndex)); |
| 2693 ++tIndex; |
| 2694 } |
| 2695 return tIndex; |
| 2696 } |
| 2697 |
1975 // FIXME: not crazy about this | 2698 // FIXME: not crazy about this |
1976 // when the intersections are performed, the other index is into an | 2699 // when the intersections are performed, the other index is into an |
1977 // incomplete array. As the array grows, the indices become incorrect | 2700 // incomplete array. As the array grows, the indices become incorrect |
1978 // while the following fixes the indices up again, it isn't smart about | 2701 // while the following fixes the indices up again, it isn't smart about |
1979 // skipping segments whose indices are already correct | 2702 // skipping segments whose indices are already correct |
1980 // assuming we leave the code that wrote the index in the first place | 2703 // assuming we leave the code that wrote the index in the first place |
1981 // FIXME: if called after remove, this needs to correct tiny | 2704 // FIXME: if called after remove, this needs to correct tiny |
1982 void SkOpSegment::fixOtherTIndex() { | 2705 void SkOpSegment::fixOtherTIndex() { |
1983 int iCount = fTs.count(); | 2706 int iCount = fTs.count(); |
1984 for (int i = 0; i < iCount; ++i) { | 2707 for (int i = 0; i < iCount; ++i) { |
(...skipping 13 matching lines...) Expand all Loading... |
1998 SkASSERT(iSpan.fOtherIndex >= 0); | 2721 SkASSERT(iSpan.fOtherIndex >= 0); |
1999 } | 2722 } |
2000 } | 2723 } |
2001 | 2724 |
2002 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, boo
l evenOdd) { | 2725 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, boo
l evenOdd) { |
2003 fDoneSpans = 0; | 2726 fDoneSpans = 0; |
2004 fOperand = operand; | 2727 fOperand = operand; |
2005 fXor = evenOdd; | 2728 fXor = evenOdd; |
2006 fPts = pts; | 2729 fPts = pts; |
2007 fVerb = verb; | 2730 fVerb = verb; |
| 2731 fLoop = fSmall = fTiny = false; |
2008 } | 2732 } |
2009 | 2733 |
2010 void SkOpSegment::initWinding(int start, int end) { | 2734 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIn
cludeType) { |
2011 int local = spanSign(start, end); | 2735 int local = spanSign(start, end); |
2012 int oppLocal = oppSign(start, end); | 2736 if (angleIncludeType == SkOpAngle::kBinarySingle) { |
2013 (void) markAndChaseWinding(start, end, local, oppLocal); | 2737 int oppLocal = oppSign(start, end); |
| 2738 (void) markAndChaseWinding(start, end, local, oppLocal); |
2014 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 2739 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
2015 (void) markAndChaseWinding(end, start, local, oppLocal); | 2740 (void) markAndChaseWinding(end, start, local, oppLocal); |
| 2741 } else { |
| 2742 (void) markAndChaseWinding(start, end, local); |
| 2743 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 2744 (void) markAndChaseWinding(end, start, local); |
| 2745 } |
2016 } | 2746 } |
2017 | 2747 |
2018 /* | 2748 /* |
2019 when we start with a vertical intersect, we try to use the dx to determine if th
e edge is to | 2749 when we start with a vertical intersect, we try to use the dx to determine if th
e edge is to |
2020 the left or the right of vertical. This determines if we need to add the span's | 2750 the left or the right of vertical. This determines if we need to add the span's |
2021 sign or not. However, this isn't enough. | 2751 sign or not. However, this isn't enough. |
2022 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. | 2752 If the supplied sign (winding) is zero, then we didn't hit another vertical span
, so dx is needed. |
2023 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed | 2753 If there was a winding, then it may or may not need adjusting. If the span the w
inding was borrowed |
2024 from has the same x direction as this span, the winding should change. If the dx
is opposite, then | 2754 from has the same x direction as this span, the winding should change. If the dx
is opposite, then |
2025 the same winding is shared by both. | 2755 the same winding is shared by both. |
2026 */ | 2756 */ |
2027 void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc
alar hitDx, | 2757 void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkSc
alar hitDx, |
2028 int oppWind, SkScalar hitOppDx) { | 2758 int oppWind, SkScalar hitOppDx) { |
2029 SkASSERT(hitDx || !winding); | 2759 SkASSERT(hitDx || !winding); |
2030 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; | 2760 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; |
2031 SkASSERT(dx); | 2761 SkASSERT(dx); |
2032 int windVal = windValue(SkMin32(start, end)); | 2762 int windVal = windValue(SkMin32(start, end)); |
2033 #if DEBUG_WINDING_AT_T | 2763 #if DEBUG_WINDING_AT_T |
2034 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding
, | 2764 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding
, |
2035 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); | 2765 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); |
2036 #endif | 2766 #endif |
2037 if (!winding) { | 2767 int sideWind = winding + (dx < 0 ? windVal : -windVal); |
2038 winding = dx < 0 ? windVal : -windVal; | 2768 if (abs(winding) < abs(sideWind)) { |
2039 } else if (winding * dx < 0) { | 2769 winding = sideWind; |
2040 int sideWind = winding + (dx < 0 ? windVal : -windVal); | |
2041 if (abs(winding) < abs(sideWind)) { | |
2042 winding = sideWind; | |
2043 } | |
2044 } | 2770 } |
2045 #if DEBUG_WINDING_AT_T | 2771 #if DEBUG_WINDING_AT_T |
2046 SkDebugf(" winding=%d\n", winding); | 2772 SkDebugf(" winding=%d\n", winding); |
2047 #endif | 2773 #endif |
2048 SkDEBUGCODE(int oppLocal = oppSign(start, end)); | 2774 SkDEBUGCODE(int oppLocal = oppSign(start, end)); |
2049 SkASSERT(hitOppDx || !oppWind || !oppLocal); | 2775 SkASSERT(hitOppDx || !oppWind || !oppLocal); |
2050 int oppWindVal = oppValue(SkMin32(start, end)); | 2776 int oppWindVal = oppValue(SkMin32(start, end)); |
2051 if (!oppWind) { | 2777 if (!oppWind) { |
2052 oppWind = dx < 0 ? oppWindVal : -oppWindVal; | 2778 oppWind = dx < 0 ? oppWindVal : -oppWindVal; |
2053 } else if (hitOppDx * dx >= 0) { | 2779 } else if (hitOppDx * dx >= 0) { |
2054 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); | 2780 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); |
2055 if (abs(oppWind) < abs(oppSideWind)) { | 2781 if (abs(oppWind) < abs(oppSideWind)) { |
2056 oppWind = oppSideWind; | 2782 oppWind = oppSideWind; |
2057 } | 2783 } |
2058 } | 2784 } |
2059 (void) markAndChaseWinding(start, end, winding, oppWind); | 2785 (void) markAndChaseWinding(start, end, winding, oppWind); |
2060 // OPTIMIZATION: the reverse mark and chase could skip the first marking | 2786 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
2061 (void) markAndChaseWinding(end, start, winding, oppWind); | 2787 (void) markAndChaseWinding(end, start, winding, oppWind); |
2062 } | 2788 } |
2063 | 2789 |
| 2790 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPt
r) const { |
| 2791 if (!baseAngle->inLoop()) { |
| 2792 return false; |
| 2793 } |
| 2794 int index = *indexPtr; |
| 2795 int froIndex = fTs[index].fFromAngleIndex; |
| 2796 int toIndex = fTs[index].fToAngleIndex; |
| 2797 while (++index < spanCount) { |
| 2798 int nextFro = fTs[index].fFromAngleIndex; |
| 2799 int nextTo = fTs[index].fToAngleIndex; |
| 2800 if (froIndex != nextFro || toIndex != nextTo) { |
| 2801 break; |
| 2802 } |
| 2803 } |
| 2804 *indexPtr = index; |
| 2805 return true; |
| 2806 } |
| 2807 |
2064 // OPTIMIZE: successive calls could start were the last leaves off | 2808 // OPTIMIZE: successive calls could start were the last leaves off |
2065 // or calls could specialize to walk forwards or backwards | 2809 // or calls could specialize to walk forwards or backwards |
2066 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const { | 2810 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const { |
2067 size_t tCount = fTs.count(); | 2811 int tCount = fTs.count(); |
2068 for (size_t index = 0; index < tCount; ++index) { | 2812 for (int index = 0; index < tCount; ++index) { |
2069 const SkOpSpan& span = fTs[index]; | 2813 const SkOpSpan& span = fTs[index]; |
2070 if (approximately_zero(startT - span.fT) && pt == span.fPt) { | 2814 if (approximately_zero(startT - span.fT) && pt == span.fPt) { |
2071 return false; | 2815 return false; |
2072 } | 2816 } |
2073 } | 2817 } |
2074 return true; | 2818 return true; |
2075 } | 2819 } |
2076 | 2820 |
2077 bool SkOpSegment::isSimple(int end) const { | 2821 bool SkOpSegment::isSimple(int end) const { |
| 2822 #if 1 |
2078 int count = fTs.count(); | 2823 int count = fTs.count(); |
2079 if (count == 2) { | 2824 if (count == 2) { |
2080 return true; | 2825 return true; |
2081 } | 2826 } |
2082 double t = fTs[end].fT; | 2827 double t = fTs[end].fT; |
2083 if (approximately_less_than_zero(t)) { | 2828 if (approximately_less_than_zero(t)) { |
2084 return !approximately_less_than_zero(fTs[1].fT); | 2829 return !approximately_less_than_zero(fTs[1].fT); |
2085 } | 2830 } |
2086 if (approximately_greater_than_one(t)) { | 2831 if (approximately_greater_than_one(t)) { |
2087 return !approximately_greater_than_one(fTs[count - 2].fT); | 2832 return !approximately_greater_than_one(fTs[count - 2].fT); |
2088 } | 2833 } |
2089 return false; | 2834 return false; |
| 2835 #else |
| 2836 // OPTIMIZE: code could be rejiggered to use this simpler test. To make this
work, a little |
| 2837 // more logic is required to ignore the dangling canceled out spans |
| 2838 const SkOpSpan& span = fTs[end]; |
| 2839 return span.fFromAngleIndex < 0 && span.fToAngleIndex < 0; |
| 2840 #endif |
| 2841 } |
| 2842 |
| 2843 bool SkOpSegment::isSmall(const SkOpAngle* angle) const { |
| 2844 int start = angle->start(); |
| 2845 int end = angle->end(); |
| 2846 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; |
| 2847 return mSpan.fSmall; |
2090 } | 2848 } |
2091 | 2849 |
2092 bool SkOpSegment::isTiny(const SkOpAngle* angle) const { | 2850 bool SkOpSegment::isTiny(const SkOpAngle* angle) const { |
2093 int start = angle->start(); | 2851 int start = angle->start(); |
2094 int end = angle->end(); | 2852 int end = angle->end(); |
2095 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; | 2853 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; |
2096 return mSpan.fTiny; | 2854 return mSpan.fTiny; |
2097 } | 2855 } |
2098 | 2856 |
2099 bool SkOpSegment::isTiny(int index) const { | 2857 bool SkOpSegment::isTiny(int index) const { |
2100 return fTs[index].fTiny; | 2858 return fTs[index].fTiny; |
2101 } | 2859 } |
2102 | 2860 |
2103 // look pair of active edges going away from coincident edge | 2861 // look pair of active edges going away from coincident edge |
2104 // one of them should be the continuation of other | 2862 // one of them should be the continuation of other |
2105 // if both are active, look to see if they both the connect to another coinciden
t pair | 2863 // if both are active, look to see if they both the connect to another coinciden
t pair |
2106 // if one at least one is a line, then make the pair coincident | 2864 // if at least one is a line, then make the pair coincident |
2107 // if neither is a line, test for coincidence | 2865 // if neither is a line, test for coincidence |
2108 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, | 2866 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, b
ool cancel) { |
2109 bool cancel) { | |
2110 int otherTIndex = other->findT(otherT, this); | 2867 int otherTIndex = other->findT(otherT, this); |
2111 int next = other->nextExactSpan(otherTIndex, step); | 2868 int next = other->nextExactSpan(otherTIndex, step); |
2112 int otherMin = SkTMin(otherTIndex, next); | 2869 int otherMin = SkMin32(otherTIndex, next); |
2113 int otherWind = other->span(otherMin).fWindValue; | 2870 int otherWind = other->span(otherMin).fWindValue; |
2114 if (otherWind == 0) { | 2871 if (otherWind == 0) { |
2115 return false; | 2872 return false; |
2116 } | 2873 } |
2117 SkASSERT(next >= 0); | 2874 SkASSERT(next >= 0); |
2118 int tIndex = 0; | 2875 int tIndex = 0; |
2119 do { | 2876 do { |
2120 SkOpSpan* test = &fTs[tIndex]; | 2877 SkOpSpan* test = &fTs[tIndex]; |
2121 SkASSERT(test->fT == 0); | 2878 SkASSERT(test->fT == 0); |
2122 if (test->fOther == other || test->fOtherT != 1) { | 2879 if (test->fOther == other || test->fOtherT != 1) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2164 SkOpSegment* other = this; | 2921 SkOpSegment* other = this; |
2165 while ((other = other->nextChase(&index, step, &min, &last))) { | 2922 while ((other = other->nextChase(&index, step, &min, &last))) { |
2166 if (other->done()) { | 2923 if (other->done()) { |
2167 return NULL; | 2924 return NULL; |
2168 } | 2925 } |
2169 other->markDoneUnary(min); | 2926 other->markDoneUnary(min); |
2170 } | 2927 } |
2171 return last; | 2928 return last; |
2172 } | 2929 } |
2173 | 2930 |
2174 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, const int win
ding) { | 2931 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding)
{ |
2175 int index = angle->start(); | 2932 int index = angle->start(); |
2176 int endIndex = angle->end(); | 2933 int endIndex = angle->end(); |
2177 int step = SkSign32(endIndex - index); | 2934 int step = SkSign32(endIndex - index); |
2178 int min = SkMin32(index, endIndex); | 2935 int min = SkMin32(index, endIndex); |
2179 markWinding(min, winding); | 2936 markWinding(min, winding); |
2180 SkOpSpan* last; | 2937 SkOpSpan* last; |
2181 SkOpSegment* other = this; | 2938 SkOpSegment* other = this; |
2182 while ((other = other->nextChase(&index, step, &min, &last))) { | 2939 while ((other = other->nextChase(&index, step, &min, &last))) { |
2183 if (other->fTs[min].fWindSum != SK_MinS32) { | 2940 if (other->fTs[min].fWindSum != SK_MinS32) { |
2184 SkASSERT(other->fTs[min].fWindSum == winding); | 2941 SkASSERT(other->fTs[min].fWindSum == winding); |
2185 return NULL; | 2942 return NULL; |
2186 } | 2943 } |
2187 other->markWinding(min, winding); | 2944 other->markWinding(min, winding); |
2188 } | 2945 } |
2189 return last; | 2946 return last; |
2190 } | 2947 } |
2191 | 2948 |
| 2949 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding)
{ |
| 2950 int min = SkMin32(index, endIndex); |
| 2951 int step = SkSign32(endIndex - index); |
| 2952 markWinding(min, winding); |
| 2953 SkOpSpan* last; |
| 2954 SkOpSegment* other = this; |
| 2955 while ((other = other->nextChase(&index, step, &min, &last))) { |
| 2956 if (other->fTs[min].fWindSum != SK_MinS32) { |
| 2957 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoo
p); |
| 2958 return NULL; |
| 2959 } |
| 2960 other->markWinding(min, winding); |
| 2961 } |
| 2962 return last; |
| 2963 } |
| 2964 |
2192 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding,
int oppWinding) { | 2965 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding,
int oppWinding) { |
2193 int min = SkMin32(index, endIndex); | 2966 int min = SkMin32(index, endIndex); |
2194 int step = SkSign32(endIndex - index); | 2967 int step = SkSign32(endIndex - index); |
2195 markWinding(min, winding, oppWinding); | 2968 markWinding(min, winding, oppWinding); |
2196 SkOpSpan* last; | 2969 SkOpSpan* last; |
2197 SkOpSegment* other = this; | 2970 SkOpSegment* other = this; |
2198 while ((other = other->nextChase(&index, step, &min, &last))) { | 2971 while ((other = other->nextChase(&index, step, &min, &last))) { |
2199 if (other->fTs[min].fWindSum != SK_MinS32) { | 2972 if (other->fTs[min].fWindSum != SK_MinS32) { |
2200 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoo
p); | 2973 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoo
p); |
2201 return NULL; | 2974 return NULL; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2258 // SkASSERT(!done()); | 3031 // SkASSERT(!done()); |
2259 SkASSERT(winding); | 3032 SkASSERT(winding); |
2260 double referenceT = fTs[index].fT; | 3033 double referenceT = fTs[index].fT; |
2261 int lesser = index; | 3034 int lesser = index; |
2262 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 3035 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { |
2263 markOneDone(__FUNCTION__, lesser, winding); | 3036 markOneDone(__FUNCTION__, lesser, winding); |
2264 } | 3037 } |
2265 do { | 3038 do { |
2266 markOneDone(__FUNCTION__, index, winding); | 3039 markOneDone(__FUNCTION__, index, winding); |
2267 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | 3040 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); |
| 3041 debugValidate(); |
2268 } | 3042 } |
2269 | 3043 |
2270 void SkOpSegment::markDoneBinary(int index) { | 3044 void SkOpSegment::markDoneBinary(int index) { |
2271 double referenceT = fTs[index].fT; | 3045 double referenceT = fTs[index].fT; |
2272 int lesser = index; | 3046 int lesser = index; |
2273 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 3047 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { |
2274 markOneDoneBinary(__FUNCTION__, lesser); | 3048 markOneDoneBinary(__FUNCTION__, lesser); |
2275 } | 3049 } |
2276 do { | 3050 do { |
2277 markOneDoneBinary(__FUNCTION__, index); | 3051 markOneDoneBinary(__FUNCTION__, index); |
2278 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | 3052 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); |
| 3053 debugValidate(); |
2279 } | 3054 } |
2280 | 3055 |
2281 void SkOpSegment::markDoneUnary(int index) { | 3056 void SkOpSegment::markDoneUnary(int index) { |
2282 double referenceT = fTs[index].fT; | 3057 double referenceT = fTs[index].fT; |
2283 int lesser = index; | 3058 int lesser = index; |
2284 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 3059 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { |
2285 markOneDoneUnary(__FUNCTION__, lesser); | 3060 markOneDoneUnary(__FUNCTION__, lesser); |
2286 } | 3061 } |
2287 do { | 3062 do { |
2288 markOneDoneUnary(__FUNCTION__, index); | 3063 markOneDoneUnary(__FUNCTION__, index); |
2289 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); | 3064 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referen
ceT)); |
| 3065 debugValidate(); |
2290 } | 3066 } |
2291 | 3067 |
2292 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) { | 3068 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) { |
2293 SkOpSpan* span = markOneWinding(funName, tIndex, winding); | 3069 SkOpSpan* span = markOneWinding(funName, tIndex, winding); |
2294 if (!span) { | 3070 if (!span || span->fDone) { |
2295 return; | 3071 return; |
2296 } | 3072 } |
2297 span->fDone = true; | 3073 span->fDone = true; |
2298 fDoneSpans++; | 3074 fDoneSpans++; |
2299 } | 3075 } |
2300 | 3076 |
2301 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) { | 3077 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) { |
2302 SkOpSpan* span = verifyOneWinding(funName, tIndex); | 3078 SkOpSpan* span = verifyOneWinding(funName, tIndex); |
2303 if (!span) { | 3079 if (!span) { |
2304 return; | 3080 return; |
2305 } | 3081 } |
| 3082 SkASSERT(!span->fDone); |
2306 span->fDone = true; | 3083 span->fDone = true; |
2307 fDoneSpans++; | 3084 fDoneSpans++; |
2308 } | 3085 } |
2309 | 3086 |
2310 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) { | 3087 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) { |
2311 SkOpSpan* span = verifyOneWindingU(funName, tIndex); | 3088 SkOpSpan* span = verifyOneWindingU(funName, tIndex); |
2312 if (!span) { | 3089 if (!span) { |
2313 return; | 3090 return; |
2314 } | 3091 } |
| 3092 if (span->fWindSum == SK_MinS32) { |
| 3093 SkDebugf("%s uncomputed\n", __FUNCTION__); |
| 3094 } |
| 3095 SkASSERT(!span->fDone); |
2315 span->fDone = true; | 3096 span->fDone = true; |
2316 fDoneSpans++; | 3097 fDoneSpans++; |
2317 } | 3098 } |
2318 | 3099 |
2319 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng) { | 3100 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng) { |
2320 SkOpSpan& span = fTs[tIndex]; | 3101 SkOpSpan& span = fTs[tIndex]; |
2321 if (span.fDone) { | 3102 if (span.fDone && !span.fSmall) { |
2322 return NULL; | 3103 return NULL; |
2323 } | 3104 } |
2324 #if DEBUG_MARK_DONE | 3105 #if DEBUG_MARK_DONE |
2325 debugShowNewWinding(funName, span, winding); | 3106 debugShowNewWinding(funName, span, winding); |
2326 #endif | 3107 #endif |
2327 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 3108 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2328 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); | 3109 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2329 span.fWindSum = winding; | 3110 span.fWindSum = winding; |
2330 return &span; | 3111 return &span; |
2331 } | 3112 } |
2332 | 3113 |
2333 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, | 3114 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, |
2334 int oppWinding) { | 3115 int oppWinding) { |
2335 SkOpSpan& span = fTs[tIndex]; | 3116 SkOpSpan& span = fTs[tIndex]; |
2336 if (span.fDone && !span.fSmall) { | 3117 if (span.fDone && !span.fSmall) { |
2337 return NULL; | 3118 return NULL; |
2338 } | 3119 } |
2339 #if DEBUG_MARK_DONE | 3120 #if DEBUG_MARK_DONE |
2340 debugShowNewWinding(funName, span, winding, oppWinding); | 3121 debugShowNewWinding(funName, span, winding, oppWinding); |
2341 #endif | 3122 #endif |
2342 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 3123 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2343 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); | 3124 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2344 span.fWindSum = winding; | 3125 span.fWindSum = winding; |
2345 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); | 3126 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); |
2346 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); | 3127 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); |
2347 span.fOppSum = oppWinding; | 3128 span.fOppSum = oppWinding; |
| 3129 debugValidate(); |
2348 return &span; | 3130 return &span; |
2349 } | 3131 } |
2350 | 3132 |
2351 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 3133 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
2352 bool SkOpSegment::clockwise(int tStart, int tEnd) const { | 3134 bool SkOpSegment::clockwise(int tStart, int tEnd) const { |
2353 SkASSERT(fVerb != SkPath::kLine_Verb); | 3135 SkASSERT(fVerb != SkPath::kLine_Verb); |
2354 SkPoint edge[4]; | 3136 SkPoint edge[4]; |
2355 subDivide(tStart, tEnd, edge); | 3137 subDivide(tStart, tEnd, edge); |
2356 int points = SkPathOpsVerbToPoints(fVerb); | 3138 int points = SkPathOpsVerbToPoints(fVerb); |
2357 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; | 3139 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2440 #endif | 3222 #endif |
2441 span->fUnsortableStart = true; | 3223 span->fUnsortableStart = true; |
2442 } else { | 3224 } else { |
2443 --span; | 3225 --span; |
2444 #if DEBUG_UNSORTABLE | 3226 #if DEBUG_UNSORTABLE |
2445 debugShowNewWinding(__FUNCTION__, *span, 0); | 3227 debugShowNewWinding(__FUNCTION__, *span, 0); |
2446 #endif | 3228 #endif |
2447 span->fUnsortableEnd = true; | 3229 span->fUnsortableEnd = true; |
2448 } | 3230 } |
2449 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) { | 3231 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) { |
| 3232 debugValidate(); |
2450 return; | 3233 return; |
2451 } | 3234 } |
2452 span->fDone = true; | 3235 span->fDone = true; |
2453 fDoneSpans++; | 3236 fDoneSpans++; |
| 3237 debugValidate(); |
2454 } | 3238 } |
2455 | 3239 |
2456 void SkOpSegment::markWinding(int index, int winding) { | 3240 void SkOpSegment::markWinding(int index, int winding) { |
2457 // SkASSERT(!done()); | 3241 // SkASSERT(!done()); |
2458 SkASSERT(winding); | 3242 SkASSERT(winding); |
2459 double referenceT = fTs[index].fT; | 3243 double referenceT = fTs[index].fT; |
2460 int lesser = index; | 3244 int lesser = index; |
2461 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 3245 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { |
2462 markOneWinding(__FUNCTION__, lesser, winding); | 3246 markOneWinding(__FUNCTION__, lesser, winding); |
2463 } | 3247 } |
2464 do { | 3248 do { |
2465 markOneWinding(__FUNCTION__, index, winding); | 3249 markOneWinding(__FUNCTION__, index, winding); |
2466 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); | 3250 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); |
| 3251 debugValidate(); |
2467 } | 3252 } |
2468 | 3253 |
2469 void SkOpSegment::markWinding(int index, int winding, int oppWinding) { | 3254 void SkOpSegment::markWinding(int index, int winding, int oppWinding) { |
2470 // SkASSERT(!done()); | 3255 // SkASSERT(!done()); |
2471 SkASSERT(winding || oppWinding); | 3256 SkASSERT(winding || oppWinding); |
2472 double referenceT = fTs[index].fT; | 3257 double referenceT = fTs[index].fT; |
2473 int lesser = index; | 3258 int lesser = index; |
2474 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { | 3259 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { |
2475 markOneWinding(__FUNCTION__, lesser, winding, oppWinding); | 3260 markOneWinding(__FUNCTION__, lesser, winding, oppWinding); |
2476 } | 3261 } |
2477 do { | 3262 do { |
2478 markOneWinding(__FUNCTION__, index, winding, oppWinding); | 3263 markOneWinding(__FUNCTION__, index, winding, oppWinding); |
2479 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); | 3264 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenc
eT)); |
| 3265 debugValidate(); |
2480 } | 3266 } |
2481 | 3267 |
2482 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) { | 3268 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) { |
2483 int nextDoorWind = SK_MaxS32; | 3269 int nextDoorWind = SK_MaxS32; |
2484 int nextOppWind = SK_MaxS32; | 3270 int nextOppWind = SK_MaxS32; |
| 3271 // prefer exact matches |
2485 if (tIndex > 0) { | 3272 if (tIndex > 0) { |
2486 const SkOpSpan& below = fTs[tIndex - 1]; | 3273 const SkOpSpan& below = fTs[tIndex - 1]; |
| 3274 if (below.fT == t) { |
| 3275 nextDoorWind = below.fWindValue; |
| 3276 nextOppWind = below.fOppValue; |
| 3277 } |
| 3278 } |
| 3279 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { |
| 3280 const SkOpSpan& above = fTs[tIndex + 1]; |
| 3281 if (above.fT == t) { |
| 3282 nextDoorWind = above.fWindValue; |
| 3283 nextOppWind = above.fOppValue; |
| 3284 } |
| 3285 } |
| 3286 if (nextDoorWind == SK_MaxS32 && tIndex > 0) { |
| 3287 const SkOpSpan& below = fTs[tIndex - 1]; |
2487 if (approximately_negative(t - below.fT)) { | 3288 if (approximately_negative(t - below.fT)) { |
2488 nextDoorWind = below.fWindValue; | 3289 nextDoorWind = below.fWindValue; |
2489 nextOppWind = below.fOppValue; | 3290 nextOppWind = below.fOppValue; |
2490 } | 3291 } |
2491 } | 3292 } |
2492 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { | 3293 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { |
2493 const SkOpSpan& above = fTs[tIndex + 1]; | 3294 const SkOpSpan& above = fTs[tIndex + 1]; |
2494 if (approximately_negative(above.fT - t)) { | 3295 if (approximately_negative(above.fT - t)) { |
2495 nextDoorWind = above.fWindValue; | 3296 nextDoorWind = above.fWindValue; |
2496 nextOppWind = above.fOppValue; | 3297 nextOppWind = above.fOppValue; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2630 } | 3431 } |
2631 | 3432 |
2632 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, | 3433 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, |
2633 int* maxWinding, int* sumWinding) { | 3434 int* maxWinding, int* sumWinding) { |
2634 int deltaSum = spanSign(index, endIndex); | 3435 int deltaSum = spanSign(index, endIndex); |
2635 *maxWinding = *sumMiWinding; | 3436 *maxWinding = *sumMiWinding; |
2636 *sumWinding = *sumMiWinding -= deltaSum; | 3437 *sumWinding = *sumMiWinding -= deltaSum; |
2637 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); | 3438 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); |
2638 } | 3439 } |
2639 | 3440 |
2640 // This marks all spans unsortable so that this info is available for early | 3441 void SkOpSegment::sortAngles() { |
2641 // exclusion in find top and others. This could be optimized to only mark | 3442 int spanCount = fTs.count(); |
2642 // adjacent spans that unsortable. However, this makes it difficult to later | 3443 if (spanCount <= 2) { |
2643 // determine starting points for edge detection in find top and the like. | 3444 return; |
2644 bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles, | 3445 } |
2645 SkTArray<SkOpAngle*, true>* angleList, | 3446 int index = 0; |
2646 SortAngleKind orderKind) { | 3447 do { |
2647 bool sortable = true; | 3448 int fromIndex = fTs[index].fFromAngleIndex; |
2648 int angleCount = angles.count(); | 3449 int toIndex = fTs[index].fToAngleIndex; |
2649 int angleIndex; | 3450 if (fromIndex < 0 && toIndex < 0) { |
2650 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 3451 index += 1; |
2651 const SkOpAngle& angle = angles[angleIndex]; | 3452 continue; |
2652 angleList->push_back(const_cast<SkOpAngle*>(&angle)); | 3453 } |
| 3454 SkOpAngle* baseAngle = NULL; |
| 3455 if (fromIndex >= 0) { |
| 3456 baseAngle = &this->angle(fromIndex); |
| 3457 if (inLoop(baseAngle, spanCount, &index)) { |
| 3458 continue; |
| 3459 } |
| 3460 } |
2653 #if DEBUG_ANGLE | 3461 #if DEBUG_ANGLE |
2654 (*(angleList->end() - 1))->setID(angleIndex); | 3462 bool wroteAfterHeader = false; |
2655 #endif | 3463 #endif |
2656 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAng
leKind | 3464 if (toIndex >= 0) { |
2657 && angle.unorderable())); | 3465 SkOpAngle* toAngle = &this->angle(toIndex); |
2658 } | 3466 if (!baseAngle) { |
2659 if (sortable) { | 3467 baseAngle = toAngle; |
2660 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); | 3468 if (inLoop(baseAngle, spanCount, &index)) { |
2661 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 3469 continue; |
2662 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_
SortAngleKind | 3470 } |
2663 && angles[angleIndex].unorderable())) { | 3471 } else { |
2664 sortable = false; | 3472 SkDEBUGCODE(int newIndex = index); |
| 3473 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex ==
index); |
| 3474 #if DEBUG_ANGLE |
| 3475 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
fTs[index].fT, |
| 3476 index); |
| 3477 wroteAfterHeader = true; |
| 3478 #endif |
| 3479 baseAngle->insert(toAngle); |
| 3480 } |
| 3481 } |
| 3482 int nextFrom, nextTo; |
| 3483 int firstIndex = index; |
| 3484 do { |
| 3485 SkOpSpan& span = fTs[index]; |
| 3486 SkOpSegment* other = span.fOther; |
| 3487 SkOpSpan& oSpan = other->fTs[span.fOtherIndex]; |
| 3488 int otherAngleIndex = oSpan.fFromAngleIndex; |
| 3489 if (otherAngleIndex >= 0) { |
| 3490 #if DEBUG_ANGLE |
| 3491 if (!wroteAfterHeader) { |
| 3492 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI
D(), fTs[index].fT, |
| 3493 index); |
| 3494 wroteAfterHeader = true; |
| 3495 } |
| 3496 #endif |
| 3497 baseAngle->insert(&other->angle(otherAngleIndex)); |
| 3498 } |
| 3499 otherAngleIndex = oSpan.fToAngleIndex; |
| 3500 if (otherAngleIndex >= 0) { |
| 3501 #if DEBUG_ANGLE |
| 3502 if (!wroteAfterHeader) { |
| 3503 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugI
D(), fTs[index].fT, |
| 3504 index); |
| 3505 wroteAfterHeader = true; |
| 3506 } |
| 3507 #endif |
| 3508 baseAngle->insert(&other->angle(otherAngleIndex)); |
| 3509 } |
| 3510 if (++index == spanCount) { |
2665 break; | 3511 break; |
2666 } | 3512 } |
| 3513 nextFrom = fTs[index].fFromAngleIndex; |
| 3514 nextTo = fTs[index].fToAngleIndex; |
| 3515 } while (fromIndex == nextFrom && toIndex == nextTo); |
| 3516 if (baseAngle && baseAngle->loopCount() == 1) { |
| 3517 index = firstIndex; |
| 3518 do { |
| 3519 SkOpSpan& span = fTs[index]; |
| 3520 span.fFromAngleIndex = span.fToAngleIndex = -1; |
| 3521 if (++index == spanCount) { |
| 3522 break; |
| 3523 } |
| 3524 nextFrom = fTs[index].fFromAngleIndex; |
| 3525 nextTo = fTs[index].fToAngleIndex; |
| 3526 } while (fromIndex == nextFrom && toIndex == nextTo); |
| 3527 baseAngle = NULL; |
2667 } | 3528 } |
2668 } | 3529 #if DEBUG_SORT |
2669 if (!sortable) { | 3530 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); |
2670 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | |
2671 const SkOpAngle& angle = angles[angleIndex]; | |
2672 angle.segment()->markUnsortable(angle.start(), angle.end()); | |
2673 } | |
2674 } | |
2675 return sortable; | |
2676 } | |
2677 | |
2678 // set segments to unsortable if angle is unsortable, but do not set all angles | |
2679 // note that for a simple 4 way crossing, two of the edges may be orderable even
though | |
2680 // two edges are too short to be orderable. | |
2681 // perhaps some classes of unsortable angles should make all shared angles unsor
table, but | |
2682 // simple lines that have tiny crossings are always sortable on the large ends | |
2683 // OPTIMIZATION: check earlier when angles are added to input if any are unsorta
ble | |
2684 // may make sense then to mark all segments in angle sweep as unsortableStart/un
sortableEnd | |
2685 // solely for the purpose of short-circuiting future angle building around this
center | |
2686 bool SkOpSegment::SortAngles2(const SkTArray<SkOpAngle, true>& angles, | |
2687 SkTArray<SkOpAngle*, true>* angleList) { | |
2688 int angleCount = angles.count(); | |
2689 int angleIndex; | |
2690 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | |
2691 const SkOpAngle& angle = angles[angleIndex]; | |
2692 if (angle.unsortable()) { | |
2693 return false; | |
2694 } | |
2695 angleList->push_back(const_cast<SkOpAngle*>(&angle)); | |
2696 #if DEBUG_ANGLE | |
2697 (*(angleList->end() - 1))->setID(angleIndex); | |
2698 #endif | 3531 #endif |
2699 } | 3532 } while (index < spanCount); |
2700 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); | |
2701 // at this point angles are sorted but individually may not be orderable | |
2702 // this means that only adjcent orderable segments may transfer winding | |
2703 return true; | |
2704 } | 3533 } |
2705 | 3534 |
2706 // return true if midpoints were computed | 3535 // return true if midpoints were computed |
2707 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { | 3536 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { |
2708 SkASSERT(start != end); | 3537 SkASSERT(start != end); |
2709 edge[0] = fTs[start].fPt; | 3538 edge[0] = fTs[start].fPt; |
2710 int points = SkPathOpsVerbToPoints(fVerb); | 3539 int points = SkPathOpsVerbToPoints(fVerb); |
2711 edge[points] = fTs[end].fPt; | 3540 edge[points] = fTs[end].fPt; |
2712 if (fVerb == SkPath::kLine_Verb) { | 3541 if (fVerb == SkPath::kLine_Verb) { |
2713 return false; | 3542 return false; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2795 } | 3624 } |
2796 | 3625 |
2797 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin
t& startPt) { | 3626 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin
t& startPt) { |
2798 int outCount = outsidePts->count(); | 3627 int outCount = outsidePts->count(); |
2799 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { | 3628 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { |
2800 outsidePts->push_back(startPt); | 3629 outsidePts->push_back(startPt); |
2801 } | 3630 } |
2802 } | 3631 } |
2803 | 3632 |
2804 void SkOpSegment::undoneSpan(int* start, int* end) { | 3633 void SkOpSegment::undoneSpan(int* start, int* end) { |
2805 size_t tCount = fTs.count(); | 3634 int tCount = fTs.count(); |
2806 size_t index; | 3635 int index; |
2807 for (index = 0; index < tCount; ++index) { | 3636 for (index = 0; index < tCount; ++index) { |
2808 if (!fTs[index].fDone) { | 3637 if (!fTs[index].fDone) { |
2809 break; | 3638 break; |
2810 } | 3639 } |
2811 } | 3640 } |
2812 SkASSERT(index < tCount - 1); | 3641 SkASSERT(index < tCount - 1); |
2813 *start = index; | 3642 *start = index; |
2814 double startT = fTs[index].fT; | 3643 double startT = fTs[index].fT; |
2815 while (approximately_negative(fTs[++index].fT - startT)) | 3644 while (approximately_negative(fTs[++index].fT - startT)) |
2816 SkASSERT(index < tCount); | 3645 SkASSERT(index < tCount); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2940 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); | 3769 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); |
2941 span->fWindValue = 0; | 3770 span->fWindValue = 0; |
2942 span->fOppValue = 0; | 3771 span->fOppValue = 0; |
2943 if (span->fTiny || span->fSmall) { | 3772 if (span->fTiny || span->fSmall) { |
2944 return; | 3773 return; |
2945 } | 3774 } |
2946 SkASSERT(!span->fDone); | 3775 SkASSERT(!span->fDone); |
2947 span->fDone = true; | 3776 span->fDone = true; |
2948 ++fDoneSpans; | 3777 ++fDoneSpans; |
2949 } | 3778 } |
2950 | |
2951 #if DEBUG_SWAP_TOP | |
2952 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | |
2953 if (fVerb != SkPath::kCubic_Verb) { | |
2954 return false; | |
2955 } | |
2956 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
2957 return dst.controlsContainedByEnds(); | |
2958 } | |
2959 #endif | |
2960 | |
2961 #if DEBUG_CONCIDENT | |
2962 // SkASSERT if pair has not already been added | |
2963 void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double other
T) const { | |
2964 for (int i = 0; i < fTs.count(); ++i) { | |
2965 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == other
T) { | |
2966 return; | |
2967 } | |
2968 } | |
2969 SkASSERT(0); | |
2970 } | |
2971 #endif | |
2972 | |
2973 #if DEBUG_CONCIDENT | |
2974 void SkOpSegment::debugShowTs(const char* prefix) const { | |
2975 SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID); | |
2976 int lastWind = -1; | |
2977 int lastOpp = -1; | |
2978 double lastT = -1; | |
2979 int i; | |
2980 for (i = 0; i < fTs.count(); ++i) { | |
2981 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue | |
2982 || lastOpp != fTs[i].fOppValue; | |
2983 if (change && lastWind >= 0) { | |
2984 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | |
2985 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | |
2986 } | |
2987 if (change) { | |
2988 SkDebugf(" [o=%d", fTs[i].fOther->fID); | |
2989 lastWind = fTs[i].fWindValue; | |
2990 lastOpp = fTs[i].fOppValue; | |
2991 lastT = fTs[i].fT; | |
2992 } else { | |
2993 SkDebugf(",%d", fTs[i].fOther->fID); | |
2994 } | |
2995 } | |
2996 if (i <= 0) { | |
2997 return; | |
2998 } | |
2999 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | |
3000 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | |
3001 if (fOperand) { | |
3002 SkDebugf(" operand"); | |
3003 } | |
3004 if (done()) { | |
3005 SkDebugf(" done"); | |
3006 } | |
3007 SkDebugf("\n"); | |
3008 } | |
3009 #endif | |
3010 | |
3011 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
3012 void SkOpSegment::debugShowActiveSpans() const { | |
3013 debugValidate(); | |
3014 if (done()) { | |
3015 return; | |
3016 } | |
3017 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
3018 int lastId = -1; | |
3019 double lastT = -1; | |
3020 #endif | |
3021 for (int i = 0; i < fTs.count(); ++i) { | |
3022 if (fTs[i].fDone) { | |
3023 continue; | |
3024 } | |
3025 SkASSERT(i < fTs.count() - 1); | |
3026 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
3027 if (lastId == fID && lastT == fTs[i].fT) { | |
3028 continue; | |
3029 } | |
3030 lastId = fID; | |
3031 lastT = fTs[i].fT; | |
3032 #endif | |
3033 SkDebugf("%s id=%d", __FUNCTION__, fID); | |
3034 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
3035 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
3036 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
3037 } | |
3038 const SkOpSpan* span = &fTs[i]; | |
3039 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span)); | |
3040 int iEnd = i + 1; | |
3041 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT))
{ | |
3042 ++iEnd; | |
3043 } | |
3044 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT); | |
3045 const SkOpSegment* other = fTs[i].fOther; | |
3046 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", | |
3047 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); | |
3048 if (fTs[i].fWindSum == SK_MinS32) { | |
3049 SkDebugf("?"); | |
3050 } else { | |
3051 SkDebugf("%d", fTs[i].fWindSum); | |
3052 } | |
3053 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppVa
lue); | |
3054 } | |
3055 } | |
3056 #endif | |
3057 | |
3058 | |
3059 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE | |
3060 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding) { | |
3061 const SkPoint& pt = xyAtT(&span); | |
3062 SkDebugf("%s id=%d", fun, fID); | |
3063 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
3064 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
3065 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
3066 } | |
3067 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
3068 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
3069 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=", | |
3070 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
3071 (&span)[1].fT, winding); | |
3072 if (span.fWindSum == SK_MinS32) { | |
3073 SkDebugf("?"); | |
3074 } else { | |
3075 SkDebugf("%d", span.fWindSum); | |
3076 } | |
3077 SkDebugf(" windValue=%d\n", span.fWindValue); | |
3078 } | |
3079 | |
3080 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding, | |
3081 int oppWinding) { | |
3082 const SkPoint& pt = xyAtT(&span); | |
3083 SkDebugf("%s id=%d", fun, fID); | |
3084 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
3085 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
3086 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
3087 } | |
3088 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
3089 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
3090 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d
oppSum=", | |
3091 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
3092 (&span)[1].fT, winding, oppWinding); | |
3093 if (span.fOppSum == SK_MinS32) { | |
3094 SkDebugf("?"); | |
3095 } else { | |
3096 SkDebugf("%d", span.fOppSum); | |
3097 } | |
3098 SkDebugf(" windSum="); | |
3099 if (span.fWindSum == SK_MinS32) { | |
3100 SkDebugf("?"); | |
3101 } else { | |
3102 SkDebugf("%d", span.fWindSum); | |
3103 } | |
3104 SkDebugf(" windValue=%d\n", span.fWindValue); | |
3105 } | |
3106 #endif | |
3107 | |
3108 #if DEBUG_SORT || DEBUG_SWAP_TOP | |
3109 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, | |
3110 int first, const int contourWinding, | |
3111 const int oppContourWinding, bool sortable) cons
t { | |
3112 if (--SkPathOpsDebug::gSortCount < 0) { | |
3113 return; | |
3114 } | |
3115 if (!sortable) { | |
3116 if (angles.count() == 0) { | |
3117 return; | |
3118 } | |
3119 if (first < 0) { | |
3120 first = 0; | |
3121 } | |
3122 } | |
3123 SkASSERT(angles[first]->segment() == this); | |
3124 SkASSERT(!sortable || angles.count() > 1); | |
3125 int lastSum = contourWinding; | |
3126 int oppLastSum = oppContourWinding; | |
3127 const SkOpAngle* firstAngle = angles[first]; | |
3128 int windSum = lastSum - spanSign(firstAngle); | |
3129 int oppoSign = oppSign(firstAngle); | |
3130 int oppWindSum = oppLastSum - oppoSign; | |
3131 #define WIND_AS_STRING(x) char x##Str[12]; \ | |
3132 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \ | |
3133 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x) | |
3134 WIND_AS_STRING(contourWinding); | |
3135 WIND_AS_STRING(oppContourWinding); | |
3136 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FU
NCTION__, | |
3137 contourWindingStr, oppContourWindingStr, spanSign(angles[first])); | |
3138 int index = first; | |
3139 bool firstTime = true; | |
3140 do { | |
3141 const SkOpAngle& angle = *angles[index]; | |
3142 const SkOpSegment& segment = *angle.segment(); | |
3143 int start = angle.start(); | |
3144 int end = angle.end(); | |
3145 const SkOpSpan& sSpan = segment.fTs[start]; | |
3146 const SkOpSpan& eSpan = segment.fTs[end]; | |
3147 const SkOpSpan& mSpan = segment.fTs[SkMin32(start, end)]; | |
3148 bool opp = segment.fOperand ^ fOperand; | |
3149 if (!firstTime) { | |
3150 oppoSign = segment.oppSign(&angle); | |
3151 if (opp) { | |
3152 oppLastSum = oppWindSum; | |
3153 oppWindSum -= segment.spanSign(&angle); | |
3154 if (oppoSign) { | |
3155 lastSum = windSum; | |
3156 windSum -= oppoSign; | |
3157 } | |
3158 } else { | |
3159 lastSum = windSum; | |
3160 windSum -= segment.spanSign(&angle); | |
3161 if (oppoSign) { | |
3162 oppLastSum = oppWindSum; | |
3163 oppWindSum -= oppoSign; | |
3164 } | |
3165 } | |
3166 } | |
3167 SkDebugf("%s [%d] %s", __FUNCTION__, index, | |
3168 angle.unsortable() ? "*** UNSORTABLE *** " : ""); | |
3169 #if DEBUG_SORT_COMPACT | |
3170 SkDebugf("id=%d %s start=%d (%1.9g,%1.9g) end=%d (%1.9g,%1.9g)", | |
3171 segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)], | |
3172 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end, | |
3173 segment.xAtT(&eSpan), segment.yAtT(&eSpan)); | |
3174 #else | |
3175 switch (segment.fVerb) { | |
3176 case SkPath::kLine_Verb: | |
3177 SkDebugf(LINE_DEBUG_STR, LINE_DEBUG_DATA(segment.fPts)); | |
3178 break; | |
3179 case SkPath::kQuad_Verb: | |
3180 SkDebugf(QUAD_DEBUG_STR, QUAD_DEBUG_DATA(segment.fPts)); | |
3181 break; | |
3182 case SkPath::kCubic_Verb: | |
3183 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts)); | |
3184 break; | |
3185 default: | |
3186 SkASSERT(0); | |
3187 } | |
3188 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT); | |
3189 #endif | |
3190 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValu
e); | |
3191 SkPathOpsDebug::WindingPrintf(mSpan.fWindSum); | |
3192 int last, wind; | |
3193 if (opp) { | |
3194 last = oppLastSum; | |
3195 wind = oppWindSum; | |
3196 } else { | |
3197 last = lastSum; | |
3198 wind = windSum; | |
3199 } | |
3200 bool useInner = SkPathOpsDebug::ValidWind(last) && SkPathOpsDebug::Valid
Wind(wind) | |
3201 && UseInnerWinding(last, wind); | |
3202 WIND_AS_STRING(last); | |
3203 WIND_AS_STRING(wind); | |
3204 WIND_AS_STRING(lastSum); | |
3205 WIND_AS_STRING(oppLastSum); | |
3206 WIND_AS_STRING(windSum); | |
3207 WIND_AS_STRING(oppWindSum); | |
3208 #undef WIND_AS_STRING | |
3209 if (!oppoSign) { | |
3210 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr :
lastStr); | |
3211 } else { | |
3212 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : op
pLastSumStr, | |
3213 opp ? windSumStr : oppWindSumStr); | |
3214 } | |
3215 SkDebugf(" done=%d unord=%d small=%d tiny=%d opp=%d\n", | |
3216 mSpan.fDone, angle.unorderable(), mSpan.fSmall, mSpan.fTiny, opp
); | |
3217 ++index; | |
3218 if (index == angles.count()) { | |
3219 index = 0; | |
3220 } | |
3221 if (firstTime) { | |
3222 firstTime = false; | |
3223 } | |
3224 } while (index != first); | |
3225 } | |
3226 | |
3227 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, | |
3228 int first, bool sortable) { | |
3229 if (!sortable) { | |
3230 if (angles.count() == 0) { | |
3231 return; | |
3232 } | |
3233 if (first < 0) { | |
3234 first = 0; | |
3235 } | |
3236 } | |
3237 const SkOpAngle* firstAngle = angles[first]; | |
3238 const SkOpSegment* segment = firstAngle->segment(); | |
3239 int winding = segment->updateWinding(firstAngle); | |
3240 int oppWinding = segment->updateOppWinding(firstAngle); | |
3241 debugShowSort(fun, angles, first, winding, oppWinding, sortable); | |
3242 } | |
3243 | |
3244 #endif | |
3245 | |
3246 #if DEBUG_SHOW_WINDING | |
3247 int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const { | |
3248 if (!(1 << fID & ofInterest)) { | |
3249 return 0; | |
3250 } | |
3251 int sum = 0; | |
3252 SkTArray<char, true> slots(slotCount * 2); | |
3253 memset(slots.begin(), ' ', slotCount * 2); | |
3254 for (int i = 0; i < fTs.count(); ++i) { | |
3255 // if (!(1 << fTs[i].fOther->fID & ofInterest)) { | |
3256 // continue; | |
3257 // } | |
3258 sum += fTs[i].fWindValue; | |
3259 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | |
3260 sum += fTs[i].fOppValue; | |
3261 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | |
3262 } | |
3263 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, | |
3264 slots.begin() + slotCount); | |
3265 return sum; | |
3266 } | |
3267 #endif | |
3268 | |
3269 void SkOpSegment::debugValidate() const { | |
3270 #if DEBUG_VALIDATE | |
3271 int count = fTs.count(); | |
3272 SkASSERT(count >= 2); | |
3273 SkASSERT(fTs[0].fT == 0); | |
3274 SkASSERT(fTs[count - 1].fT == 1); | |
3275 int done = 0; | |
3276 double t = -1; | |
3277 for (int i = 0; i < count; ++i) { | |
3278 const SkOpSpan& span = fTs[i]; | |
3279 SkASSERT(t <= span.fT); | |
3280 t = span.fT; | |
3281 int otherIndex = span.fOtherIndex; | |
3282 const SkOpSegment* other = span.fOther; | |
3283 const SkOpSpan& otherSpan = other->fTs[otherIndex]; | |
3284 SkASSERT(otherSpan.fPt == span.fPt); | |
3285 SkASSERT(otherSpan.fOtherT == t); | |
3286 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]); | |
3287 done += span.fDone; | |
3288 } | |
3289 SkASSERT(done == fDoneSpans); | |
3290 #endif | |
3291 } | |
3292 | |
3293 #ifdef SK_DEBUG | |
3294 void SkOpSegment::dumpPts() const { | |
3295 int last = SkPathOpsVerbToPoints(fVerb); | |
3296 SkDebugf("{{"); | |
3297 int index = 0; | |
3298 do { | |
3299 SkDPoint::dump(fPts[index]); | |
3300 SkDebugf(", "); | |
3301 } while (++index < last); | |
3302 SkDPoint::dump(fPts[index]); | |
3303 SkDebugf("}}\n"); | |
3304 } | |
3305 | |
3306 void SkOpSegment::dumpDPts() const { | |
3307 int count = SkPathOpsVerbToPoints(fVerb); | |
3308 SkDebugf("{{"); | |
3309 int index = 0; | |
3310 do { | |
3311 SkDPoint dPt = {fPts[index].fX, fPts[index].fY}; | |
3312 dPt.dump(); | |
3313 if (index != count) { | |
3314 SkDebugf(", "); | |
3315 } | |
3316 } while (++index <= count); | |
3317 SkDebugf("}}\n"); | |
3318 } | |
3319 | |
3320 void SkOpSegment::dumpSpans() const { | |
3321 int count = this->count(); | |
3322 for (int index = 0; index < count; ++index) { | |
3323 const SkOpSpan& span = this->span(index); | |
3324 SkDebugf("[%d] ", index); | |
3325 span.dump(); | |
3326 } | |
3327 } | |
3328 #endif | |
OLD | NEW |