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" |
(...skipping 14 matching lines...) Expand all Loading... |
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 { kOutsideTrackedTCount = 16 }; // FIXME: determine what this should be | 35 enum { |
| 36 kOutsideTrackedTCount = 16, // FIXME: determine what this should be |
| 37 kMissingSpanCount = 4, // FIXME: determine what this should be |
| 38 }; |
36 | 39 |
37 // OPTIMIZATION: does the following also work, and is it any faster? | 40 // note that this follows the same logic flow as build angles |
38 // return outerWinding * innerWinding > 0 | |
39 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) | |
40 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { | |
41 SkASSERT(outerWinding != SK_MaxS32); | |
42 SkASSERT(innerWinding != SK_MaxS32); | |
43 int absOut = abs(outerWinding); | |
44 int absIn = abs(innerWinding); | |
45 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; | |
46 return result; | |
47 } | |
48 | |
49 bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* a
ngles) { | 41 bool SkOpSegment::activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* a
ngles) { |
50 if (activeAngleInner(index, done, angles)) { | 42 if (activeAngleInner(index, done, angles)) { |
51 return true; | 43 return true; |
52 } | 44 } |
| 45 double referenceT = fTs[index].fT; |
53 int lesser = index; | 46 int lesser = index; |
54 while (--lesser >= 0 && equalPoints(index, lesser)) { | 47 while (--lesser >= 0 |
| 48 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { |
55 if (activeAngleOther(lesser, done, angles)) { | 49 if (activeAngleOther(lesser, done, angles)) { |
56 return true; | 50 return true; |
57 } | 51 } |
58 } | 52 } |
59 lesser = index; | |
60 do { | 53 do { |
61 if (activeAngleOther(index, done, angles)) { | 54 if (activeAngleOther(index, done, angles)) { |
62 return true; | 55 return true; |
63 } | 56 } |
64 } while (++index < fTs.count() && equalPoints(index, lesser)); | 57 if (++index == fTs.count()) { |
| 58 break; |
| 59 } |
| 60 if (fTs[index - 1].fTiny) { |
| 61 referenceT = fTs[index].fT; |
| 62 continue; |
| 63 } |
| 64 } while (precisely_negative(fTs[index].fT - referenceT)); |
65 return false; | 65 return false; |
66 } | 66 } |
67 | 67 |
68 bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, tru
e>* angles) { | 68 bool SkOpSegment::activeAngleOther(int index, int* done, SkTArray<SkOpAngle, tru
e>* angles) { |
69 SkOpSpan* span = &fTs[index]; | 69 SkOpSpan* span = &fTs[index]; |
70 SkOpSegment* other = span->fOther; | 70 SkOpSegment* other = span->fOther; |
71 int oIndex = span->fOtherIndex; | 71 int oIndex = span->fOtherIndex; |
72 return other->activeAngleInner(oIndex, done, angles); | 72 return other->activeAngleInner(oIndex, done, angles); |
73 } | 73 } |
74 | 74 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 suTo = (*sumWinding & xorSuMask) != 0; | 180 suTo = (*sumWinding & xorSuMask) != 0; |
181 } else { | 181 } else { |
182 miFrom = (*maxWinding & xorMiMask) != 0; | 182 miFrom = (*maxWinding & xorMiMask) != 0; |
183 miTo = (*sumWinding & xorMiMask) != 0; | 183 miTo = (*sumWinding & xorMiMask) != 0; |
184 suFrom = (*oppMaxWinding & xorSuMask) != 0; | 184 suFrom = (*oppMaxWinding & xorSuMask) != 0; |
185 suTo = (*oppSumWinding & xorSuMask) != 0; | 185 suTo = (*oppSumWinding & xorSuMask) != 0; |
186 } | 186 } |
187 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; | 187 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; |
188 #if DEBUG_ACTIVE_OP | 188 #if DEBUG_ACTIVE_OP |
189 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCT
ION__, | 189 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCT
ION__, |
190 kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); | 190 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); |
191 #endif | 191 #endif |
192 return result; | 192 return result; |
193 } | 193 } |
194 | 194 |
195 bool SkOpSegment::activeWinding(int index, int endIndex) { | 195 bool SkOpSegment::activeWinding(int index, int endIndex) { |
196 int sumWinding = updateWinding(endIndex, index); | 196 int sumWinding = updateWinding(endIndex, index); |
197 int maxWinding; | 197 int maxWinding; |
198 return activeWinding(index, endIndex, &maxWinding, &sumWinding); | 198 return activeWinding(index, endIndex, &maxWinding, &sumWinding); |
199 } | 199 } |
200 | 200 |
201 bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* s
umWinding) { | 201 bool SkOpSegment::activeWinding(int index, int endIndex, int* maxWinding, int* s
umWinding) { |
202 setUpWinding(index, endIndex, maxWinding, sumWinding); | 202 setUpWinding(index, endIndex, maxWinding, sumWinding); |
203 bool from = *maxWinding != 0; | 203 bool from = *maxWinding != 0; |
204 bool to = *sumWinding != 0; | 204 bool to = *sumWinding != 0; |
205 bool result = gUnaryActiveEdge[from][to]; | 205 bool result = gUnaryActiveEdge[from][to]; |
206 return result; | 206 return result; |
207 } | 207 } |
208 | 208 |
209 void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int
end) const { | 209 void SkOpSegment::addAngle(SkTArray<SkOpAngle, true>* anglesPtr, int start, int
end) const { |
210 SkASSERT(start != end); | 210 SkASSERT(start != end); |
211 SkOpAngle& angle = anglesPtr->push_back(); | 211 SkOpAngle& angle = anglesPtr->push_back(); |
212 #if 0 && DEBUG_ANGLE // computed pt and actual pt may differ by more than approx
eq | |
213 SkTArray<SkOpAngle, true>& angles = *anglesPtr; | |
214 if (angles.count() > 1) { | |
215 const SkOpSegment* aSeg = angles[0].segment(); | |
216 int aStart = angles[0].start(); | |
217 if (!aSeg->fTs[aStart].fTiny) { | |
218 const SkPoint& angle0Pt = aSeg->xyAtT(aStart); | |
219 SkDPoint newPt = (*CurveDPointAtT[SkPathOpsVerbToPoints(aSeg->fVerb)
])(aSeg->fPts, | |
220 aSeg->fTs[aStart].fT); | |
221 #if ONE_OFF_DEBUG | |
222 SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g)\n", __FUNCTION__
, | |
223 aSeg->fTs[aStart].fT, newPt.fX, newPt.fY, angle0Pt.fX, angle
0Pt.fY); | |
224 #endif | |
225 SkASSERT(newPt.approximatelyEqual(angle0Pt)); | |
226 } | |
227 } | |
228 #endif | |
229 angle.set(this, start, end); | 212 angle.set(this, start, end); |
230 } | 213 } |
231 | 214 |
232 void SkOpSegment::addCancelOutsides(double tStart, double oStart, SkOpSegment* o
ther, double oEnd) { | 215 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt
, |
| 216 SkOpSegment* other) { |
233 int tIndex = -1; | 217 int tIndex = -1; |
234 int tCount = fTs.count(); | 218 int tCount = fTs.count(); |
235 int oIndex = -1; | 219 int oIndex = -1; |
236 int oCount = other->fTs.count(); | 220 int oCount = other->fTs.count(); |
237 do { | 221 do { |
238 ++tIndex; | 222 ++tIndex; |
239 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount
); | 223 } while (startPt != fTs[tIndex].fPt && tIndex < tCount); |
240 int tIndexStart = tIndex; | 224 int tIndexStart = tIndex; |
241 do { | 225 do { |
242 ++oIndex; | 226 ++oIndex; |
243 } while (!approximately_negative(oStart - other->fTs[oIndex].fT) && oIndex <
oCount); | 227 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount); |
244 int oIndexStart = oIndex; | 228 int oIndexStart = oIndex; |
245 double nextT; | 229 const SkPoint* nextPt; |
246 do { | 230 do { |
247 nextT = fTs[++tIndex].fT; | 231 nextPt = &fTs[++tIndex].fPt; |
248 } while (nextT < 1 && approximately_negative(nextT - tStart)); | 232 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt); |
249 double oNextT; | 233 } while (startPt == *nextPt); |
| 234 double nextT = fTs[tIndex].fT; |
| 235 const SkPoint* oNextPt; |
250 do { | 236 do { |
251 oNextT = other->fTs[++oIndex].fT; | 237 oNextPt = &other->fTs[++oIndex].fPt; |
252 } while (oNextT < 1 && approximately_negative(oNextT - oStart)); | 238 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt); |
| 239 } while (endPt == *oNextPt); |
| 240 double oNextT = other->fTs[oIndex].fT; |
253 // at this point, spans before and after are at: | 241 // at this point, spans before and after are at: |
254 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] | 242 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] |
255 // if tIndexStart == 0, no prior span | 243 // if tIndexStart == 0, no prior span |
256 // if nextT == 1, no following span | 244 // if nextT == 1, no following span |
257 | 245 |
258 // advance the span with zero winding | 246 // advance the span with zero winding |
259 // if the following span exists (not past the end, non-zero winding) | 247 // if the following span exists (not past the end, non-zero winding) |
260 // connect the two edges | 248 // connect the two edges |
261 if (!fTs[tIndexStart].fWindValue) { | 249 if (!fTs[tIndexStart].fWindValue) { |
262 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { | 250 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", | 282 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", |
295 __FUNCTION__, fID, other->fID, oIndex, | 283 __FUNCTION__, fID, other->fID, oIndex, |
296 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX, | 284 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX, |
297 other->xyAtT(oIndex).fY); | 285 other->xyAtT(oIndex).fY); |
298 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].
fT); | 286 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].
fT); |
299 #endif | 287 #endif |
300 } | 288 } |
301 } | 289 } |
302 } | 290 } |
303 | 291 |
304 void SkOpSegment::addCoinOutsides(const SkTArray<double, true>& outsideTs, SkOpS
egment* other, | 292 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, |
305 double oEnd) { | 293 SkOpSegment* other) { |
306 // walk this to outsideTs[0] | 294 // walk this to startPt |
307 // walk other to outsideTs[1] | 295 // walk other to startPt |
308 // if either is > 0, add a pointer to the other, copying adjacent winding | 296 // if either is > 0, add a pointer to the other, copying adjacent winding |
309 int tIndex = -1; | 297 int tIndex = -1; |
310 int oIndex = -1; | 298 int oIndex = -1; |
311 double tStart = outsideTs[0]; | |
312 double oStart = outsideTs[1]; | |
313 do { | 299 do { |
314 ++tIndex; | 300 ++tIndex; |
315 } while (!approximately_negative(tStart - fTs[tIndex].fT)); | 301 } while (startPt != fTs[tIndex].fPt); |
316 SkPoint ptStart = fTs[tIndex].fPt; | |
317 do { | 302 do { |
318 ++oIndex; | 303 ++oIndex; |
319 } while (!approximately_negative(oStart - other->fTs[oIndex].fT)); | 304 } while (startPt != other->fTs[oIndex].fPt); |
320 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) { | 305 if (tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) { |
321 addTPair(tStart, other, oStart, false, ptStart); | 306 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt); |
322 } | 307 } |
323 tStart = fTs[tIndex].fT; | 308 SkPoint nextPt = startPt; |
324 oStart = other->fTs[oIndex].fT; | |
325 do { | 309 do { |
326 double nextT; | 310 const SkPoint* workPt; |
327 do { | 311 do { |
328 nextT = fTs[++tIndex].fT; | 312 workPt = &fTs[++tIndex].fPt; |
329 } while (approximately_negative(nextT - tStart)); | 313 } while (nextPt == *workPt); |
330 tStart = nextT; | |
331 ptStart = fTs[tIndex].fPt; | |
332 do { | 314 do { |
333 nextT = other->fTs[++oIndex].fT; | 315 workPt = &other->fTs[++oIndex].fPt; |
334 } while (approximately_negative(nextT - oStart)); | 316 } while (nextPt == *workPt); |
335 oStart = nextT; | 317 nextPt = *workPt; |
| 318 double tStart = fTs[tIndex].fT; |
| 319 double oStart = other->fTs[oIndex].fT; |
336 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) { | 320 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) { |
337 break; | 321 break; |
338 } | 322 } |
339 addTPair(tStart, other, oStart, false, ptStart); | 323 addTPair(tStart, other, oStart, false, nextPt); |
340 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart))
; | 324 } while (endPt != nextPt); |
341 } | 325 } |
342 | 326 |
343 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) { | 327 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) { |
344 init(pts, SkPath::kCubic_Verb, operand, evenOdd); | 328 init(pts, SkPath::kCubic_Verb, operand, evenOdd); |
345 fBounds.setCubicBounds(pts); | 329 fBounds.setCubicBounds(pts); |
346 } | 330 } |
347 | 331 |
348 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
) const { | 332 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
) const { |
349 SkPoint edge[4]; | 333 SkPoint edge[4]; |
350 const SkPoint* ePtr; | 334 const SkPoint* ePtr; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 fBounds.setQuadBounds(pts); | 400 fBounds.setQuadBounds(pts); |
417 } | 401 } |
418 | 402 |
419 // Defer all coincident edge processing until | 403 // Defer all coincident edge processing until |
420 // after normal intersections have been computed | 404 // after normal intersections have been computed |
421 | 405 |
422 // no need to be tricky; insert in normal T order | 406 // no need to be tricky; insert in normal T order |
423 // resolve overlapping ts when considering coincidence later | 407 // resolve overlapping ts when considering coincidence later |
424 | 408 |
425 // add non-coincident intersection. Resulting edges are sorted in T. | 409 // add non-coincident intersection. Resulting edges are sorted in T. |
426 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { | 410 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT, bool i
sNear) { |
427 if (precisely_zero(newT)) { | 411 if (precisely_zero(newT)) { |
428 newT = 0; | 412 newT = 0; |
429 } else if (precisely_equal(newT, 1)) { | 413 } else if (precisely_equal(newT, 1)) { |
430 newT = 1; | 414 newT = 1; |
431 } | 415 } |
432 // FIXME: in the pathological case where there is a ton of intercepts, | 416 // FIXME: in the pathological case where there is a ton of intercepts, |
433 // binary search? | 417 // binary search? |
434 int insertedAt = -1; | 418 int insertedAt = -1; |
435 size_t tCount = fTs.count(); | 419 size_t tCount = fTs.count(); |
436 for (size_t index = 0; index < tCount; ++index) { | 420 for (size_t index = 0; index < tCount; ++index) { |
(...skipping 11 matching lines...) Expand all Loading... |
448 SkOpSpan* span; | 432 SkOpSpan* span; |
449 if (insertedAt >= 0) { | 433 if (insertedAt >= 0) { |
450 span = fTs.insert(insertedAt); | 434 span = fTs.insert(insertedAt); |
451 } else { | 435 } else { |
452 insertedAt = tCount; | 436 insertedAt = tCount; |
453 span = fTs.append(); | 437 span = fTs.append(); |
454 } | 438 } |
455 span->fT = newT; | 439 span->fT = newT; |
456 span->fOther = other; | 440 span->fOther = other; |
457 span->fPt = pt; | 441 span->fPt = pt; |
| 442 span->fNear = isNear; |
458 #if 0 | 443 #if 0 |
459 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) | 444 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) |
460 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) | 445 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) |
461 && approximately_equal(xyAtT(newT).fY, pt.fY)); | 446 && approximately_equal(xyAtT(newT).fY, pt.fY)); |
462 #endif | 447 #endif |
463 span->fWindSum = SK_MinS32; | 448 span->fWindSum = SK_MinS32; |
464 span->fOppSum = SK_MinS32; | 449 span->fOppSum = SK_MinS32; |
465 span->fWindValue = 1; | 450 span->fWindValue = 1; |
466 span->fOppValue = 0; | 451 span->fOppValue = 0; |
| 452 span->fSmall = false; |
467 span->fTiny = false; | 453 span->fTiny = false; |
468 span->fLoop = false; | 454 span->fLoop = false; |
469 if ((span->fDone = newT == 1)) { | 455 if ((span->fDone = newT == 1)) { |
470 ++fDoneSpans; | 456 ++fDoneSpans; |
471 } | 457 } |
472 span->fUnsortableStart = false; | 458 span->fUnsortableStart = false; |
473 span->fUnsortableEnd = false; | 459 span->fUnsortableEnd = false; |
474 int less = -1; | 460 int less = -1; |
475 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span
)) { | 461 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt,
span->fPt)) { |
476 if (span[less].fDone) { | 462 if (span[less].fDone) { |
477 break; | 463 break; |
478 } | 464 } |
479 double tInterval = newT - span[less].fT; | 465 double tInterval = newT - span[less].fT; |
480 if (precisely_negative(tInterval)) { | 466 if (precisely_negative(tInterval)) { |
481 break; | 467 break; |
482 } | 468 } |
483 if (fVerb == SkPath::kCubic_Verb) { | 469 if (fVerb == SkPath::kCubic_Verb) { |
484 double tMid = newT - tInterval / 2; | 470 double tMid = newT - tInterval / 2; |
485 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); | 471 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); |
486 if (!midPt.approximatelyEqual(xyAtT(span))) { | 472 if (!midPt.approximatelyEqual(xyAtT(span))) { |
487 break; | 473 break; |
488 } | 474 } |
489 } | 475 } |
490 span[less].fTiny = true; | 476 span[less].fSmall = true; |
| 477 bool tiny = span[less].fPt == span->fPt; |
| 478 span[less].fTiny = tiny; |
491 span[less].fDone = true; | 479 span[less].fDone = true; |
492 if (approximately_negative(newT - span[less].fT)) { | 480 if (approximately_negative(newT - span[less].fT) && tiny) { |
493 if (approximately_greater_than_one(newT)) { | 481 if (approximately_greater_than_one(newT)) { |
494 SkASSERT(&span[less] - fTs.begin() < fTs.count()); | 482 SkASSERT(&span[less] - fTs.begin() < fTs.count()); |
495 span[less].fUnsortableStart = true; | 483 span[less].fUnsortableStart = true; |
496 if (&span[less - 1] - fTs.begin() >= 0) { | 484 if (&span[less - 1] - fTs.begin() >= 0) { |
497 span[less - 1].fUnsortableEnd = true; | 485 span[less - 1].fUnsortableEnd = true; |
498 } | 486 } |
499 } | 487 } |
500 if (approximately_less_than_zero(span[less].fT)) { | 488 if (approximately_less_than_zero(span[less].fT)) { |
501 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count()); | 489 SkASSERT(&span[less + 1] - fTs.begin() < fTs.count()); |
502 SkASSERT(&span[less] - fTs.begin() >= 0); | 490 SkASSERT(&span[less] - fTs.begin() >= 0); |
503 span[less + 1].fUnsortableStart = true; | 491 span[less + 1].fUnsortableStart = true; |
504 span[less].fUnsortableEnd = true; | 492 span[less].fUnsortableEnd = true; |
505 } | 493 } |
506 } | 494 } |
507 ++fDoneSpans; | 495 ++fDoneSpans; |
508 --less; | 496 --less; |
509 } | 497 } |
510 int more = 1; | 498 int more = 1; |
511 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span))
{ | 499 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, sp
an->fPt)) { |
512 if (span[more - 1].fDone) { | 500 if (span[more - 1].fDone) { |
513 break; | 501 break; |
514 } | 502 } |
515 double tEndInterval = span[more].fT - newT; | 503 double tEndInterval = span[more].fT - newT; |
516 if (precisely_negative(tEndInterval)) { | 504 if (precisely_negative(tEndInterval)) { |
517 break; | 505 break; |
518 } | 506 } |
519 if (fVerb == SkPath::kCubic_Verb) { | 507 if (fVerb == SkPath::kCubic_Verb) { |
520 double tMid = newT - tEndInterval / 2; | 508 double tMid = newT - tEndInterval / 2; |
521 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); | 509 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); |
522 if (!midEndPt.approximatelyEqual(xyAtT(span))) { | 510 if (!midEndPt.approximatelyEqual(xyAtT(span))) { |
523 break; | 511 break; |
524 } | 512 } |
525 } | 513 } |
526 span[more - 1].fTiny = true; | 514 span[more - 1].fSmall = true; |
| 515 bool tiny = span[more].fPt == span->fPt; |
| 516 span[more - 1].fTiny = tiny; |
527 span[more - 1].fDone = true; | 517 span[more - 1].fDone = true; |
528 if (approximately_negative(span[more].fT - newT)) { | 518 if (approximately_negative(span[more].fT - newT) && tiny) { |
529 if (approximately_greater_than_one(span[more].fT)) { | 519 if (approximately_greater_than_one(span[more].fT)) { |
530 span[more + 1].fUnsortableStart = true; | 520 span[more + 1].fUnsortableStart = true; |
531 span[more].fUnsortableEnd = true; | 521 span[more].fUnsortableEnd = true; |
532 } | 522 } |
533 if (approximately_less_than_zero(newT)) { | 523 if (approximately_less_than_zero(newT)) { |
534 span[more].fUnsortableStart = true; | 524 span[more].fUnsortableStart = true; |
535 span[more - 1].fUnsortableEnd = true; | 525 span[more - 1].fUnsortableEnd = true; |
536 } | 526 } |
537 } | 527 } |
538 ++fDoneSpans; | 528 ++fDoneSpans; |
539 ++more; | 529 ++more; |
540 } | 530 } |
541 return insertedAt; | 531 return insertedAt; |
542 } | 532 } |
543 | 533 |
544 // set spans from start to end to decrement by one | 534 // set spans from start to end to decrement by one |
545 // note this walks other backwards | 535 // note this walks other backwards |
546 // FIXME: there's probably an edge case that can be constructed where | 536 // FIXME: there's probably an edge case that can be constructed where |
547 // two span in one segment are separated by float epsilon on one span but | 537 // two span in one segment are separated by float epsilon on one span but |
548 // not the other, if one segment is very small. For this | 538 // not the other, if one segment is very small. For this |
549 // case the counts asserted below may or may not be enough to separate the | 539 // case the counts asserted below may or may not be enough to separate the |
550 // spans. Even if the counts work out, what if the spans aren't correctly | 540 // spans. Even if the counts work out, what if the spans aren't correctly |
551 // sorted? It feels better in such a case to match the span's other span | 541 // sorted? It feels better in such a case to match the span's other span |
552 // pointer since both coincident segments must contain the same spans. | 542 // pointer since both coincident segments must contain the same spans. |
553 // FIXME? It seems that decrementing by one will fail for complex paths that | 543 // FIXME? It seems that decrementing by one will fail for complex paths that |
554 // have three or more coincident edges. Shouldn't this subtract the difference | 544 // have three or more coincident edges. Shouldn't this subtract the difference |
555 // between the winding values? | 545 // between the winding values? |
556 void SkOpSegment::addTCancel(double startT, double endT, SkOpSegment* other, | 546 /* |--> |--> |
557 double oStartT, double oEndT) { | 547 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>
4 |
558 SkASSERT(!approximately_negative(endT - startT)); | 548 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0 |
559 SkASSERT(!approximately_negative(oEndT - oStartT)); | 549 ^ ^ <--| <--| |
| 550 startPt endPt test/oTest first pos test/oTest final po
s |
| 551 */ |
| 552 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { |
560 bool binary = fOperand != other->fOperand; | 553 bool binary = fOperand != other->fOperand; |
561 int index = 0; | 554 int index = 0; |
562 while (!approximately_negative(startT - fTs[index].fT)) { | 555 while (startPt != fTs[index].fPt) { |
| 556 SkASSERT(index < fTs.count()); |
563 ++index; | 557 ++index; |
564 } | 558 } |
565 int oIndex = other->fTs.count(); | 559 int oIndex = other->fTs.count(); |
566 while (approximately_positive(other->fTs[--oIndex].fT - oEndT)) | 560 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match |
567 ; | 561 SkASSERT(oIndex > 0); |
568 double tRatio = (oEndT - oStartT) / (endT - startT); | 562 } |
| 563 while (startPt == other->fTs[--oIndex].fPt) { // look for first point beyon
d match |
| 564 SkASSERT(oIndex > 0); |
| 565 } |
569 SkOpSpan* test = &fTs[index]; | 566 SkOpSpan* test = &fTs[index]; |
570 SkOpSpan* oTest = &other->fTs[oIndex]; | 567 SkOpSpan* oTest = &other->fTs[oIndex]; |
571 SkSTArray<kOutsideTrackedTCount, double, true> outsideTs; | 568 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
572 SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs; | 569 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
573 do { | 570 do { |
| 571 SkASSERT(test->fT < 1); |
| 572 SkASSERT(oTest->fT < 1); |
574 bool decrement = test->fWindValue && oTest->fWindValue; | 573 bool decrement = test->fWindValue && oTest->fWindValue; |
575 bool track = test->fWindValue || oTest->fWindValue; | 574 bool track = test->fWindValue || oTest->fWindValue; |
576 bool bigger = test->fWindValue >= oTest->fWindValue; | 575 bool bigger = test->fWindValue >= oTest->fWindValue; |
577 double testT = test->fT; | 576 const SkPoint& testPt = test->fPt; |
578 double oTestT = oTest->fT; | 577 const SkPoint& oTestPt = oTest->fPt; |
579 SkOpSpan* span = test; | |
580 do { | 578 do { |
581 if (decrement) { | 579 if (decrement) { |
582 if (binary && bigger) { | 580 if (binary && bigger) { |
583 span->fOppValue--; | 581 test->fOppValue--; |
584 } else { | 582 } else { |
585 decrementSpan(span); | 583 decrementSpan(test); |
586 } | 584 } |
587 } else if (track && span->fT < 1 && oTestT < 1) { | 585 } else if (track) { |
588 TrackOutside(&outsideTs, span->fT, oTestT); | 586 TrackOutsidePair(&outsidePts, testPt, oTestPt); |
589 } | 587 } |
590 span = &fTs[++index]; | 588 SkASSERT(index < fTs.count() - 1); |
591 } while (approximately_negative(span->fT - testT)); | 589 test = &fTs[++index]; |
592 SkOpSpan* oSpan = oTest; | 590 } while (testPt == test->fPt); |
593 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio; | 591 SkDEBUGCODE(int originalWindValue = oTest->fWindValue); |
594 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio; | 592 do { |
595 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue); | 593 SkASSERT(oTest->fT < 1); |
596 while (approximately_negative(otherTMatchStart - oSpan->fT) | 594 SkASSERT(originalWindValue == oTest->fWindValue); |
597 && !approximately_negative(otherTMatchEnd - oSpan->fT)) { | |
598 #ifdef SK_DEBUG | |
599 SkASSERT(originalWindValue == oSpan->fWindValue); | |
600 #endif | |
601 if (decrement) { | 595 if (decrement) { |
602 if (binary && !bigger) { | 596 if (binary && !bigger) { |
603 oSpan->fOppValue--; | 597 oTest->fOppValue--; |
604 } else { | 598 } else { |
605 other->decrementSpan(oSpan); | 599 other->decrementSpan(oTest); |
606 } | 600 } |
607 } else if (track && oSpan->fT < 1 && testT < 1) { | 601 } else if (track) { |
608 TrackOutside(&oOutsideTs, oSpan->fT, testT); | 602 TrackOutsidePair(&oOutsidePts, oTestPt, testPt); |
609 } | 603 } |
610 if (!oIndex) { | 604 if (!oIndex) { |
611 break; | 605 break; |
612 } | 606 } |
613 oSpan = &other->fTs[--oIndex]; | 607 oTest = &other->fTs[--oIndex]; |
614 } | 608 } while (oTestPt == oTest->fPt); |
615 test = span; | 609 SkASSERT(endPt != test->fPt || oTestPt == endPt); |
616 oTest = oSpan; | 610 } while (endPt != test->fPt); |
617 } while (!approximately_negative(endT - test->fT)); | |
618 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT)); | |
619 // FIXME: determine if canceled edges need outside ts added | 611 // FIXME: determine if canceled edges need outside ts added |
620 if (!done() && outsideTs.count()) { | 612 int outCount = outsidePts.count(); |
621 double tStart = outsideTs[0]; | 613 if (!done() && outCount) { |
622 double oStart = outsideTs[1]; | 614 addCancelOutsides(outsidePts[0], outsidePts[1], other); |
623 addCancelOutsides(tStart, oStart, other, oEndT); | 615 if (outCount > 2) { |
624 int count = outsideTs.count(); | 616 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); |
625 if (count > 2) { | |
626 double tStart = outsideTs[count - 2]; | |
627 double oStart = outsideTs[count - 1]; | |
628 addCancelOutsides(tStart, oStart, other, oEndT); | |
629 } | 617 } |
630 } | 618 } |
631 if (!other->done() && oOutsideTs.count()) { | 619 if (!other->done() && oOutsidePts.count()) { |
632 double tStart = oOutsideTs[0]; | 620 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); |
633 double oStart = oOutsideTs[1]; | |
634 other->addCancelOutsides(tStart, oStart, this, endT); | |
635 } | 621 } |
636 } | 622 } |
637 | 623 |
638 int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) { | 624 int SkOpSegment::addSelfT(SkOpSegment* other, const SkPoint& pt, double newT) { |
639 int result = addT(other, pt, newT); | 625 // if the tail nearly intersects itself but not quite, the caller records th
is separately |
| 626 int result = addT(other, pt, newT, SkOpSpan::kPointIsExact); |
640 SkOpSpan* span = &fTs[result]; | 627 SkOpSpan* span = &fTs[result]; |
641 span->fLoop = true; | 628 span->fLoop = true; |
642 return result; | 629 return result; |
643 } | 630 } |
644 | 631 |
645 int SkOpSegment::addUnsortableT(SkOpSegment* other, bool start, const SkPoint& p
t, double newT) { | 632 void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* in
dexPtr, |
646 int result = addT(other, pt, newT); | 633 SkTArray<SkPoint, true>* outsideTs) { |
647 SkOpSpan* span = &fTs[result]; | 634 int index = *indexPtr; |
648 if (start) { | |
649 if (result > 0) { | |
650 span[result - 1].fUnsortableEnd = true; | |
651 } | |
652 span[result].fUnsortableStart = true; | |
653 } else { | |
654 span[result].fUnsortableEnd = true; | |
655 if (result + 1 < fTs.count()) { | |
656 span[result + 1].fUnsortableStart = true; | |
657 } | |
658 } | |
659 return result; | |
660 } | |
661 | |
662 int SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool opp, int index, | |
663 SkTArray<double, true>* outsideTs) { | |
664 int oWindValue = oTest.fWindValue; | 635 int oWindValue = oTest.fWindValue; |
665 int oOppValue = oTest.fOppValue; | 636 int oOppValue = oTest.fOppValue; |
666 if (opp) { | 637 if (binary) { |
667 SkTSwap<int>(oWindValue, oOppValue); | 638 SkTSwap<int>(oWindValue, oOppValue); |
668 } | 639 } |
669 SkOpSpan* const test = &fTs[index]; | 640 SkOpSpan* const test = &fTs[index]; |
670 SkOpSpan* end = test; | 641 SkOpSpan* end = test; |
671 const double oStartT = oTest.fT; | 642 const SkPoint& oStartPt = oTest.fPt; |
672 do { | 643 do { |
673 if (bumpSpan(end, oWindValue, oOppValue)) { | 644 if (bumpSpan(end, oWindValue, oOppValue)) { |
674 TrackOutside(outsideTs, end->fT, oStartT); | 645 TrackOutside(outsideTs, oStartPt); |
675 } | 646 } |
676 end = &fTs[++index]; | 647 end = &fTs[++index]; |
677 } while (approximately_negative(end->fT - test->fT)); | 648 } while (end->fPt == test->fPt); |
678 return index; | 649 *indexPtr = index; |
| 650 } |
| 651 |
| 652 bool SkOpSegment::bumpCoincident(SkOpSpan* test, bool bigger, bool binary) { |
| 653 if (bigger) { |
| 654 if (binary) { |
| 655 if (fOppXor) { |
| 656 test->fOppValue ^= 1; |
| 657 } else { |
| 658 test->fOppValue++; |
| 659 } |
| 660 } else { |
| 661 if (fXor) { |
| 662 test->fWindValue ^= 1; |
| 663 } else { |
| 664 test->fWindValue++; |
| 665 } |
| 666 } |
| 667 if (!test->fWindValue && !test->fOppValue) { |
| 668 test->fDone = true; |
| 669 ++fDoneSpans; |
| 670 return true; |
| 671 } |
| 672 return false; |
| 673 } |
| 674 return decrementSpan(test); |
679 } | 675 } |
680 | 676 |
681 // because of the order in which coincidences are resolved, this and other | 677 // because of the order in which coincidences are resolved, this and other |
682 // may not have the same intermediate points. Compute the corresponding | 678 // may not have the same intermediate points. Compute the corresponding |
683 // intermediate T values (using this as the master, other as the follower) | 679 // intermediate T values (using this as the master, other as the follower) |
684 // and walk other conditionally -- hoping that it catches up in the end | 680 // and walk other conditionally -- hoping that it catches up in the end |
685 int SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, double oEndT, int& oI
ndex, | 681 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, |
686 SkTArray<double, true>* oOutsideTs) { | 682 SkTArray<SkPoint, true>* oOutsidePts) { |
| 683 int oIndex = *oIndexPtr; |
687 SkOpSpan* const oTest = &fTs[oIndex]; | 684 SkOpSpan* const oTest = &fTs[oIndex]; |
688 SkOpSpan* oEnd = oTest; | 685 SkOpSpan* oEnd = oTest; |
689 const double startT = test.fT; | 686 const SkPoint& startPt = test.fPt; |
690 const double oStartT = oTest->fT; | 687 const SkPoint& oStartPt = oTest->fPt; |
691 while (!approximately_negative(oEndT - oEnd->fT) | 688 if (oStartPt == oEnd->fPt) { |
692 && approximately_negative(oEnd->fT - oStartT)) { | 689 TrackOutside(oOutsidePts, startPt); |
| 690 } |
| 691 while (oStartPt == oEnd->fPt) { |
693 zeroSpan(oEnd); | 692 zeroSpan(oEnd); |
694 TrackOutside(oOutsideTs, oEnd->fT, startT); | |
695 oEnd = &fTs[++oIndex]; | 693 oEnd = &fTs[++oIndex]; |
696 } | 694 } |
697 return oIndex; | 695 *oIndexPtr = oIndex; |
698 } | 696 } |
699 | 697 |
700 // FIXME: need to test this case: | 698 // FIXME: need to test this case: |
701 // contourA has two segments that are coincident | 699 // contourA has two segments that are coincident |
702 // contourB has two segments that are coincident in the same place | 700 // contourB has two segments that are coincident in the same place |
703 // each ends up with +2/0 pairs for winding count | 701 // each ends up with +2/0 pairs for winding count |
704 // since logic below doesn't transfer count (only increments/decrements) can thi
s be | 702 // since logic below doesn't transfer count (only increments/decrements) can thi
s be |
705 // resolved to +4/0 ? | 703 // resolved to +4/0 ? |
706 | 704 |
707 // set spans from start to end to increment the greater by one and decrement | 705 // set spans from start to end to increment the greater by one and decrement |
708 // the lesser | 706 // the lesser |
709 void SkOpSegment::addTCoincident(double startT, double endT, SkOpSegment* other,
double oStartT, | 707 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, |
710 double oEndT) { | 708 SkOpSegment* other) { |
711 SkASSERT(!approximately_negative(endT - startT)); | 709 bool binary = fOperand != other->fOperand; |
712 SkASSERT(!approximately_negative(oEndT - oStartT)); | |
713 bool opp = fOperand ^ other->fOperand; | |
714 int index = 0; | 710 int index = 0; |
715 while (!approximately_negative(startT - fTs[index].fT)) { | 711 while (startPt != fTs[index].fPt) { |
| 712 SkASSERT(index < fTs.count()); |
716 ++index; | 713 ++index; |
717 } | 714 } |
718 int oIndex = 0; | 715 int oIndex = 0; |
719 while (!approximately_negative(oStartT - other->fTs[oIndex].fT)) { | 716 while (startPt != other->fTs[oIndex].fPt) { |
| 717 SkASSERT(oIndex < other->fTs.count()); |
720 ++oIndex; | 718 ++oIndex; |
721 } | 719 } |
| 720 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
| 721 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
722 SkOpSpan* test = &fTs[index]; | 722 SkOpSpan* test = &fTs[index]; |
| 723 const SkPoint* testPt = &test->fPt; |
723 SkOpSpan* oTest = &other->fTs[oIndex]; | 724 SkOpSpan* oTest = &other->fTs[oIndex]; |
724 SkSTArray<kOutsideTrackedTCount, double, true> outsideTs; | 725 const SkPoint* oTestPt = &oTest->fPt; |
725 SkSTArray<kOutsideTrackedTCount, double, true> oOutsideTs; | 726 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
726 do { | 727 do { |
727 // if either span has an opposite value and the operands don't match, re
solve first | 728 SkASSERT(test->fT < 1); |
728 // SkASSERT(!test->fDone || !oTest->fDone); | 729 SkASSERT(oTest->fT < 1); |
| 730 #if 0 |
729 if (test->fDone || oTest->fDone) { | 731 if (test->fDone || oTest->fDone) { |
730 index = advanceCoincidentThis(oTest, opp, index); | 732 #else // consolidate the winding count even if done |
731 oIndex = other->advanceCoincidentOther(test, oEndT, oIndex); | 733 if ((test->fWindValue == 0 && test->fOppValue == 0) |
| 734 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { |
| 735 #endif |
| 736 SkDEBUGCODE(int firstWind = test->fWindValue); |
| 737 SkDEBUGCODE(int firstOpp = test->fOppValue); |
| 738 do { |
| 739 SkASSERT(firstWind == fTs[index].fWindValue); |
| 740 SkASSERT(firstOpp == fTs[index].fOppValue); |
| 741 ++index; |
| 742 SkASSERT(index < fTs.count()); |
| 743 } while (*testPt == fTs[index].fPt); |
| 744 SkDEBUGCODE(firstWind = oTest->fWindValue); |
| 745 SkDEBUGCODE(firstOpp = oTest->fOppValue); |
| 746 do { |
| 747 SkASSERT(firstWind == other->fTs[oIndex].fWindValue); |
| 748 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue); |
| 749 ++oIndex; |
| 750 SkASSERT(oIndex < other->fTs.count()); |
| 751 } while (*oTestPt == other->fTs[oIndex].fPt); |
732 } else { | 752 } else { |
733 index = bumpCoincidentThis(*oTest, opp, index, &outsideTs); | 753 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { |
734 oIndex = other->bumpCoincidentOther(*test, oEndT, oIndex, &oOutsideT
s); | 754 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); |
| 755 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); |
| 756 } else { |
| 757 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); |
| 758 bumpCoincidentOther(*oTest, &index, &outsidePts); |
| 759 } |
735 } | 760 } |
736 test = &fTs[index]; | 761 test = &fTs[index]; |
| 762 testPt = &test->fPt; |
| 763 if (endPt == *testPt) { |
| 764 break; |
| 765 } |
737 oTest = &other->fTs[oIndex]; | 766 oTest = &other->fTs[oIndex]; |
738 } while (!approximately_negative(endT - test->fT)); | 767 oTestPt = &oTest->fPt; |
739 SkASSERT(approximately_negative(oTest->fT - oEndT)); | 768 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
740 SkASSERT(approximately_negative(oEndT - oTest->fT)); | 769 } while (endPt != *oTestPt); |
741 if (!done() && outsideTs.count()) { | 770 int outCount = outsidePts.count(); |
742 addCoinOutsides(outsideTs, other, oEndT); | 771 if (!done() && outCount) { |
| 772 addCoinOutsides(outsidePts[0], endPt, other); |
743 } | 773 } |
744 if (!other->done() && oOutsideTs.count()) { | 774 if (!other->done() && oOutsidePts.count()) { |
745 other->addCoinOutsides(oOutsideTs, this, endT); | 775 other->addCoinOutsides(oOutsidePts[0], endPt, this); |
746 } | 776 } |
747 } | 777 } |
748 | 778 |
749 // FIXME: this doesn't prevent the same span from being added twice | 779 // FIXME: this doesn't prevent the same span from being added twice |
750 // fix in caller, SkASSERT here? | 780 // fix in caller, SkASSERT here? |
751 void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool bor
rowWind, | 781 void SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool bor
rowWind, |
752 const SkPoint& pt) { | 782 const SkPoint& pt) { |
753 int tCount = fTs.count(); | 783 int tCount = fTs.count(); |
754 for (int tIndex = 0; tIndex < tCount; ++tIndex) { | 784 for (int tIndex = 0; tIndex < tCount; ++tIndex) { |
755 const SkOpSpan& span = fTs[tIndex]; | 785 const SkOpSpan& span = fTs[tIndex]; |
756 if (!approximately_negative(span.fT - t)) { | 786 if (!approximately_negative(span.fT - t)) { |
757 break; | 787 break; |
758 } | 788 } |
759 if (approximately_negative(span.fT - t) && span.fOther == other | 789 if (approximately_negative(span.fT - t) && span.fOther == other |
760 && approximately_equal(span.fOtherT, otherT)) { | 790 && approximately_equal(span.fOtherT, otherT)) { |
761 #if DEBUG_ADD_T_PAIR | 791 #if DEBUG_ADD_T_PAIR |
762 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", | 792 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", |
763 __FUNCTION__, fID, t, other->fID, otherT); | 793 __FUNCTION__, fID, t, other->fID, otherT); |
764 #endif | 794 #endif |
765 return; | 795 return; |
766 } | 796 } |
767 } | 797 } |
768 #if DEBUG_ADD_T_PAIR | 798 #if DEBUG_ADD_T_PAIR |
769 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", | 799 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", |
770 __FUNCTION__, fID, t, other->fID, otherT); | 800 __FUNCTION__, fID, t, other->fID, otherT); |
771 #endif | 801 #endif |
772 int insertedAt = addT(other, pt, t); | 802 int insertedAt = addT(other, pt, t, SkOpSpan::kPointIsExact); |
773 int otherInsertedAt = other->addT(this, pt, otherT); | 803 int otherInsertedAt = other->addT(this, pt, otherT, SkOpSpan::kPointIsExact)
; |
774 addOtherT(insertedAt, otherT, otherInsertedAt); | 804 addOtherT(insertedAt, otherT, otherInsertedAt); |
775 other->addOtherT(otherInsertedAt, t, insertedAt); | 805 other->addOtherT(otherInsertedAt, t, insertedAt); |
776 matchWindingValue(insertedAt, t, borrowWind); | 806 matchWindingValue(insertedAt, t, borrowWind); |
777 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); | 807 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); |
778 } | 808 } |
779 | 809 |
780 void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* an
gles) const { | 810 void SkOpSegment::addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* an
gles) const { |
781 // add edge leading into junction | 811 // add edge leading into junction |
782 int min = SkMin32(end, start); | 812 int min = SkMin32(end, start); |
783 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) { | 813 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) { |
784 addAngle(angles, end, start); | 814 addAngle(angles, end, start); |
785 } | 815 } |
786 // add edge leading away from junction | 816 // add edge leading away from junction |
787 int step = SkSign32(end - start); | 817 int step = SkSign32(end - start); |
788 int tIndex = nextExactSpan(end, step); | 818 int tIndex = nextExactSpan(end, step); |
789 min = SkMin32(end, tIndex); | 819 min = SkMin32(end, tIndex); |
790 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) { | 820 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) { |
791 addAngle(angles, end, tIndex); | 821 addAngle(angles, end, tIndex); |
792 } | 822 } |
793 } | 823 } |
794 | 824 |
795 int SkOpSegment::advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int inde
x) { | 825 SkOpSegment::MissingSpan::Command SkOpSegment::adjustThisNear(double startT, con
st SkPoint& startPt, |
| 826 const SkPoint& endPt, SkTArray<MissingSpan, true>* missingSpans) { |
| 827 // see if endPt exists on this curve, and if it has the same t or a differen
t T than the startT |
| 828 int count = this->count(); |
| 829 SkASSERT(count > 0); |
| 830 int startIndex, endIndex, step; |
| 831 if (startT == 0) { |
| 832 startIndex = 0; |
| 833 endIndex = count; |
| 834 step = 1; |
| 835 } else { |
| 836 SkASSERT(startT == 1); |
| 837 startIndex = count - 1; |
| 838 endIndex = -1; |
| 839 step = -1; |
| 840 } |
| 841 int index = startIndex; |
| 842 do { |
| 843 const SkOpSpan& span = fTs[index]; |
| 844 if (span.fPt != endPt) { |
| 845 continue; |
| 846 } |
| 847 if (span.fT == startT) { |
| 848 // check to see if otherT matches some other mid curve intersection |
| 849 int inner = startIndex; |
| 850 do { |
| 851 if (inner == index) { |
| 852 continue; |
| 853 } |
| 854 const SkOpSpan& matchSpan = fTs[inner]; |
| 855 double matchT = span.fOther->missingNear(span.fOtherT, matchSpan
.fOther, startPt, |
| 856 endPt); |
| 857 if (matchT >= 0) { |
| 858 SkASSERT(missingSpans); |
| 859 MissingSpan& missingSpan = missingSpans->push_back(); |
| 860 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan))); |
| 861 missingSpan.fCommand = MissingSpan::kRemoveNear; |
| 862 missingSpan.fT = startT; |
| 863 missingSpan.fSegment = this; |
| 864 missingSpan.fOther = span.fOther; |
| 865 missingSpan.fOtherT = matchT; |
| 866 return missingSpan.fCommand; |
| 867 } |
| 868 } while ((inner += step) != endIndex); |
| 869 break; |
| 870 } |
| 871 double midT = (startT + span.fT) / 2; |
| 872 if (betweenPoints(midT, startPt, endPt)) { |
| 873 if (!missingSpans) { |
| 874 return MissingSpan::kZeroSpan; |
| 875 } |
| 876 MissingSpan& missingSpan = missingSpans->push_back(); |
| 877 SkDEBUGCODE(sk_bzero(&missingSpan, sizeof(missingSpan))); |
| 878 missingSpan.fCommand = MissingSpan::kZeroSpan; |
| 879 missingSpan.fT = SkTMin(startT, span.fT); |
| 880 missingSpan.fEndT = SkTMax(startT, span.fT); |
| 881 missingSpan.fSegment = this; |
| 882 return missingSpan.fCommand; |
| 883 } |
| 884 } while ((index += step) != endIndex); |
| 885 return MissingSpan::kNoAction; |
| 886 } |
| 887 |
| 888 void SkOpSegment::adjustOtherNear(double startT, const SkPoint& startPt, const S
kPoint& endPt, |
| 889 SkTArray<MissingSpan, true>* missingSpans) { |
| 890 int count = this->count(); |
| 891 SkASSERT(count > 0); |
| 892 int startIndex, endIndex, step; |
| 893 if (startT == 0) { |
| 894 startIndex = 0; |
| 895 endIndex = count; |
| 896 step = 1; |
| 897 } else { |
| 898 SkASSERT(startT == 1); |
| 899 startIndex = count - 1; |
| 900 endIndex = -1; |
| 901 step = -1; |
| 902 } |
| 903 int index = startIndex; |
| 904 do { |
| 905 const SkOpSpan& span = fTs[index]; |
| 906 if (span.fT != startT) { |
| 907 return; |
| 908 } |
| 909 SkOpSegment* other = span.fOther; |
| 910 if (other->fPts[0] == endPt) { |
| 911 other->adjustThisNear(0, endPt, startPt, missingSpans); |
| 912 } else if (other->fPts[0] == startPt) { |
| 913 other->adjustThisNear(0, startPt, endPt, missingSpans); |
| 914 } |
| 915 if (other->ptAtT(1) == endPt) { |
| 916 other->adjustThisNear(1, endPt, startPt, missingSpans); |
| 917 } else if (other->ptAtT(1) == startPt) { |
| 918 other->adjustThisNear(1, startPt, endPt, missingSpans); |
| 919 } |
| 920 } while ((index += step) != endIndex); |
| 921 } |
| 922 |
| 923 void SkOpSegment::adjustMissingNear(const SkPoint& startPt, const SkPoint& endPt
, |
| 924 SkTArray<MissingSpan, true>* missingSpans) { |
| 925 int count = missingSpans->count(); |
| 926 for (int index = 0; index < count; ) { |
| 927 MissingSpan& missing = (*missingSpans)[index]; |
| 928 SkOpSegment* other = missing.fOther; |
| 929 MissingSpan::Command command = MissingSpan::kNoAction; |
| 930 if (missing.fPt == startPt) { |
| 931 if (missingNear(missing.fT, other, startPt, endPt) >= 0) { |
| 932 command = MissingSpan::kZeroSpan; |
| 933 } else if (other->ptAtT(0) == endPt) { |
| 934 command = other->adjustThisNear(0, endPt, startPt, NULL); |
| 935 } else if (other->ptAtT(1) == endPt) { |
| 936 command = other->adjustThisNear(1, endPt, startPt, NULL); |
| 937 } |
| 938 } else if (missing.fPt == endPt) { |
| 939 if (missingNear(missing.fT, other, endPt, startPt) >= 0) { |
| 940 command = MissingSpan::kZeroSpan; |
| 941 } else if (other->ptAtT(0) == startPt) { |
| 942 command = other->adjustThisNear(0, startPt, endPt, NULL); |
| 943 } else if (other->ptAtT(1) == startPt) { |
| 944 command = other->adjustThisNear(1, startPt, endPt, NULL); |
| 945 } |
| 946 } |
| 947 if (command == MissingSpan::kZeroSpan) { |
| 948 #if 1 |
| 949 missing = missingSpans->back(); |
| 950 missingSpans->pop_back(); |
| 951 #else // if this is supported in the future ... |
| 952 missingSpans->removeShuffle(index); |
| 953 #endif |
| 954 --count; |
| 955 continue; |
| 956 } |
| 957 ++index; |
| 958 } |
| 959 } |
| 960 |
| 961 void SkOpSegment::adjustNear(double startT, const SkPoint& endPt, |
| 962 SkTArray<MissingSpan, true>* missingSpans) { |
| 963 const SkPoint startPt = ptAtT(startT); |
| 964 adjustMissingNear(startPt, endPt, missingSpans); |
| 965 adjustThisNear(startT, startPt, endPt, missingSpans); |
| 966 adjustOtherNear(startT, startPt, endPt, missingSpans); |
| 967 } |
| 968 |
| 969 int SkOpSegment::advanceCoincidentThis(int index) { |
796 SkOpSpan* const test = &fTs[index]; | 970 SkOpSpan* const test = &fTs[index]; |
797 SkOpSpan* end; | 971 SkOpSpan* end; |
798 do { | 972 do { |
799 end = &fTs[++index]; | 973 end = &fTs[++index]; |
800 } while (approximately_negative(end->fT - test->fT)); | 974 } while (approximately_negative(end->fT - test->fT)); |
801 return index; | 975 return index; |
802 } | 976 } |
803 | 977 |
804 int SkOpSegment::advanceCoincidentOther(const SkOpSpan* test, double oEndT, int
oIndex) { | 978 int SkOpSegment::advanceCoincidentOther(double oEndT, int oIndex) { |
805 SkOpSpan* const oTest = &fTs[oIndex]; | 979 SkOpSpan* const oTest = &fTs[oIndex]; |
806 SkOpSpan* oEnd = oTest; | 980 SkOpSpan* oEnd = oTest; |
807 const double oStartT = oTest->fT; | 981 const double oStartT = oTest->fT; |
808 while (!approximately_negative(oEndT - oEnd->fT) | 982 while (!approximately_negative(oEndT - oEnd->fT) |
809 && approximately_negative(oEnd->fT - oStartT)) { | 983 && approximately_negative(oEnd->fT - oStartT)) { |
810 oEnd = &fTs[++oIndex]; | 984 oEnd = &fTs[++oIndex]; |
811 } | 985 } |
812 return oIndex; | 986 return oIndex; |
813 } | 987 } |
814 | 988 |
| 989 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint&
pt2) const { |
| 990 const SkPoint midPt = ptAtT(midT); |
| 991 SkPathOpsBounds bounds; |
| 992 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY); |
| 993 bounds.sort(); |
| 994 return bounds.almostContains(midPt); |
| 995 } |
| 996 |
815 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { | 997 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { |
816 if (lesser > greater) { | 998 if (lesser > greater) { |
817 SkTSwap<int>(lesser, greater); | 999 SkTSwap<int>(lesser, greater); |
818 } | 1000 } |
819 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); | 1001 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); |
820 } | 1002 } |
821 | 1003 |
822 void SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool
includeOpp) const { | 1004 // note that this follows the same logic flow as active angle |
| 1005 bool SkOpSegment::buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool
allowOpp) const { |
823 double referenceT = fTs[index].fT; | 1006 double referenceT = fTs[index].fT; |
| 1007 const SkPoint& referencePt = fTs[index].fPt; |
824 int lesser = index; | 1008 int lesser = index; |
825 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOper
and) | 1009 while (--lesser >= 0 && (allowOpp || fTs[lesser].fOther->fOperand == fOperan
d) |
826 && precisely_negative(referenceT - fTs[lesser].fT)) { | 1010 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].f
Tiny)) { |
827 buildAnglesInner(lesser, angles); | 1011 buildAnglesInner(lesser, angles); |
828 } | 1012 } |
829 do { | 1013 do { |
830 buildAnglesInner(index, angles); | 1014 buildAnglesInner(index, angles); |
831 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand
== fOperand) | 1015 if (++index == fTs.count()) { |
832 && precisely_negative(fTs[index].fT - referenceT)); | 1016 break; |
| 1017 } |
| 1018 if (!allowOpp && fTs[index].fOther->fOperand != fOperand) { |
| 1019 break; |
| 1020 } |
| 1021 if (fTs[index - 1].fTiny) { |
| 1022 referenceT = fTs[index].fT; |
| 1023 continue; |
| 1024 } |
| 1025 if (!precisely_negative(fTs[index].fT - referenceT) && fTs[index].fPt ==
referencePt) { |
| 1026 // FIXME |
| 1027 // testQuad8 generates the wrong output unless false is returned her
e. Other tests will |
| 1028 // take this path although they aren't required to. This means that
many go much slower |
| 1029 // because of this sort fail. |
| 1030 // SkDebugf("!!!\n"); |
| 1031 return false; |
| 1032 } |
| 1033 } while (precisely_negative(fTs[index].fT - referenceT)); |
| 1034 return true; |
833 } | 1035 } |
834 | 1036 |
835 void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles)
const { | 1037 void SkOpSegment::buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles)
const { |
836 const SkOpSpan* span = &fTs[index]; | 1038 const SkOpSpan* span = &fTs[index]; |
837 SkOpSegment* other = span->fOther; | 1039 SkOpSegment* other = span->fOther; |
838 // if there is only one live crossing, and no coincidence, continue | 1040 // if there is only one live crossing, and no coincidence, continue |
839 // in the same direction | 1041 // in the same direction |
840 // if there is coincidence, the only choice may be to reverse direction | 1042 // if there is coincidence, the only choice may be to reverse direction |
841 // find edge on either side of intersection | 1043 // find edge on either side of intersection |
842 int oIndex = span->fOtherIndex; | 1044 int oIndex = span->fOtherIndex; |
843 // if done == -1, prior span has already been processed | 1045 // if done == -1, prior span has already been processed |
844 int step = 1; | 1046 int step = 1; |
845 int next = other->nextExactSpan(oIndex, step); | 1047 int next = other->nextExactSpan(oIndex, step); |
846 if (next < 0) { | 1048 if (next < 0) { |
847 step = -step; | 1049 step = -step; |
848 next = other->nextExactSpan(oIndex, step); | 1050 next = other->nextExactSpan(oIndex, step); |
849 } | 1051 } |
850 // add candidate into and away from junction | 1052 // add candidate into and away from junction |
851 other->addTwoAngles(next, oIndex, angles); | 1053 other->addTwoAngles(next, oIndex, angles); |
852 } | 1054 } |
853 | 1055 |
854 int SkOpSegment::computeSum(int startIndex, int endIndex, bool binary) { | 1056 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType
includeType, |
855 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 1057 SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted) { |
856 addTwoAngles(startIndex, endIndex, &angles); | 1058 addTwoAngles(startIndex, endIndex, angles); |
857 buildAngles(endIndex, &angles, false); | 1059 if (!buildAngles(endIndex, angles, includeType == SkOpAngle::kBinaryOpp)) { |
858 // OPTIMIZATION: check all angles to see if any have computed wind sum | 1060 return SK_NaN32; |
859 // before sorting (early exit if none) | 1061 } |
860 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 1062 int angleCount = angles->count(); |
861 // FIXME?: Not sure if this sort must be ordered or if the relaxed ordering
is OK ... | 1063 // abort early before sorting if an unsortable (not an unorderable) angle is
found |
862 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); | 1064 if (includeType != SkOpAngle::kUnaryXor) { |
863 #if DEBUG_SORT | 1065 int firstIndex = -1; |
864 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable)
; | 1066 while (++firstIndex < angleCount) { |
| 1067 const SkOpAngle& angle = (*angles)[firstIndex]; |
| 1068 if (angle.segment()->windSum(&angle) != SK_MinS32) { |
| 1069 break; |
| 1070 } |
| 1071 } |
| 1072 if (firstIndex == angleCount) { |
| 1073 return SK_MinS32; |
| 1074 } |
| 1075 } |
| 1076 bool sortable = SortAngles2(*angles, sorted); |
| 1077 #if DEBUG_SORT_RAW |
| 1078 if (sorted->count() > 0) { |
| 1079 (*sorted)[0]->segment()->debugShowSort(__FUNCTION__, *sorted, 0, 0, 0, s
ortable); |
| 1080 } |
865 #endif | 1081 #endif |
866 if (!sortable) { | 1082 if (!sortable) { |
| 1083 return SK_NaN32; |
| 1084 } |
| 1085 if (includeType == SkOpAngle::kUnaryXor) { |
867 return SK_MinS32; | 1086 return SK_MinS32; |
868 } | 1087 } |
869 int angleCount = angles.count(); | 1088 // if all angles have a computed winding, |
870 const SkOpAngle* angle; | 1089 // or if no adjacent angles are orderable, |
871 const SkOpSegment* base; | 1090 // or if adjacent orderable angles have no computed winding, |
872 int winding; | 1091 // there's nothing to do |
873 int oWinding; | 1092 // if two orderable angles are adjacent, and one has winding computed, trans
fer to the other |
874 int firstIndex = 0; | 1093 const SkOpAngle* baseAngle = NULL; |
| 1094 int last = angleCount; |
| 1095 int finalInitialOrderable = -1; |
| 1096 bool tryReverse = false; |
| 1097 // look for counterclockwise transfers |
875 do { | 1098 do { |
876 angle = sorted[firstIndex]; | 1099 int index = 0; |
877 base = angle->segment(); | 1100 do { |
878 winding = base->windSum(angle); | 1101 SkOpAngle* testAngle = (*sorted)[index]; |
879 if (winding != SK_MinS32) { | 1102 int testWinding = testAngle->segment()->windSum(testAngle); |
880 oWinding = base->oppSum(angle); | 1103 if (SK_MinS32 != testWinding && !testAngle->unorderable()) { |
| 1104 baseAngle = testAngle; |
| 1105 continue; |
| 1106 } |
| 1107 if (testAngle->unorderable()) { |
| 1108 baseAngle = NULL; |
| 1109 tryReverse = true; |
| 1110 continue; |
| 1111 } |
| 1112 if (baseAngle) { |
| 1113 ComputeOneSum(baseAngle, testAngle, includeType); |
| 1114 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testAngle
) ? testAngle |
| 1115 : NULL; |
| 1116 tryReverse |= !baseAngle; |
| 1117 continue; |
| 1118 } |
| 1119 if (finalInitialOrderable + 1 == index) { |
| 1120 finalInitialOrderable = index; |
| 1121 } |
| 1122 } while (++index != last); |
| 1123 if (finalInitialOrderable < 0) { |
881 break; | 1124 break; |
882 } | 1125 } |
883 if (++firstIndex == angleCount) { | 1126 last = finalInitialOrderable + 1; |
884 return SK_MinS32; | 1127 finalInitialOrderable = -2; // make this always negative the second tim
e through |
885 } | 1128 } while (baseAngle); |
886 } while (true); | 1129 if (tryReverse) { |
887 // turn winding into contourWinding | 1130 baseAngle = NULL; |
888 int spanWinding = base->spanSign(angle); | 1131 last = 0; |
889 bool inner = UseInnerWinding(winding + spanWinding, winding); | 1132 finalInitialOrderable = angleCount; |
890 #if DEBUG_WINDING | 1133 do { |
891 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNC
TION__, | 1134 int index = angleCount; |
892 spanWinding, winding, angle->sign(), inner, | 1135 while (--index >= last) { |
893 inner ? winding + spanWinding : winding); | 1136 SkOpAngle* testAngle = (*sorted)[index]; |
894 #endif | 1137 int testWinding = testAngle->segment()->windSum(testAngle); |
895 if (inner) { | 1138 if (SK_MinS32 != testWinding) { |
896 winding += spanWinding; | 1139 baseAngle = testAngle; |
| 1140 continue; |
| 1141 } |
| 1142 if (testAngle->unorderable()) { |
| 1143 baseAngle = NULL; |
| 1144 continue; |
| 1145 } |
| 1146 if (baseAngle) { |
| 1147 ComputeOneSumReverse(baseAngle, testAngle, includeType); |
| 1148 baseAngle = SK_MinS32 != testAngle->segment()->windSum(testA
ngle) ? testAngle |
| 1149 : NULL; |
| 1150 continue; |
| 1151 } |
| 1152 if (finalInitialOrderable - 1 == index) { |
| 1153 finalInitialOrderable = index; |
| 1154 } |
| 1155 } |
| 1156 if (finalInitialOrderable >= angleCount) { |
| 1157 break; |
| 1158 } |
| 1159 last = finalInitialOrderable; |
| 1160 finalInitialOrderable = angleCount + 1; // make this inactive 2nd t
ime through |
| 1161 } while (baseAngle); |
897 } | 1162 } |
898 #if DEBUG_SORT | |
899 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding, sor
table); | |
900 #endif | |
901 int nextIndex = firstIndex + 1; | |
902 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | |
903 winding -= base->spanSign(angle); | |
904 oWinding -= base->oppSign(angle); | |
905 do { | |
906 if (nextIndex == angleCount) { | |
907 nextIndex = 0; | |
908 } | |
909 angle = sorted[nextIndex]; | |
910 SkOpSegment* segment = angle->segment(); | |
911 bool opp = base->fOperand ^ segment->fOperand; | |
912 int maxWinding, oMaxWinding; | |
913 int spanSign = segment->spanSign(angle); | |
914 int oppoSign = segment->oppSign(angle); | |
915 if (opp) { | |
916 oMaxWinding = oWinding; | |
917 oWinding -= spanSign; | |
918 maxWinding = winding; | |
919 if (oppoSign) { | |
920 winding -= oppoSign; | |
921 } | |
922 } else { | |
923 maxWinding = winding; | |
924 winding -= spanSign; | |
925 oMaxWinding = oWinding; | |
926 if (oppoSign) { | |
927 oWinding -= oppoSign; | |
928 } | |
929 } | |
930 if (segment->windSum(angle) == SK_MinS32) { | |
931 if (opp) { | |
932 if (UseInnerWinding(oMaxWinding, oWinding)) { | |
933 oMaxWinding = oWinding; | |
934 } | |
935 if (oppoSign && UseInnerWinding(maxWinding, winding)) { | |
936 maxWinding = winding; | |
937 } | |
938 #ifdef SK_DEBUG | |
939 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum); | |
940 SkASSERT(abs(oMaxWinding) <= gDebugMaxWindSum); | |
941 #endif | |
942 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWindi
ng); | |
943 } else { | |
944 if (UseInnerWinding(maxWinding, winding)) { | |
945 maxWinding = winding; | |
946 } | |
947 if (oppoSign && UseInnerWinding(oMaxWinding, oWinding)) { | |
948 oMaxWinding = oWinding; | |
949 } | |
950 #ifdef SK_DEBUG | |
951 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum); | |
952 SkASSERT(abs(binary ? oMaxWinding : 0) <= gDebugMaxWindSum); | |
953 #endif | |
954 (void) segment->markAndChaseWinding(angle, maxWinding, | |
955 binary ? oMaxWinding : 0); | |
956 } | |
957 } | |
958 } while (++nextIndex != lastIndex); | |
959 int minIndex = SkMin32(startIndex, endIndex); | 1163 int minIndex = SkMin32(startIndex, endIndex); |
960 return windSum(minIndex); | 1164 return windSum(minIndex); |
961 } | 1165 } |
962 | 1166 |
| 1167 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
| 1168 SkOpAngle::IncludeType includeType) { |
| 1169 const SkOpSegment* baseSegment = baseAngle->segment(); |
| 1170 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
| 1171 int sumSuWinding; |
| 1172 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 1173 if (binary) { |
| 1174 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); |
| 1175 if (baseSegment->operand()) { |
| 1176 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 1177 } |
| 1178 } |
| 1179 SkOpSegment* nextSegment = nextAngle->segment(); |
| 1180 int maxWinding, sumWinding; |
| 1181 SkOpSpan* last; |
| 1182 if (binary) { |
| 1183 int oppMaxWinding, oppSumWinding; |
| 1184 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 1185 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); |
| 1186 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
| 1187 true, nextAngle); |
| 1188 } else { |
| 1189 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiW
inding, |
| 1190 &maxWinding, &sumWinding); |
| 1191 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle); |
| 1192 } |
| 1193 nextAngle->setLastMarked(last); |
| 1194 } |
| 1195 |
| 1196 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne
xtAngle, |
| 1197 SkOpAngle::IncludeType includeType) { |
| 1198 const SkOpSegment* baseSegment = baseAngle->segment(); |
| 1199 int sumMiWinding = baseSegment->updateWinding(baseAngle); |
| 1200 int sumSuWinding; |
| 1201 bool binary = includeType >= SkOpAngle::kBinarySingle; |
| 1202 if (binary) { |
| 1203 sumSuWinding = baseSegment->updateOppWinding(baseAngle); |
| 1204 if (baseSegment->operand()) { |
| 1205 SkTSwap<int>(sumMiWinding, sumSuWinding); |
| 1206 } |
| 1207 } |
| 1208 SkOpSegment* nextSegment = nextAngle->segment(); |
| 1209 int maxWinding, sumWinding; |
| 1210 SkOpSpan* last; |
| 1211 if (binary) { |
| 1212 int oppMaxWinding, oppSumWinding; |
| 1213 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, |
| 1214 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSum
Winding); |
| 1215 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, opp
SumWinding, |
| 1216 true, nextAngle); |
| 1217 } else { |
| 1218 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiW
inding, |
| 1219 &maxWinding, &sumWinding); |
| 1220 last = nextSegment->markAngle(maxWinding, sumWinding, true, nextAngle); |
| 1221 } |
| 1222 nextAngle->setLastMarked(last); |
| 1223 } |
| 1224 |
963 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, | 1225 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, |
964 bool* hitSomething, double mid, bool opp, bool cur
rent) const { | 1226 bool* hitSomething, double mid, bool opp, bool cur
rent) const { |
965 SkScalar bottom = fBounds.fBottom; | 1227 SkScalar bottom = fBounds.fBottom; |
966 int bestTIndex = -1; | 1228 int bestTIndex = -1; |
967 if (bottom <= *bestY) { | 1229 if (bottom <= *bestY) { |
968 return bestTIndex; | 1230 return bestTIndex; |
969 } | 1231 } |
970 SkScalar top = fBounds.fTop; | 1232 SkScalar top = fBounds.fTop; |
971 if (top >= basePt.fY) { | 1233 if (top >= basePt.fY) { |
972 return bestTIndex; | 1234 return bestTIndex; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 ++start; | 1305 ++start; |
1044 } | 1306 } |
1045 if (!isCanceled(start)) { | 1307 if (!isCanceled(start)) { |
1046 *hitT = bestT; | 1308 *hitT = bestT; |
1047 bestTIndex = start; | 1309 bestTIndex = start; |
1048 *hitSomething = true; | 1310 *hitSomething = true; |
1049 } | 1311 } |
1050 return bestTIndex; | 1312 return bestTIndex; |
1051 } | 1313 } |
1052 | 1314 |
1053 void SkOpSegment::decrementSpan(SkOpSpan* span) { | 1315 bool SkOpSegment::decrementSpan(SkOpSpan* span) { |
1054 SkASSERT(span->fWindValue > 0); | 1316 SkASSERT(span->fWindValue > 0); |
1055 if (--(span->fWindValue) == 0) { | 1317 if (--(span->fWindValue) == 0) { |
1056 if (!span->fOppValue && !span->fDone) { | 1318 if (!span->fOppValue && !span->fDone) { |
1057 span->fDone = true; | 1319 span->fDone = true; |
1058 ++fDoneSpans; | 1320 ++fDoneSpans; |
| 1321 return true; |
1059 } | 1322 } |
1060 } | 1323 } |
| 1324 return false; |
1061 } | 1325 } |
1062 | 1326 |
1063 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { | 1327 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { |
1064 SkASSERT(!span->fDone); | 1328 SkASSERT(!span->fDone || span->fTiny); |
1065 span->fWindValue += windDelta; | 1329 span->fWindValue += windDelta; |
1066 SkASSERT(span->fWindValue >= 0); | 1330 SkASSERT(span->fWindValue >= 0); |
1067 span->fOppValue += oppDelta; | 1331 span->fOppValue += oppDelta; |
1068 SkASSERT(span->fOppValue >= 0); | 1332 SkASSERT(span->fOppValue >= 0); |
1069 if (fXor) { | 1333 if (fXor) { |
1070 span->fWindValue &= 1; | 1334 span->fWindValue &= 1; |
1071 } | 1335 } |
1072 if (fOppXor) { | 1336 if (fOppXor) { |
1073 span->fOppValue &= 1; | 1337 span->fOppValue &= 1; |
1074 } | 1338 } |
1075 if (!span->fWindValue && !span->fOppValue) { | 1339 if (!span->fWindValue && !span->fOppValue) { |
1076 span->fDone = true; | 1340 span->fDone = true; |
1077 ++fDoneSpans; | 1341 ++fDoneSpans; |
1078 return true; | 1342 return true; |
1079 } | 1343 } |
1080 return false; | 1344 return false; |
1081 } | 1345 } |
1082 | 1346 |
1083 // look to see if the curve end intersects an intermediary that intersects the o
ther | 1347 // look to see if the curve end intersects an intermediary that intersects the o
ther |
1084 void SkOpSegment::checkEnds() { | 1348 void SkOpSegment::checkEnds() { |
1085 debugValidate(); | 1349 debugValidate(); |
1086 SkTDArray<SkOpSpan> missingSpans; | 1350 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
1087 int count = fTs.count(); | 1351 int count = fTs.count(); |
1088 for (int index = 0; index < count; ++index) { | 1352 for (int index = 0; index < count; ++index) { |
1089 const SkOpSpan& span = fTs[index]; | 1353 const SkOpSpan& span = fTs[index]; |
| 1354 double otherT = span.fOtherT; |
| 1355 if (otherT != 0 && otherT != 1) { // only check ends |
| 1356 continue; |
| 1357 } |
1090 const SkOpSegment* other = span.fOther; | 1358 const SkOpSegment* other = span.fOther; |
1091 const SkOpSpan* otherSpan = &other->fTs[span.fOtherIndex]; | 1359 // peek start/last describe the range of spans that match the other t of
this span |
1092 double otherT = otherSpan->fT; | |
1093 if (otherT != 0 && otherT != 1) { | |
1094 continue; | |
1095 } | |
1096 int peekStart = span.fOtherIndex; | 1360 int peekStart = span.fOtherIndex; |
1097 while (peekStart > 0) { | 1361 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT) |
1098 const SkOpSpan* peeker = &other->fTs[peekStart - 1]; | 1362 ; |
1099 if (peeker->fT != otherT) { | 1363 int otherCount = other->fTs.count(); |
1100 break; | |
1101 } | |
1102 --peekStart; | |
1103 } | |
1104 int otherLast = other->fTs.count() - 1; | |
1105 int peekLast = span.fOtherIndex; | 1364 int peekLast = span.fOtherIndex; |
1106 while (peekLast < otherLast) { | 1365 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT) |
1107 const SkOpSpan* peeker = &other->fTs[peekLast + 1]; | 1366 ; |
1108 if (peeker->fT != otherT) { | 1367 if (++peekStart == --peekLast) { // if there isn't a range, there's noth
ing to do |
1109 break; | 1368 continue; |
1110 } | 1369 } |
1111 ++peekLast; | 1370 // t start/last describe the range of spans that match the t of this spa
n |
1112 } | |
1113 if (peekStart == peekLast) { | |
1114 continue; | |
1115 } | |
1116 double t = span.fT; | 1371 double t = span.fT; |
1117 int tStart = index; | 1372 int tStart = index; |
1118 while (tStart > 0 && t == fTs[tStart - 1].fT) { | 1373 while (--tStart >= 0 && (t == fTs[tStart].fT || fTs[tStart].fTiny)) |
1119 --tStart; | 1374 ; |
1120 } | |
1121 int tLast = index; | 1375 int tLast = index; |
1122 int last = count - 1; | 1376 while (fTs[tLast].fTiny) { |
1123 while (tLast < last && t == fTs[tLast + 1].fT) { | |
1124 ++tLast; | 1377 ++tLast; |
1125 } | 1378 } |
| 1379 while (++tLast < count && t == fTs[tLast].fT) |
| 1380 ; |
1126 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { | 1381 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { |
1127 if (peekIndex == span.fOtherIndex) { | 1382 if (peekIndex == span.fOtherIndex) { // skip the other span pointed
to by this span |
1128 continue; | 1383 continue; |
1129 } | 1384 } |
1130 const SkOpSpan& peekSpan = other->fTs[peekIndex]; | 1385 const SkOpSpan& peekSpan = other->fTs[peekIndex]; |
1131 SkOpSegment* match = peekSpan.fOther; | 1386 SkOpSegment* match = peekSpan.fOther; |
1132 const double matchT = peekSpan.fOtherT; | 1387 const double matchT = peekSpan.fOtherT; |
1133 for (int tIndex = tStart; tIndex <= tLast; ++tIndex) { | 1388 // see if any of the spans match the other spans |
| 1389 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) { |
1134 const SkOpSpan& tSpan = fTs[tIndex]; | 1390 const SkOpSpan& tSpan = fTs[tIndex]; |
1135 if (tSpan.fOther == match && tSpan.fOtherT == matchT) { | 1391 if (tSpan.fOther == match) { |
1136 goto nextPeeker; | 1392 if (tSpan.fOtherT == matchT) { |
1137 } | 1393 goto nextPeeker; |
1138 } | 1394 } |
| 1395 double midT = (tSpan.fOtherT + matchT) / 2; |
| 1396 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) { |
| 1397 goto nextPeeker; |
| 1398 } |
| 1399 } |
| 1400 } |
| 1401 if (missingSpans.count() > 0) { |
| 1402 const MissingSpan& lastMissing = missingSpans.back(); |
| 1403 if (lastMissing.fCommand == MissingSpan::kAddMissing |
| 1404 && lastMissing.fT == t |
| 1405 && lastMissing.fOther == match |
| 1406 && lastMissing.fOtherT == matchT) { |
| 1407 SkASSERT(lastMissing.fPt == peekSpan.fPt); |
| 1408 continue; |
| 1409 } |
| 1410 } |
| 1411 #if DEBUG_CHECK_ENDS |
| 1412 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%
1.9g)\n", |
| 1413 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, p
eekSpan.fPt.fY); |
| 1414 #endif |
1139 // this segment is missing a entry that the other contains | 1415 // this segment is missing a entry that the other contains |
1140 // remember so we can add the missing one and recompute the indices | 1416 // remember so we can add the missing one and recompute the indices |
1141 SkOpSpan* missing = missingSpans.append(); | 1417 MissingSpan& missing = missingSpans.push_back(); |
1142 missing->fT = t; | 1418 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); |
1143 missing->fOther = match; | 1419 missing.fCommand = MissingSpan::kAddMissing; |
1144 missing->fOtherT = matchT; | 1420 missing.fT = t; |
1145 missing->fPt = peekSpan.fPt; | 1421 missing.fOther = match; |
| 1422 missing.fOtherT = matchT; |
| 1423 missing.fPt = peekSpan.fPt; |
1146 } | 1424 } |
1147 nextPeeker: | 1425 nextPeeker: |
1148 ; | 1426 ; |
1149 } | 1427 } |
| 1428 if (missingSpans.count() == 0) { |
| 1429 return; |
| 1430 } |
| 1431 // if one end is near the other point, look for a coincident span |
| 1432 for (int index = 0; index < count; ++index) { |
| 1433 const SkOpSpan& span = fTs[index]; |
| 1434 if (span.fT > 0) { |
| 1435 break; |
| 1436 } |
| 1437 const SkOpSpan& otherSpan = span.fOther->span(span.fOtherIndex); |
| 1438 if (span.fNear) { |
| 1439 SkASSERT(otherSpan.fPt == fPts[0]); |
| 1440 adjustNear(0, span.fPt, &missingSpans); |
| 1441 continue; |
| 1442 } |
| 1443 if (otherSpan.fNear) { |
| 1444 SkASSERT(span.fPt == fPts[0]); |
| 1445 adjustNear(0, otherSpan.fPt, &missingSpans); |
| 1446 } |
| 1447 } |
| 1448 for (int index = count; --index >= 0; ) { |
| 1449 const SkOpSpan& span = fTs[index]; |
| 1450 if (span.fT < 1) { |
| 1451 break; |
| 1452 } |
| 1453 const SkOpSegment* other = span.fOther; |
| 1454 if (span.fNear) { |
| 1455 SkASSERT(other->ptAtT(span.fOtherT) == ptAtT(1)); |
| 1456 const SkPoint& otherPt = other->xyAtT(span.fOtherIndex); |
| 1457 SkASSERT(otherPt != ptAtT(1)); |
| 1458 adjustNear(1, otherPt, &missingSpans); |
| 1459 continue; |
| 1460 } |
| 1461 const SkOpSpan& otherSpan = other->span(span.fOtherIndex); |
| 1462 if (otherSpan.fNear) { |
| 1463 SkASSERT(otherSpan.fPt == ptAtT(1)); |
| 1464 SkPoint otherPt = other->ptAtT(span.fOtherT); |
| 1465 SkASSERT(otherPt != ptAtT(1)); |
| 1466 adjustNear(1, otherPt, &missingSpans); |
| 1467 } |
| 1468 } |
| 1469 debugValidate(); |
1150 int missingCount = missingSpans.count(); | 1470 int missingCount = missingSpans.count(); |
1151 if (missingCount == 0) { | 1471 for (int index = 0; index < missingCount; ++index) { |
1152 return; | 1472 MissingSpan& missing = missingSpans[index]; |
1153 } | 1473 switch (missing.fCommand) { |
1154 debugValidate(); | 1474 case MissingSpan::kNoAction: |
1155 for (int index = 0; index < missingCount; ++index) { | 1475 break; |
1156 const SkOpSpan& missing = missingSpans[index]; | 1476 case MissingSpan::kAddMissing: |
1157 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt
); | 1477 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, mis
sing.fPt); |
| 1478 break; |
| 1479 case MissingSpan::kRemoveNear: { |
| 1480 SkOpSegment* segment = missing.fSegment; |
| 1481 int count = segment->count(); |
| 1482 for (int inner = 0; inner < count; ++inner) { |
| 1483 const SkOpSpan& span = segment->span(inner); |
| 1484 if (span.fT != missing.fT && span.fOther != missing.fOther)
{ |
| 1485 continue; |
| 1486 } |
| 1487 SkASSERT(span.fNear); |
| 1488 SkOpSegment* other = span.fOther; |
| 1489 int otherCount = other->count(); |
| 1490 for (int otherIndex = 0; otherIndex < otherCount; ++otherInd
ex) { |
| 1491 const SkOpSpan& otherSpan = other->span(otherIndex); |
| 1492 if (otherSpan.fT == span.fOtherT && otherSpan.fOther ==
segment |
| 1493 && otherSpan.fOtherT == span.fT) { |
| 1494 if (otherSpan.fDone) { |
| 1495 other->fDoneSpans--; |
| 1496 } |
| 1497 other->fTs.remove(otherIndex); |
| 1498 // FIXME: remove may leave a tiny dangling -- recomp
ute tiny w/index |
| 1499 break; |
| 1500 } |
| 1501 } |
| 1502 if (span.fDone) { |
| 1503 segment->fDoneSpans--; |
| 1504 } |
| 1505 segment->fTs.remove(inner); |
| 1506 // FIXME: remove may leave a tiny dangling -- recompute tiny
w/index |
| 1507 break; |
| 1508 } |
| 1509 break; |
| 1510 } |
| 1511 case MissingSpan::kZeroSpan: { |
| 1512 SkOpSegment* segment = missing.fSegment; |
| 1513 int count = segment->count(); |
| 1514 for (int inner = 0; inner < count; ++inner) { |
| 1515 SkOpSpan& span = segment->fTs[inner]; |
| 1516 if (span.fT < missing.fT) { |
| 1517 continue; |
| 1518 } |
| 1519 if (span.fT >= missing.fEndT) { |
| 1520 break; |
| 1521 } |
| 1522 span.fWindValue = span.fOppValue = 0; |
| 1523 if (!span.fDone) { |
| 1524 span.fDone = true; |
| 1525 ++segment->fDoneSpans; |
| 1526 } |
| 1527 } |
| 1528 break; |
| 1529 } |
| 1530 } |
1158 } | 1531 } |
1159 fixOtherTIndex(); | 1532 fixOtherTIndex(); |
1160 for (int index = 0; index < missingCount; ++index) { | 1533 // OPTIMIZATION: this may fix indices more than once. Build an array of uniq
ue segments to |
1161 const SkOpSpan& missing = missingSpans[index]; | 1534 // avoid this |
1162 missing.fOther->fixOtherTIndex(); | 1535 for (int index = 0; index < missingCount; ++index) { |
| 1536 const MissingSpan& missing = missingSpans[index]; |
| 1537 switch (missing.fCommand) { |
| 1538 case MissingSpan::kNoAction: |
| 1539 break; |
| 1540 case MissingSpan::kAddMissing: |
| 1541 missing.fOther->fixOtherTIndex(); |
| 1542 break; |
| 1543 case MissingSpan::kRemoveNear: |
| 1544 missing.fSegment->fixOtherTIndex(); |
| 1545 missing.fOther->fixOtherTIndex(); |
| 1546 break; |
| 1547 case MissingSpan::kZeroSpan: |
| 1548 break; |
| 1549 } |
1163 } | 1550 } |
1164 debugValidate(); | 1551 debugValidate(); |
1165 } | 1552 } |
1166 | 1553 |
1167 bool SkOpSegment::equalPoints(int greaterTIndex, int lesserTIndex) { | 1554 bool SkOpSegment::checkSmall(int index) const { |
1168 SkASSERT(greaterTIndex >= lesserTIndex); | 1555 if (fTs[index].fSmall) { |
1169 double greaterT = fTs[greaterTIndex].fT; | |
1170 double lesserT = fTs[lesserTIndex].fT; | |
1171 if (greaterT == lesserT) { | |
1172 return true; | 1556 return true; |
1173 } | 1557 } |
1174 if (!approximately_negative(greaterT - lesserT)) { | 1558 double tBase = fTs[index].fT; |
1175 return false; | 1559 while (index > 0 && precisely_negative(tBase - fTs[--index].fT)) |
1176 } | 1560 ; |
1177 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex); | 1561 return fTs[index].fSmall; |
| 1562 } |
| 1563 |
| 1564 // if pair of spans on either side of tiny have the same end point and mid point
, mark |
| 1565 // them as parallel |
| 1566 // OPTIMIZATION : mark the segment to note that some span is tiny |
| 1567 void SkOpSegment::checkTiny() { |
| 1568 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; |
| 1569 SkOpSpan* thisSpan = fTs.begin() - 1; |
| 1570 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny |
| 1571 while (++thisSpan < endSpan) { |
| 1572 if (!thisSpan->fTiny) { |
| 1573 continue; |
| 1574 } |
| 1575 SkOpSpan* nextSpan = thisSpan + 1; |
| 1576 double thisT = thisSpan->fT; |
| 1577 double nextT = nextSpan->fT; |
| 1578 if (thisT == nextT) { |
| 1579 continue; |
| 1580 } |
| 1581 SkASSERT(thisT < nextT); |
| 1582 SkASSERT(thisSpan->fPt == nextSpan->fPt); |
| 1583 SkOpSegment* thisOther = thisSpan->fOther; |
| 1584 SkOpSegment* nextOther = nextSpan->fOther; |
| 1585 int oIndex = thisSpan->fOtherIndex; |
| 1586 for (int oStep = -1; oStep <= 1; oStep += 2) { |
| 1587 int oEnd = thisOther->nextExactSpan(oIndex, oStep); |
| 1588 if (oEnd < 0) { |
| 1589 continue; |
| 1590 } |
| 1591 const SkOpSpan& oSpan = thisOther->span(oEnd); |
| 1592 int nIndex = nextSpan->fOtherIndex; |
| 1593 for (int nStep = -1; nStep <= 1; nStep += 2) { |
| 1594 int nEnd = nextOther->nextExactSpan(nIndex, nStep); |
| 1595 if (nEnd < 0) { |
| 1596 continue; |
| 1597 } |
| 1598 const SkOpSpan& nSpan = nextOther->span(nEnd); |
| 1599 if (oSpan.fPt != nSpan.fPt) { |
| 1600 continue; |
| 1601 } |
| 1602 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2; |
| 1603 const SkPoint& oPt = thisOther->ptAtT(oMidT); |
| 1604 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2; |
| 1605 const SkPoint& nPt = nextOther->ptAtT(nMidT); |
| 1606 if (!AlmostEqualUlps(oPt, nPt)) { |
| 1607 continue; |
| 1608 } |
| 1609 #if DEBUG_CHECK_TINY |
| 1610 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fI
D, |
| 1611 thisOther->fID, nextOther->fID); |
| 1612 #endif |
| 1613 // this segment is missing a entry that the other contains |
| 1614 // remember so we can add the missing one and recompute the indi
ces |
| 1615 MissingSpan& missing = missingSpans.push_back(); |
| 1616 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); |
| 1617 missing.fCommand = MissingSpan::kAddMissing; |
| 1618 missing.fSegment = thisOther; |
| 1619 missing.fT = thisSpan->fOtherT; |
| 1620 missing.fOther = nextOther; |
| 1621 missing.fOtherT = nextSpan->fOtherT; |
| 1622 missing.fPt = thisSpan->fPt; |
| 1623 } |
| 1624 } |
| 1625 } |
| 1626 int missingCount = missingSpans.count(); |
| 1627 if (!missingCount) { |
| 1628 return; |
| 1629 } |
| 1630 for (int index = 0; index < missingCount; ++index) { |
| 1631 MissingSpan& missing = missingSpans[index]; |
| 1632 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT,
false, missing.fPt); |
| 1633 } |
| 1634 for (int index = 0; index < missingCount; ++index) { |
| 1635 MissingSpan& missing = missingSpans[index]; |
| 1636 missing.fSegment->fixOtherTIndex(); |
| 1637 missing.fOther->fixOtherTIndex(); |
| 1638 } |
1178 } | 1639 } |
1179 | 1640 |
1180 /* | 1641 /* |
1181 The M and S variable name parts stand for the operators. | 1642 The M and S variable name parts stand for the operators. |
1182 Mi stands for Minuend (see wiki subtraction, analogous to difference) | 1643 Mi stands for Minuend (see wiki subtraction, analogous to difference) |
1183 Su stands for Subtrahend | 1644 Su stands for Subtrahend |
1184 The Opp variable name part designates that the value is for the Opposite operat
or. | 1645 The Opp variable name part designates that the value is for the Opposite operat
or. |
1185 Opposite values result from combining coincident spans. | 1646 Opposite values result from combining coincident spans. |
1186 */ | 1647 */ |
1187 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
, int* nextEnd, | 1648 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart
, int* nextEnd, |
(...skipping 19 matching lines...) Expand all Loading... |
1207 if (fTs[min].fDone) { | 1668 if (fTs[min].fDone) { |
1208 return NULL; | 1669 return NULL; |
1209 } | 1670 } |
1210 markDoneBinary(min); | 1671 markDoneBinary(min); |
1211 other = endSpan->fOther; | 1672 other = endSpan->fOther; |
1212 *nextStart = endSpan->fOtherIndex; | 1673 *nextStart = endSpan->fOtherIndex; |
1213 double startT = other->fTs[*nextStart].fT; | 1674 double startT = other->fTs[*nextStart].fT; |
1214 *nextEnd = *nextStart; | 1675 *nextEnd = *nextStart; |
1215 do { | 1676 do { |
1216 *nextEnd += step; | 1677 *nextEnd += step; |
1217 } | 1678 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
1218 while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
1219 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 1679 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
1220 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { | 1680 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { |
1221 *unsortable = true; | 1681 *unsortable = true; |
1222 return NULL; | 1682 return NULL; |
1223 } | 1683 } |
1224 return other; | 1684 return other; |
1225 } | 1685 } |
1226 // more than one viable candidate -- measure angles to find best | 1686 // more than one viable candidate -- measure angles to find best |
1227 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 1687 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
1228 SkASSERT(startIndex - endIndex != 0); | 1688 SkASSERT(startIndex - endIndex != 0); |
1229 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1689 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1230 addTwoAngles(startIndex, end, &angles); | |
1231 buildAngles(end, &angles, true); | |
1232 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 1690 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
1233 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); | 1691 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles
, &sorted); |
| 1692 bool sortable = calcWinding != SK_NaN32; |
1234 int angleCount = angles.count(); | 1693 int angleCount = angles.count(); |
1235 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1694 int firstIndex = findStartingEdge(sorted, startIndex, end); |
1236 SkASSERT(firstIndex >= 0); | 1695 SkASSERT(!sortable || firstIndex >= 0); |
1237 #if DEBUG_SORT | 1696 #if DEBUG_SORT |
1238 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | 1697 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); |
1239 #endif | 1698 #endif |
1240 if (!sortable) { | 1699 if (!sortable) { |
1241 *unsortable = true; | 1700 *unsortable = true; |
1242 return NULL; | 1701 return NULL; |
1243 } | 1702 } |
1244 SkASSERT(sorted[firstIndex]->segment() == this); | 1703 SkASSERT(sorted[firstIndex]->segment() == this); |
1245 #if DEBUG_WINDING | 1704 #if DEBUG_WINDING |
1246 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, | 1705 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, |
(...skipping 23 matching lines...) Expand all Loading... |
1270 nextAngle->end(), op, &sumMiWinding, &sumSuWinding, | 1729 nextAngle->end(), op, &sumMiWinding, &sumSuWinding, |
1271 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); | 1730 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); |
1272 if (activeAngle) { | 1731 if (activeAngle) { |
1273 ++activeCount; | 1732 ++activeCount; |
1274 if (!foundAngle || (foundDone && activeCount & 1)) { | 1733 if (!foundAngle || (foundDone && activeCount & 1)) { |
1275 if (nextSegment->isTiny(nextAngle)) { | 1734 if (nextSegment->isTiny(nextAngle)) { |
1276 *unsortable = true; | 1735 *unsortable = true; |
1277 return NULL; | 1736 return NULL; |
1278 } | 1737 } |
1279 foundAngle = nextAngle; | 1738 foundAngle = nextAngle; |
1280 foundDone = nextSegment->done(nextAngle) && !nextSegment->isTiny
(nextAngle); | 1739 foundDone = nextSegment->done(nextAngle); |
1281 } | 1740 } |
1282 } | 1741 } |
1283 if (nextSegment->done()) { | 1742 if (nextSegment->done()) { |
1284 continue; | 1743 continue; |
1285 } | 1744 } |
1286 if (nextSegment->windSum(nextAngle) != SK_MinS32) { | 1745 if (nextSegment->isTiny(nextAngle)) { |
1287 continue; | 1746 continue; |
1288 } | 1747 } |
1289 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWi
nding, | 1748 if (!activeAngle) { |
1290 oppSumWinding, activeAngle, nextAngle); | 1749 nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->e
nd()); |
| 1750 } |
| 1751 SkOpSpan* last = nextAngle->lastMarked(); |
1291 if (last) { | 1752 if (last) { |
1292 *chase->append() = last; | 1753 *chase->append() = last; |
1293 #if DEBUG_WINDING | 1754 #if DEBUG_WINDING |
1294 SkDebugf("%s chase.append id=%d\n", __FUNCTION__, | 1755 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, |
1295 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); | 1756 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, |
| 1757 last->fSmall); |
1296 #endif | 1758 #endif |
1297 } | 1759 } |
1298 } while (++nextIndex != lastIndex); | 1760 } while (++nextIndex != lastIndex); |
1299 markDoneBinary(SkMin32(startIndex, endIndex)); | 1761 markDoneBinary(SkMin32(startIndex, endIndex)); |
1300 if (!foundAngle) { | 1762 if (!foundAngle) { |
1301 return NULL; | 1763 return NULL; |
1302 } | 1764 } |
1303 *nextStart = foundAngle->start(); | 1765 *nextStart = foundAngle->start(); |
1304 *nextEnd = foundAngle->end(); | 1766 *nextEnd = foundAngle->end(); |
1305 nextSegment = foundAngle->segment(); | 1767 nextSegment = foundAngle->segment(); |
1306 | |
1307 #if DEBUG_WINDING | 1768 #if DEBUG_WINDING |
1308 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 1769 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
1309 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 1770 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
1310 #endif | 1771 #endif |
1311 return nextSegment; | 1772 return nextSegment; |
1312 } | 1773 } |
1313 | 1774 |
1314 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
Start, | 1775 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next
Start, |
1315 int* nextEnd, bool* unsortable) { | 1776 int* nextEnd, bool* unsortable) { |
1316 const int startIndex = *nextStart; | 1777 const int startIndex = *nextStart; |
(...skipping 16 matching lines...) Expand all Loading... |
1333 if (fTs[min].fDone) { | 1794 if (fTs[min].fDone) { |
1334 return NULL; | 1795 return NULL; |
1335 } | 1796 } |
1336 markDoneUnary(min); | 1797 markDoneUnary(min); |
1337 other = endSpan->fOther; | 1798 other = endSpan->fOther; |
1338 *nextStart = endSpan->fOtherIndex; | 1799 *nextStart = endSpan->fOtherIndex; |
1339 double startT = other->fTs[*nextStart].fT; | 1800 double startT = other->fTs[*nextStart].fT; |
1340 *nextEnd = *nextStart; | 1801 *nextEnd = *nextStart; |
1341 do { | 1802 do { |
1342 *nextEnd += step; | 1803 *nextEnd += step; |
| 1804 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
| 1805 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
| 1806 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { |
| 1807 *unsortable = true; |
| 1808 return NULL; |
1343 } | 1809 } |
1344 while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
1345 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | |
1346 return other; | 1810 return other; |
1347 } | 1811 } |
1348 // more than one viable candidate -- measure angles to find best | 1812 // more than one viable candidate -- measure angles to find best |
1349 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 1813 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
1350 SkASSERT(startIndex - endIndex != 0); | 1814 SkASSERT(startIndex - endIndex != 0); |
1351 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1815 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1352 addTwoAngles(startIndex, end, &angles); | |
1353 buildAngles(end, &angles, true); | |
1354 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 1816 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
1355 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); | 1817 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding, &ang
les, &sorted); |
| 1818 bool sortable = calcWinding != SK_NaN32; |
1356 int angleCount = angles.count(); | 1819 int angleCount = angles.count(); |
1357 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1820 int firstIndex = findStartingEdge(sorted, startIndex, end); |
1358 SkASSERT(firstIndex >= 0); | 1821 SkASSERT(!sortable || firstIndex >= 0); |
1359 #if DEBUG_SORT | 1822 #if DEBUG_SORT |
1360 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | 1823 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); |
1361 #endif | 1824 #endif |
1362 if (!sortable) { | 1825 if (!sortable) { |
1363 *unsortable = true; | 1826 *unsortable = true; |
1364 return NULL; | 1827 return NULL; |
1365 } | 1828 } |
1366 SkASSERT(sorted[firstIndex]->segment() == this); | 1829 SkASSERT(sorted[firstIndex]->segment() == this); |
1367 #if DEBUG_WINDING | 1830 #if DEBUG_WINDING |
1368 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, | 1831 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, |
(...skipping 24 matching lines...) Expand all Loading... |
1393 *unsortable = true; | 1856 *unsortable = true; |
1394 return NULL; | 1857 return NULL; |
1395 } | 1858 } |
1396 foundAngle = nextAngle; | 1859 foundAngle = nextAngle; |
1397 foundDone = nextSegment->done(nextAngle); | 1860 foundDone = nextSegment->done(nextAngle); |
1398 } | 1861 } |
1399 } | 1862 } |
1400 if (nextSegment->done()) { | 1863 if (nextSegment->done()) { |
1401 continue; | 1864 continue; |
1402 } | 1865 } |
1403 if (nextSegment->windSum(nextAngle) != SK_MinS32) { | 1866 if (nextSegment->isTiny(nextAngle)) { |
1404 continue; | 1867 continue; |
1405 } | 1868 } |
1406 SkOpSpan* last = nextSegment->markAngle(maxWinding, sumWinding, activeAn
gle, nextAngle); | 1869 if (!activeAngle) { |
| 1870 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->en
d()); |
| 1871 } |
| 1872 SkOpSpan* last = nextAngle->lastMarked(); |
1407 if (last) { | 1873 if (last) { |
1408 *chase->append() = last; | 1874 *chase->append() = last; |
1409 #if DEBUG_WINDING | 1875 #if DEBUG_WINDING |
1410 SkDebugf("%s chase.append id=%d\n", __FUNCTION__, | 1876 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__
, |
1411 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); | 1877 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last
->fWindSum, |
| 1878 last->fSmall); |
1412 #endif | 1879 #endif |
1413 } | 1880 } |
1414 } while (++nextIndex != lastIndex); | 1881 } while (++nextIndex != lastIndex); |
1415 markDoneUnary(SkMin32(startIndex, endIndex)); | 1882 markDoneUnary(SkMin32(startIndex, endIndex)); |
1416 if (!foundAngle) { | 1883 if (!foundAngle) { |
1417 return NULL; | 1884 return NULL; |
1418 } | 1885 } |
1419 *nextStart = foundAngle->start(); | 1886 *nextStart = foundAngle->start(); |
1420 *nextEnd = foundAngle->end(); | 1887 *nextEnd = foundAngle->end(); |
1421 nextSegment = foundAngle->segment(); | 1888 nextSegment = foundAngle->segment(); |
1422 #if DEBUG_WINDING | 1889 #if DEBUG_WINDING |
1423 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", | 1890 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", |
1424 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); | 1891 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEn
d); |
1425 #endif | 1892 #endif |
1426 return nextSegment; | 1893 return nextSegment; |
1427 } | 1894 } |
1428 | 1895 |
1429 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
able) { | 1896 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsort
able) { |
1430 const int startIndex = *nextStart; | 1897 const int startIndex = *nextStart; |
1431 const int endIndex = *nextEnd; | 1898 const int endIndex = *nextEnd; |
1432 SkASSERT(startIndex != endIndex); | 1899 SkASSERT(startIndex != endIndex); |
1433 SkDEBUGCODE(int count = fTs.count()); | 1900 SkDEBUGCODE(int count = fTs.count()); |
1434 SkASSERT(startIndex < endIndex ? startIndex < count - 1 | 1901 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); |
1435 : startIndex > 0); | |
1436 int step = SkSign32(endIndex - startIndex); | 1902 int step = SkSign32(endIndex - startIndex); |
1437 int end = nextExactSpan(startIndex, step); | 1903 int end = nextExactSpan(startIndex, step); |
1438 SkASSERT(end >= 0); | 1904 SkASSERT(end >= 0); |
1439 SkOpSpan* endSpan = &fTs[end]; | 1905 SkOpSpan* endSpan = &fTs[end]; |
1440 SkOpSegment* other; | 1906 SkOpSegment* other; |
1441 if (isSimple(end)) { | 1907 if (isSimple(end)) { |
1442 #if DEBUG_WINDING | 1908 #if DEBUG_WINDING |
1443 SkDebugf("%s simple\n", __FUNCTION__); | 1909 SkDebugf("%s simple\n", __FUNCTION__); |
1444 #endif | 1910 #endif |
1445 int min = SkMin32(startIndex, endIndex); | 1911 int min = SkMin32(startIndex, endIndex); |
1446 if (fTs[min].fDone) { | 1912 if (fTs[min].fDone) { |
1447 return NULL; | 1913 return NULL; |
1448 } | 1914 } |
1449 markDone(min, 1); | 1915 markDone(min, 1); |
1450 other = endSpan->fOther; | 1916 other = endSpan->fOther; |
1451 *nextStart = endSpan->fOtherIndex; | 1917 *nextStart = endSpan->fOtherIndex; |
1452 double startT = other->fTs[*nextStart].fT; | 1918 double startT = other->fTs[*nextStart].fT; |
1453 // FIXME: I don't know why the logic here is difference from the winding
case | 1919 // FIXME: I don't know why the logic here is difference from the winding
case |
1454 SkDEBUGCODE(bool firstLoop = true;) | 1920 SkDEBUGCODE(bool firstLoop = true;) |
1455 if ((approximately_less_than_zero(startT) && step < 0) | 1921 if ((approximately_less_than_zero(startT) && step < 0) |
1456 || (approximately_greater_than_one(startT) && step > 0)) { | 1922 || (approximately_greater_than_one(startT) && step > 0)) { |
1457 step = -step; | 1923 step = -step; |
1458 SkDEBUGCODE(firstLoop = false;) | 1924 SkDEBUGCODE(firstLoop = false;) |
1459 } | 1925 } |
1460 do { | 1926 do { |
1461 *nextEnd = *nextStart; | 1927 *nextEnd = *nextStart; |
1462 do { | 1928 do { |
1463 *nextEnd += step; | 1929 *nextEnd += step; |
1464 } | 1930 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); |
1465 while (precisely_zero(startT - other->fTs[*nextEnd].fT)); | |
1466 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { | 1931 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { |
1467 break; | 1932 break; |
1468 } | 1933 } |
1469 #ifdef SK_DEBUG | |
1470 SkASSERT(firstLoop); | 1934 SkASSERT(firstLoop); |
1471 #endif | |
1472 SkDEBUGCODE(firstLoop = false;) | 1935 SkDEBUGCODE(firstLoop = false;) |
1473 step = -step; | 1936 step = -step; |
1474 } while (true); | 1937 } while (true); |
1475 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); | 1938 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); |
1476 return other; | 1939 return other; |
1477 } | 1940 } |
1478 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 1941 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
1479 SkASSERT(startIndex - endIndex != 0); | 1942 SkASSERT(startIndex - endIndex != 0); |
1480 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1943 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1481 addTwoAngles(startIndex, end, &angles); | |
1482 buildAngles(end, &angles, false); | |
1483 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 1944 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
1484 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMustBeOrdered_Sort
AngleKind); | 1945 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryXor, &angles,
&sorted); |
1485 if (!sortable) { | 1946 bool sortable = calcWinding != SK_NaN32; |
1486 *unsortable = true; | |
1487 #if DEBUG_SORT | |
1488 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex,
end), 0, 0, | |
1489 sortable); | |
1490 #endif | |
1491 return NULL; | |
1492 } | |
1493 int angleCount = angles.count(); | 1947 int angleCount = angles.count(); |
1494 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1948 int firstIndex = findStartingEdge(sorted, startIndex, end); |
1495 SkASSERT(firstIndex >= 0); | 1949 SkASSERT(!sortable || firstIndex >= 0); |
1496 #if DEBUG_SORT | 1950 #if DEBUG_SORT |
1497 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable); | 1951 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0, sortable); |
1498 #endif | 1952 #endif |
| 1953 if (!sortable) { |
| 1954 *unsortable = true; |
| 1955 return NULL; |
| 1956 } |
1499 SkASSERT(sorted[firstIndex]->segment() == this); | 1957 SkASSERT(sorted[firstIndex]->segment() == this); |
| 1958 #if DEBUG_WINDING |
| 1959 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, |
| 1960 sorted[firstIndex]->sign()); |
| 1961 #endif |
1500 int nextIndex = firstIndex + 1; | 1962 int nextIndex = firstIndex + 1; |
1501 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; | 1963 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; |
1502 const SkOpAngle* foundAngle = NULL; | 1964 const SkOpAngle* foundAngle = NULL; |
1503 bool foundDone = false; | 1965 bool foundDone = false; |
1504 SkOpSegment* nextSegment; | 1966 SkOpSegment* nextSegment; |
1505 int activeCount = 0; | 1967 int activeCount = 0; |
1506 do { | 1968 do { |
1507 SkASSERT(nextIndex != firstIndex); | 1969 SkASSERT(nextIndex != firstIndex); |
1508 if (nextIndex == angleCount) { | 1970 if (nextIndex == angleCount) { |
1509 nextIndex = 0; | 1971 nextIndex = 0; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1544 const SkOpAngle* angle = sorted[angleIndex]; | 2006 const SkOpAngle* angle = sorted[angleIndex]; |
1545 if (angle->segment() == this && angle->start() == end && | 2007 if (angle->segment() == this && angle->start() == end && |
1546 angle->end() == start) { | 2008 angle->end() == start) { |
1547 firstIndex = angleIndex; | 2009 firstIndex = angleIndex; |
1548 break; | 2010 break; |
1549 } | 2011 } |
1550 } | 2012 } |
1551 return firstIndex; | 2013 return firstIndex; |
1552 } | 2014 } |
1553 | 2015 |
1554 // FIXME: this is tricky code; needs its own unit test | |
1555 // note that fOtherIndex isn't computed yet, so it can't be used here | |
1556 void SkOpSegment::findTooCloseToCall() { | |
1557 int count = fTs.count(); | |
1558 if (count < 3) { // require t=0, x, 1 at minimum | |
1559 return; | |
1560 } | |
1561 int matchIndex = 0; | |
1562 int moCount; | |
1563 SkOpSpan* match; | |
1564 SkOpSegment* mOther; | |
1565 do { | |
1566 match = &fTs[matchIndex]; | |
1567 mOther = match->fOther; | |
1568 // FIXME: allow quads, cubics to be near coincident? | |
1569 if (mOther->fVerb == SkPath::kLine_Verb) { | |
1570 moCount = mOther->fTs.count(); | |
1571 if (moCount >= 3) { | |
1572 break; | |
1573 } | |
1574 } | |
1575 if (++matchIndex >= count) { | |
1576 return; | |
1577 } | |
1578 } while (true); // require t=0, x, 1 at minimum | |
1579 // OPTIMIZATION: defer matchPt until qualifying toCount is found? | |
1580 const SkPoint* matchPt = &xyAtT(match); | |
1581 // look for a pair of nearby T values that map to the same (x,y) value | |
1582 // if found, see if the pair of other segments share a common point. If | |
1583 // so, the span from here to there is coincident. | |
1584 for (int index = matchIndex + 1; index < count; ++index) { | |
1585 SkOpSpan* test = &fTs[index]; | |
1586 if (test->fDone) { | |
1587 continue; | |
1588 } | |
1589 SkOpSegment* tOther = test->fOther; | |
1590 if (tOther->fVerb != SkPath::kLine_Verb) { | |
1591 continue; // FIXME: allow quads, cubics to be near coincident? | |
1592 } | |
1593 int toCount = tOther->fTs.count(); | |
1594 if (toCount < 3) { // require t=0, x, 1 at minimum | |
1595 continue; | |
1596 } | |
1597 const SkPoint* testPt = &xyAtT(test); | |
1598 if (*matchPt != *testPt) { | |
1599 matchIndex = index; | |
1600 moCount = toCount; | |
1601 match = test; | |
1602 mOther = tOther; | |
1603 matchPt = testPt; | |
1604 continue; | |
1605 } | |
1606 int moStart = -1; | |
1607 int moEnd = -1; | |
1608 double moStartT = 0; | |
1609 double moEndT = 0; | |
1610 for (int moIndex = 0; moIndex < moCount; ++moIndex) { | |
1611 SkOpSpan& moSpan = mOther->fTs[moIndex]; | |
1612 if (moSpan.fDone) { | |
1613 continue; | |
1614 } | |
1615 if (moSpan.fOther == this) { | |
1616 if (moSpan.fOtherT == match->fT) { | |
1617 moStart = moIndex; | |
1618 moStartT = moSpan.fT; | |
1619 } | |
1620 continue; | |
1621 } | |
1622 if (moSpan.fOther == tOther) { | |
1623 if (tOther->windValueAt(moSpan.fOtherT) == 0) { | |
1624 moStart = -1; | |
1625 break; | |
1626 } | |
1627 SkASSERT(moEnd == -1); | |
1628 moEnd = moIndex; | |
1629 moEndT = moSpan.fT; | |
1630 } | |
1631 } | |
1632 if (moStart < 0 || moEnd < 0) { | |
1633 continue; | |
1634 } | |
1635 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test | |
1636 if (approximately_equal(moStartT, moEndT)) { | |
1637 continue; | |
1638 } | |
1639 int toStart = -1; | |
1640 int toEnd = -1; | |
1641 double toStartT = 0; | |
1642 double toEndT = 0; | |
1643 for (int toIndex = 0; toIndex < toCount; ++toIndex) { | |
1644 SkOpSpan& toSpan = tOther->fTs[toIndex]; | |
1645 if (toSpan.fDone) { | |
1646 continue; | |
1647 } | |
1648 if (toSpan.fOther == this) { | |
1649 if (toSpan.fOtherT == test->fT) { | |
1650 toStart = toIndex; | |
1651 toStartT = toSpan.fT; | |
1652 } | |
1653 continue; | |
1654 } | |
1655 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) { | |
1656 if (mOther->windValueAt(toSpan.fOtherT) == 0) { | |
1657 moStart = -1; | |
1658 break; | |
1659 } | |
1660 SkASSERT(toEnd == -1); | |
1661 toEnd = toIndex; | |
1662 toEndT = toSpan.fT; | |
1663 } | |
1664 } | |
1665 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test | |
1666 if (toStart <= 0 || toEnd <= 0) { | |
1667 continue; | |
1668 } | |
1669 if (approximately_equal(toStartT, toEndT)) { | |
1670 continue; | |
1671 } | |
1672 // test to see if the segment between there and here is linear | |
1673 if (!mOther->isLinear(moStart, moEnd) | |
1674 || !tOther->isLinear(toStart, toEnd)) { | |
1675 continue; | |
1676 } | |
1677 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1; | |
1678 if (flipped) { | |
1679 mOther->addTCancel(moStartT, moEndT, tOther, toEndT, toStartT); | |
1680 } else { | |
1681 mOther->addTCoincident(moStartT, moEndT, tOther, toStartT, toEndT); | |
1682 } | |
1683 } | |
1684 } | |
1685 | |
1686 // FIXME: either: | 2016 // FIXME: either: |
1687 // a) mark spans with either end unsortable as done, or | 2017 // a) mark spans with either end unsortable as done, or |
1688 // b) rewrite findTop / findTopSegment / findTopContour to iterate further | 2018 // b) rewrite findTop / findTopSegment / findTopContour to iterate further |
1689 // when encountering an unsortable span | 2019 // when encountering an unsortable span |
1690 | 2020 |
1691 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) | 2021 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) |
1692 // and use more concise logic like the old edge walker code? | 2022 // and use more concise logic like the old edge walker code? |
1693 // FIXME: this needs to deal with coincident edges | 2023 // FIXME: this needs to deal with coincident edges |
1694 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
able, | 2024 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort
able, |
1695 bool onlySortable) { | 2025 bool onlySortable) { |
(...skipping 19 matching lines...) Expand all Loading... |
1715 if (end == -1) { | 2045 if (end == -1) { |
1716 step = -1; | 2046 step = -1; |
1717 end = nextSpan(firstT, step); | 2047 end = nextSpan(firstT, step); |
1718 SkASSERT(end != -1); | 2048 SkASSERT(end != -1); |
1719 } | 2049 } |
1720 // if the topmost T is not on end, or is three-way or more, find left | 2050 // if the topmost T is not on end, or is three-way or more, find left |
1721 // look for left-ness from tLeft to firstT (matching y of other) | 2051 // look for left-ness from tLeft to firstT (matching y of other) |
1722 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 2052 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
1723 SkASSERT(firstT - end != 0); | 2053 SkASSERT(firstT - end != 0); |
1724 addTwoAngles(end, firstT, &angles); | 2054 addTwoAngles(end, firstT, &angles); |
1725 buildAngles(firstT, &angles, true); | 2055 if (!buildAngles(firstT, &angles, true) && onlySortable) { |
| 2056 // *unsortable = true; |
| 2057 // return NULL; |
| 2058 } |
1726 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 2059 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
1727 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_Sor
tAngleKind); | 2060 bool sortable = SortAngles(angles, &sorted, SkOpSegment::kMayBeUnordered_Sor
tAngleKind); |
| 2061 if (onlySortable && !sortable) { |
| 2062 *unsortable = true; |
| 2063 return NULL; |
| 2064 } |
1728 int first = SK_MaxS32; | 2065 int first = SK_MaxS32; |
1729 SkScalar top = SK_ScalarMax; | 2066 SkScalar top = SK_ScalarMax; |
1730 int count = sorted.count(); | 2067 int count = sorted.count(); |
1731 for (int index = 0; index < count; ++index) { | 2068 for (int index = 0; index < count; ++index) { |
1732 const SkOpAngle* angle = sorted[index]; | 2069 const SkOpAngle* angle = sorted[index]; |
| 2070 if (onlySortable && angle->unorderable()) { |
| 2071 continue; |
| 2072 } |
1733 SkOpSegment* next = angle->segment(); | 2073 SkOpSegment* next = angle->segment(); |
1734 SkPathOpsBounds bounds; | 2074 SkPathOpsBounds bounds; |
1735 next->subDivideBounds(angle->end(), angle->start(), &bounds); | 2075 next->subDivideBounds(angle->end(), angle->start(), &bounds); |
1736 if (approximately_greater(top, bounds.fTop)) { | 2076 if (approximately_greater(top, bounds.fTop)) { |
1737 top = bounds.fTop; | 2077 top = bounds.fTop; |
1738 first = index; | 2078 first = index; |
1739 } | 2079 } |
1740 } | 2080 } |
1741 SkASSERT(first < SK_MaxS32); | 2081 SkASSERT(first < SK_MaxS32); |
1742 #if DEBUG_SORT // || DEBUG_SWAP_TOP | 2082 #if DEBUG_SORT // || DEBUG_SWAP_TOP |
1743 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, s
ortable); | 2083 sorted[first]->segment()->debugShowSort(__FUNCTION__, sorted, first, 0, 0, s
ortable); |
1744 #endif | 2084 #endif |
1745 if (onlySortable && !sortable) { | |
1746 *unsortable = true; | |
1747 return NULL; | |
1748 } | |
1749 // skip edges that have already been processed | 2085 // skip edges that have already been processed |
1750 firstT = first - 1; | 2086 firstT = first - 1; |
1751 SkOpSegment* leftSegment; | 2087 SkOpSegment* leftSegment; |
1752 do { | 2088 do { |
1753 if (++firstT == count) { | 2089 if (++firstT == count) { |
1754 firstT = 0; | 2090 firstT = 0; |
1755 } | 2091 } |
1756 const SkOpAngle* angle = sorted[firstT]; | 2092 const SkOpAngle* angle = sorted[firstT]; |
1757 SkASSERT(!onlySortable || !angle->unsortable()); | 2093 SkASSERT(!onlySortable || !angle->unsortable()); |
1758 leftSegment = angle->segment(); | 2094 leftSegment = angle->segment(); |
(...skipping 23 matching lines...) Expand all Loading... |
1782 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); | 2118 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); |
1783 return leftSegment; | 2119 return leftSegment; |
1784 } | 2120 } |
1785 | 2121 |
1786 // FIXME: not crazy about this | 2122 // FIXME: not crazy about this |
1787 // when the intersections are performed, the other index is into an | 2123 // when the intersections are performed, the other index is into an |
1788 // incomplete array. As the array grows, the indices become incorrect | 2124 // incomplete array. As the array grows, the indices become incorrect |
1789 // while the following fixes the indices up again, it isn't smart about | 2125 // while the following fixes the indices up again, it isn't smart about |
1790 // skipping segments whose indices are already correct | 2126 // skipping segments whose indices are already correct |
1791 // assuming we leave the code that wrote the index in the first place | 2127 // assuming we leave the code that wrote the index in the first place |
| 2128 // FIXME: if called after remove, this needs to correct tiny |
1792 void SkOpSegment::fixOtherTIndex() { | 2129 void SkOpSegment::fixOtherTIndex() { |
1793 int iCount = fTs.count(); | 2130 int iCount = fTs.count(); |
1794 for (int i = 0; i < iCount; ++i) { | 2131 for (int i = 0; i < iCount; ++i) { |
1795 SkOpSpan& iSpan = fTs[i]; | 2132 SkOpSpan& iSpan = fTs[i]; |
1796 double oT = iSpan.fOtherT; | 2133 double oT = iSpan.fOtherT; |
1797 SkOpSegment* other = iSpan.fOther; | 2134 SkOpSegment* other = iSpan.fOther; |
1798 int oCount = other->fTs.count(); | 2135 int oCount = other->fTs.count(); |
1799 SkDEBUGCODE(iSpan.fOtherIndex = -1); | 2136 SkDEBUGCODE(iSpan.fOtherIndex = -1); |
1800 for (int o = 0; o < oCount; ++o) { | 2137 for (int o = 0; o < oCount; ++o) { |
1801 SkOpSpan& oSpan = other->fTs[o]; | 2138 SkOpSpan& oSpan = other->fTs[o]; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1862 oppWind = dx < 0 ? oppWindVal : -oppWindVal; | 2199 oppWind = dx < 0 ? oppWindVal : -oppWindVal; |
1863 } else if (hitOppDx * dx >= 0) { | 2200 } else if (hitOppDx * dx >= 0) { |
1864 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); | 2201 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); |
1865 if (abs(oppWind) < abs(oppSideWind)) { | 2202 if (abs(oppWind) < abs(oppSideWind)) { |
1866 oppWind = oppSideWind; | 2203 oppWind = oppSideWind; |
1867 } | 2204 } |
1868 } | 2205 } |
1869 (void) markAndChaseWinding(start, end, winding, oppWind); | 2206 (void) markAndChaseWinding(start, end, winding, oppWind); |
1870 } | 2207 } |
1871 | 2208 |
1872 bool SkOpSegment::isLinear(int start, int end) const { | |
1873 if (fVerb == SkPath::kLine_Verb) { | |
1874 return true; | |
1875 } | |
1876 if (fVerb == SkPath::kQuad_Verb) { | |
1877 SkDQuad qPart = SkDQuad::SubDivide(fPts, fTs[start].fT, fTs[end].fT); | |
1878 return qPart.isLinear(0, 2); | |
1879 } else { | |
1880 SkASSERT(fVerb == SkPath::kCubic_Verb); | |
1881 SkDCubic cPart = SkDCubic::SubDivide(fPts, fTs[start].fT, fTs[end].fT); | |
1882 return cPart.isLinear(0, 3); | |
1883 } | |
1884 } | |
1885 | |
1886 // OPTIMIZE: successive calls could start were the last leaves off | 2209 // OPTIMIZE: successive calls could start were the last leaves off |
1887 // or calls could specialize to walk forwards or backwards | 2210 // or calls could specialize to walk forwards or backwards |
1888 bool SkOpSegment::isMissing(double startT) const { | 2211 bool SkOpSegment::isMissing(double startT) const { |
1889 size_t tCount = fTs.count(); | 2212 size_t tCount = fTs.count(); |
1890 for (size_t index = 0; index < tCount; ++index) { | 2213 for (size_t index = 0; index < tCount; ++index) { |
1891 if (approximately_zero(startT - fTs[index].fT)) { | 2214 if (approximately_zero(startT - fTs[index].fT)) { |
1892 return false; | 2215 return false; |
1893 } | 2216 } |
1894 } | 2217 } |
1895 return true; | 2218 return true; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2020 SkASSERT(angle->segment() == this); | 2343 SkASSERT(angle->segment() == this); |
2021 if (UseInnerWinding(maxWinding, sumWinding)) { | 2344 if (UseInnerWinding(maxWinding, sumWinding)) { |
2022 maxWinding = sumWinding; | 2345 maxWinding = sumWinding; |
2023 } | 2346 } |
2024 SkOpSpan* last; | 2347 SkOpSpan* last; |
2025 if (activeAngle) { | 2348 if (activeAngle) { |
2026 last = markAndChaseWinding(angle, maxWinding); | 2349 last = markAndChaseWinding(angle, maxWinding); |
2027 } else { | 2350 } else { |
2028 last = markAndChaseDoneUnary(angle, maxWinding); | 2351 last = markAndChaseDoneUnary(angle, maxWinding); |
2029 } | 2352 } |
| 2353 #if DEBUG_WINDING |
| 2354 if (last) { |
| 2355 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__, |
| 2356 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fW
indSum, |
| 2357 last->fSmall); |
| 2358 } |
| 2359 #endif |
2030 return last; | 2360 return last; |
2031 } | 2361 } |
2032 | 2362 |
2033 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi
ng, | 2363 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi
ng, |
2034 int oppSumWinding, bool activeAngle, const SkOp
Angle* angle) { | 2364 int oppSumWinding, bool activeAngle, const SkOp
Angle* angle) { |
2035 SkASSERT(angle->segment() == this); | 2365 SkASSERT(angle->segment() == this); |
2036 if (UseInnerWinding(maxWinding, sumWinding)) { | 2366 if (UseInnerWinding(maxWinding, sumWinding)) { |
2037 maxWinding = sumWinding; | 2367 maxWinding = sumWinding; |
2038 } | 2368 } |
2039 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { | 2369 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { |
2040 oppMaxWinding = oppSumWinding; | 2370 oppMaxWinding = oppSumWinding; |
2041 } | 2371 } |
2042 SkOpSpan* last; | 2372 SkOpSpan* last; |
2043 if (activeAngle) { | 2373 if (activeAngle) { |
2044 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); | 2374 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); |
2045 } else { | 2375 } else { |
2046 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding); | 2376 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding); |
2047 } | 2377 } |
| 2378 #if DEBUG_WINDING |
| 2379 if (last) { |
| 2380 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__, |
| 2381 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fW
indSum, |
| 2382 last->fSmall); |
| 2383 } |
| 2384 #endif |
2048 return last; | 2385 return last; |
2049 } | 2386 } |
2050 | 2387 |
2051 // FIXME: this should also mark spans with equal (x,y) | 2388 // FIXME: this should also mark spans with equal (x,y) |
2052 // This may be called when the segment is already marked done. While this | 2389 // This may be called when the segment is already marked done. While this |
2053 // wastes time, it shouldn't do any more than spin through the T spans. | 2390 // wastes time, it shouldn't do any more than spin through the T spans. |
2054 // OPTIMIZATION: abort on first done found (assuming that this code is | 2391 // OPTIMIZATION: abort on first done found (assuming that this code is |
2055 // always called to mark segments done). | 2392 // always called to mark segments done). |
2056 void SkOpSegment::markDone(int index, int winding) { | 2393 void SkOpSegment::markDone(int index, int winding) { |
2057 // SkASSERT(!done()); | 2394 // SkASSERT(!done()); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2139 | 2476 |
2140 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng) { | 2477 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng) { |
2141 SkOpSpan& span = fTs[tIndex]; | 2478 SkOpSpan& span = fTs[tIndex]; |
2142 if (span.fDone) { | 2479 if (span.fDone) { |
2143 return NULL; | 2480 return NULL; |
2144 } | 2481 } |
2145 #if DEBUG_MARK_DONE | 2482 #if DEBUG_MARK_DONE |
2146 debugShowNewWinding(funName, span, winding); | 2483 debugShowNewWinding(funName, span, winding); |
2147 #endif | 2484 #endif |
2148 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 2485 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2149 #ifdef SK_DEBUG | 2486 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2150 SkASSERT(abs(winding) <= gDebugMaxWindSum); | |
2151 #endif | |
2152 span.fWindSum = winding; | 2487 span.fWindSum = winding; |
2153 return &span; | 2488 return &span; |
2154 } | 2489 } |
2155 | 2490 |
2156 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, | 2491 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, |
2157 int oppWinding) { | 2492 int oppWinding) { |
2158 SkOpSpan& span = fTs[tIndex]; | 2493 SkOpSpan& span = fTs[tIndex]; |
2159 if (span.fDone) { | 2494 if (span.fDone) { |
2160 return NULL; | 2495 return NULL; |
2161 } | 2496 } |
2162 #if DEBUG_MARK_DONE | 2497 #if DEBUG_MARK_DONE |
2163 debugShowNewWinding(funName, span, winding, oppWinding); | 2498 debugShowNewWinding(funName, span, winding, oppWinding); |
2164 #endif | 2499 #endif |
2165 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 2500 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2166 #ifdef SK_DEBUG | 2501 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2167 SkASSERT(abs(winding) <= gDebugMaxWindSum); | |
2168 #endif | |
2169 span.fWindSum = winding; | 2502 span.fWindSum = winding; |
2170 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); | 2503 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); |
2171 #ifdef SK_DEBUG | 2504 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); |
2172 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum); | |
2173 #endif | |
2174 span.fOppSum = oppWinding; | 2505 span.fOppSum = oppWinding; |
2175 return &span; | 2506 return &span; |
2176 } | 2507 } |
2177 | 2508 |
2178 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 2509 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
2179 bool SkOpSegment::clockwise(int tStart, int tEnd) const { | 2510 bool SkOpSegment::clockwise(int tStart, int tEnd) const { |
2180 SkASSERT(fVerb != SkPath::kLine_Verb); | 2511 SkASSERT(fVerb != SkPath::kLine_Verb); |
2181 SkPoint edge[4]; | 2512 SkPoint edge[4]; |
2182 subDivide(tStart, tEnd, edge); | 2513 subDivide(tStart, tEnd, edge); |
2183 int points = SkPathOpsVerbToPoints(fVerb); | 2514 int points = SkPathOpsVerbToPoints(fVerb); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2324 SkOpSpan& newSpan = fTs[tIndex]; | 2655 SkOpSpan& newSpan = fTs[tIndex]; |
2325 newSpan.fWindValue = nextDoorWind; | 2656 newSpan.fWindValue = nextDoorWind; |
2326 newSpan.fOppValue = nextOppWind; | 2657 newSpan.fOppValue = nextOppWind; |
2327 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) { | 2658 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) { |
2328 newSpan.fDone = true; | 2659 newSpan.fDone = true; |
2329 ++fDoneSpans; | 2660 ++fDoneSpans; |
2330 } | 2661 } |
2331 } | 2662 } |
2332 } | 2663 } |
2333 | 2664 |
| 2665 double SkOpSegment::missingNear(double t, const SkOpSegment* other, const SkPoin
t& startPt, |
| 2666 const SkPoint& endPt) const { |
| 2667 int count = this->count(); |
| 2668 for (int index = 0; index < count; ++index) { |
| 2669 const SkOpSpan& span = this->span(index); |
| 2670 if (span.fOther == other && span.fPt == startPt) { |
| 2671 double midT = (t + span.fT) / 2; |
| 2672 if (betweenPoints(midT, startPt, endPt)) { |
| 2673 return span.fT; |
| 2674 } |
| 2675 } |
| 2676 } |
| 2677 return -1; |
| 2678 } |
| 2679 |
2334 // return span if when chasing, two or more radiating spans are not done | 2680 // return span if when chasing, two or more radiating spans are not done |
2335 // OPTIMIZATION: ? multiple spans is detected when there is only one valid | 2681 // OPTIMIZATION: ? multiple spans is detected when there is only one valid |
2336 // candidate and the remaining spans have windValue == 0 (canceled by | 2682 // candidate and the remaining spans have windValue == 0 (canceled by |
2337 // coincidence). The coincident edges could either be removed altogether, | 2683 // coincidence). The coincident edges could either be removed altogether, |
2338 // or this code could be more complicated in detecting this case. Worth it? | 2684 // or this code could be more complicated in detecting this case. Worth it? |
2339 bool SkOpSegment::multipleSpans(int end) const { | 2685 bool SkOpSegment::multipleSpans(int end) const { |
2340 return end > 0 && end < fTs.count() - 1; | 2686 return end > 0 && end < fTs.count() - 1; |
2341 } | 2687 } |
2342 | 2688 |
2343 bool SkOpSegment::nextCandidate(int* start, int* end) const { | 2689 bool SkOpSegment::nextCandidate(int* start, int* end) const { |
2344 while (fTs[*end].fDone) { | 2690 while (fTs[*end].fDone) { |
2345 if (fTs[*end].fT == 1) { | 2691 if (fTs[*end].fT == 1) { |
2346 return false; | 2692 return false; |
2347 } | 2693 } |
2348 ++(*end); | 2694 ++(*end); |
2349 } | 2695 } |
2350 *start = *end; | 2696 *start = *end; |
2351 *end = nextExactSpan(*start, 1); | 2697 *end = nextExactSpan(*start, 1); |
2352 return true; | 2698 return true; |
2353 } | 2699 } |
2354 | 2700 |
2355 SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSp
an** last) { | 2701 SkOpSegment* SkOpSegment::nextChase(int* index, const int step, int* min, SkOpSp
an** last) { |
2356 int end = nextExactSpan(*index, step); | 2702 int end = nextExactSpan(*index, step); |
2357 SkASSERT(end >= 0); | 2703 SkASSERT(end >= 0); |
| 2704 if (fTs[end].fSmall) { |
| 2705 *last = NULL; |
| 2706 return NULL; |
| 2707 } |
2358 if (multipleSpans(end)) { | 2708 if (multipleSpans(end)) { |
2359 *last = &fTs[end]; | 2709 *last = &fTs[end]; |
2360 return NULL; | 2710 return NULL; |
2361 } | 2711 } |
2362 const SkOpSpan& endSpan = fTs[end]; | 2712 const SkOpSpan& endSpan = fTs[end]; |
2363 SkOpSegment* other = endSpan.fOther; | 2713 SkOpSegment* other = endSpan.fOther; |
2364 *index = endSpan.fOtherIndex; | 2714 *index = endSpan.fOtherIndex; |
2365 SkASSERT(*index >= 0); | 2715 SkASSERT(*index >= 0); |
2366 int otherEnd = other->nextExactSpan(*index, step); | 2716 int otherEnd = other->nextExactSpan(*index, step); |
2367 SkASSERT(otherEnd >= 0); | 2717 SkASSERT(otherEnd >= 0); |
2368 *min = SkMin32(*index, otherEnd); | 2718 *min = SkMin32(*index, otherEnd); |
2369 if (other->fTs[*min].fTiny) { | 2719 if (other->fTs[*min].fSmall) { |
2370 *last = NULL; | 2720 *last = NULL; |
2371 return NULL; | 2721 return NULL; |
2372 } | 2722 } |
2373 return other; | 2723 return other; |
2374 } | 2724 } |
2375 | 2725 |
2376 // This has callers for two different situations: one establishes the end | 2726 // This has callers for two different situations: one establishes the end |
2377 // of the current span, and one establishes the beginning of the next span | 2727 // of the current span, and one establishes the beginning of the next span |
2378 // (thus the name). When this is looking for the end of the current span, | 2728 // (thus the name). When this is looking for the end of the current span, |
2379 // coincidence is found when the beginning Ts contain -step and the end | 2729 // coincidence is found when the beginning Ts contain -step and the end |
(...skipping 10 matching lines...) Expand all Loading... |
2390 continue; | 2740 continue; |
2391 } | 2741 } |
2392 return to; | 2742 return to; |
2393 } | 2743 } |
2394 return -1; | 2744 return -1; |
2395 } | 2745 } |
2396 | 2746 |
2397 // FIXME | 2747 // FIXME |
2398 // this returns at any difference in T, vs. a preset minimum. It may be | 2748 // this returns at any difference in T, vs. a preset minimum. It may be |
2399 // that all callers to nextSpan should use this instead. | 2749 // that all callers to nextSpan should use this instead. |
2400 // OPTIMIZATION splitting this into separate loops for up/down steps | |
2401 // would allow using precisely_negative instead of precisely_zero | |
2402 int SkOpSegment::nextExactSpan(int from, int step) const { | 2750 int SkOpSegment::nextExactSpan(int from, int step) const { |
2403 const SkOpSpan& fromSpan = fTs[from]; | |
2404 int count = fTs.count(); | |
2405 int to = from; | 2751 int to = from; |
2406 while (step > 0 ? ++to < count : --to >= 0) { | 2752 if (step < 0) { |
2407 const SkOpSpan& span = fTs[to]; | 2753 const SkOpSpan& fromSpan = fTs[from]; |
2408 if (precisely_zero(span.fT - fromSpan.fT)) { | 2754 while (--to >= 0) { |
2409 continue; | 2755 const SkOpSpan& span = fTs[to]; |
| 2756 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) { |
| 2757 continue; |
| 2758 } |
| 2759 return to; |
2410 } | 2760 } |
2411 return to; | 2761 } else { |
| 2762 while (fTs[from].fTiny) { |
| 2763 from++; |
| 2764 } |
| 2765 const SkOpSpan& fromSpan = fTs[from]; |
| 2766 int count = fTs.count(); |
| 2767 while (++to < count) { |
| 2768 const SkOpSpan& span = fTs[to]; |
| 2769 if (precisely_negative(span.fT - fromSpan.fT)) { |
| 2770 continue; |
| 2771 } |
| 2772 return to; |
| 2773 } |
2412 } | 2774 } |
2413 return -1; | 2775 return -1; |
2414 } | 2776 } |
2415 | 2777 |
2416 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int*
sumSuWinding, | 2778 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int*
sumSuWinding, |
2417 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding
) { | 2779 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding
) { |
2418 int deltaSum = spanSign(index, endIndex); | 2780 int deltaSum = spanSign(index, endIndex); |
2419 int oppDeltaSum = oppSign(index, endIndex); | 2781 int oppDeltaSum = oppSign(index, endIndex); |
2420 if (operand()) { | 2782 if (operand()) { |
2421 *maxWinding = *sumSuWinding; | 2783 *maxWinding = *sumSuWinding; |
2422 *sumWinding = *sumSuWinding -= deltaSum; | 2784 *sumWinding = *sumSuWinding -= deltaSum; |
2423 *oppMaxWinding = *sumMiWinding; | 2785 *oppMaxWinding = *sumMiWinding; |
2424 *oppSumWinding = *sumMiWinding -= oppDeltaSum; | 2786 *oppSumWinding = *sumMiWinding -= oppDeltaSum; |
2425 } else { | 2787 } else { |
2426 *maxWinding = *sumMiWinding; | 2788 *maxWinding = *sumMiWinding; |
2427 *sumWinding = *sumMiWinding -= deltaSum; | 2789 *sumWinding = *sumMiWinding -= deltaSum; |
2428 *oppMaxWinding = *sumSuWinding; | 2790 *oppMaxWinding = *sumSuWinding; |
2429 *oppSumWinding = *sumSuWinding -= oppDeltaSum; | 2791 *oppSumWinding = *sumSuWinding -= oppDeltaSum; |
2430 } | 2792 } |
| 2793 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); |
| 2794 SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum); |
| 2795 } |
| 2796 |
| 2797 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, |
| 2798 int* maxWinding, int* sumWinding) { |
| 2799 int deltaSum = spanSign(index, endIndex); |
| 2800 *maxWinding = *sumMiWinding; |
| 2801 *sumWinding = *sumMiWinding -= deltaSum; |
| 2802 SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); |
2431 } | 2803 } |
2432 | 2804 |
2433 // This marks all spans unsortable so that this info is available for early | 2805 // This marks all spans unsortable so that this info is available for early |
2434 // exclusion in find top and others. This could be optimized to only mark | 2806 // exclusion in find top and others. This could be optimized to only mark |
2435 // adjacent spans that unsortable. However, this makes it difficult to later | 2807 // adjacent spans that unsortable. However, this makes it difficult to later |
2436 // determine starting points for edge detection in find top and the like. | 2808 // determine starting points for edge detection in find top and the like. |
2437 bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles, | 2809 bool SkOpSegment::SortAngles(const SkTArray<SkOpAngle, true>& angles, |
2438 SkTArray<SkOpAngle*, true>* angleList, | 2810 SkTArray<SkOpAngle*, true>* angleList, |
2439 SortAngleKind orderKind) { | 2811 SortAngleKind orderKind) { |
2440 bool sortable = true; | 2812 bool sortable = true; |
2441 int angleCount = angles.count(); | 2813 int angleCount = angles.count(); |
2442 int angleIndex; | 2814 int angleIndex; |
2443 // FIXME: caller needs to use SkTArray constructor with reserve count | |
2444 // angleList->setReserve(angleCount); | |
2445 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2815 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
2446 const SkOpAngle& angle = angles[angleIndex]; | 2816 const SkOpAngle& angle = angles[angleIndex]; |
2447 angleList->push_back(const_cast<SkOpAngle*>(&angle)); | 2817 angleList->push_back(const_cast<SkOpAngle*>(&angle)); |
2448 #if DEBUG_ANGLE | 2818 #if DEBUG_ANGLE |
2449 (*(angleList->end() - 1))->setID(angleIndex); | 2819 (*(angleList->end() - 1))->setID(angleIndex); |
2450 #endif | 2820 #endif |
2451 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAng
leKind | 2821 sortable &= !(angle.unsortable() || (orderKind == kMustBeOrdered_SortAng
leKind |
2452 && angle.unorderable())); | 2822 && angle.unorderable())); |
2453 } | 2823 } |
2454 if (sortable) { | 2824 if (sortable) { |
2455 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); | 2825 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); |
2456 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2826 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
2457 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_
SortAngleKind | 2827 if (angles[angleIndex].unsortable() || (orderKind == kMustBeOrdered_
SortAngleKind |
2458 && angles[angleIndex].unorderable())) { | 2828 && angles[angleIndex].unorderable())) { |
2459 sortable = false; | 2829 sortable = false; |
2460 break; | 2830 break; |
2461 } | 2831 } |
2462 } | 2832 } |
2463 } | 2833 } |
2464 if (!sortable) { | 2834 if (!sortable) { |
2465 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { | 2835 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
2466 const SkOpAngle& angle = angles[angleIndex]; | 2836 const SkOpAngle& angle = angles[angleIndex]; |
2467 angle.segment()->markUnsortable(angle.start(), angle.end()); | 2837 angle.segment()->markUnsortable(angle.start(), angle.end()); |
2468 } | 2838 } |
2469 } | 2839 } |
2470 return sortable; | 2840 return sortable; |
2471 } | 2841 } |
2472 | 2842 |
| 2843 // set segments to unsortable if angle is unsortable, but do not set all angles |
| 2844 // note that for a simple 4 way crossing, two of the edges may be orderable even
though |
| 2845 // two edges are too short to be orderable. |
| 2846 // perhaps some classes of unsortable angles should make all shared angles unsor
table, but |
| 2847 // simple lines that have tiny crossings are always sortable on the large ends |
| 2848 // OPTIMIZATION: check earlier when angles are added to input if any are unsorta
ble |
| 2849 // may make sense then to mark all segments in angle sweep as unsortableStart/un
sortableEnd |
| 2850 // solely for the purpose of short-circuiting future angle building around this
center |
| 2851 bool SkOpSegment::SortAngles2(const SkTArray<SkOpAngle, true>& angles, |
| 2852 SkTArray<SkOpAngle*, true>* angleList) { |
| 2853 int angleCount = angles.count(); |
| 2854 int angleIndex; |
| 2855 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { |
| 2856 const SkOpAngle& angle = angles[angleIndex]; |
| 2857 if (angle.unsortable()) { |
| 2858 return false; |
| 2859 } |
| 2860 angleList->push_back(const_cast<SkOpAngle*>(&angle)); |
| 2861 #if DEBUG_ANGLE |
| 2862 (*(angleList->end() - 1))->setID(angleIndex); |
| 2863 #endif |
| 2864 } |
| 2865 SkTQSort<SkOpAngle>(angleList->begin(), angleList->end() - 1); |
| 2866 // at this point angles are sorted but individually may not be orderable |
| 2867 // this means that only adjcent orderable segments may transfer winding |
| 2868 return true; |
| 2869 } |
| 2870 |
2473 // return true if midpoints were computed | 2871 // return true if midpoints were computed |
2474 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { | 2872 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { |
2475 SkASSERT(start != end); | 2873 SkASSERT(start != end); |
2476 edge[0] = fTs[start].fPt; | 2874 edge[0] = fTs[start].fPt; |
2477 int points = SkPathOpsVerbToPoints(fVerb); | 2875 int points = SkPathOpsVerbToPoints(fVerb); |
2478 edge[points] = fTs[end].fPt; | 2876 edge[points] = fTs[end].fPt; |
2479 if (fVerb == SkPath::kLine_Verb) { | 2877 if (fVerb == SkPath::kLine_Verb) { |
2480 return false; | 2878 return false; |
2481 } | 2879 } |
2482 double startT = fTs[start].fT; | 2880 double startT = fTs[start].fT; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2556 int start = angle->start(); | 2954 int start = angle->start(); |
2557 int end = angle->end(); | 2955 int end = angle->end(); |
2558 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; | 2956 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; |
2559 return mSpan.fTiny; | 2957 return mSpan.fTiny; |
2560 } | 2958 } |
2561 | 2959 |
2562 bool SkOpSegment::isTiny(int index) const { | 2960 bool SkOpSegment::isTiny(int index) const { |
2563 return fTs[index].fTiny; | 2961 return fTs[index].fTiny; |
2564 } | 2962 } |
2565 | 2963 |
2566 void SkOpSegment::TrackOutside(SkTArray<double, true>* outsideTs, double end, do
uble start) { | 2964 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const Sk
Point& endPt, |
2567 int outCount = outsideTs->count(); | 2965 const SkPoint& startPt) { |
2568 if (outCount == 0 || !approximately_negative(end - (*outsideTs)[outCount - 2
])) { | 2966 int outCount = outsidePts->count(); |
2569 outsideTs->push_back(end); | 2967 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) { |
2570 outsideTs->push_back(start); | 2968 outsidePts->push_back(endPt); |
| 2969 outsidePts->push_back(startPt); |
2571 } | 2970 } |
2572 } | 2971 } |
2573 | 2972 |
| 2973 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin
t& startPt) { |
| 2974 int outCount = outsidePts->count(); |
| 2975 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { |
| 2976 outsidePts->push_back(startPt); |
| 2977 } |
| 2978 } |
| 2979 |
2574 void SkOpSegment::undoneSpan(int* start, int* end) { | 2980 void SkOpSegment::undoneSpan(int* start, int* end) { |
2575 size_t tCount = fTs.count(); | 2981 size_t tCount = fTs.count(); |
2576 size_t index; | 2982 size_t index; |
2577 for (index = 0; index < tCount; ++index) { | 2983 for (index = 0; index < tCount; ++index) { |
2578 if (!fTs[index].fDone) { | 2984 if (!fTs[index].fDone) { |
2579 break; | 2985 break; |
2580 } | 2986 } |
2581 } | 2987 } |
2582 SkASSERT(index < tCount - 1); | 2988 SkASSERT(index < tCount - 1); |
2583 *start = index; | 2989 *start = index; |
(...skipping 24 matching lines...) Expand all Loading... |
2608 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { | 3014 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { |
2609 int startIndex = angle->start(); | 3015 int startIndex = angle->start(); |
2610 int endIndex = angle->end(); | 3016 int endIndex = angle->end(); |
2611 return updateOppWinding(startIndex, endIndex); | 3017 return updateOppWinding(startIndex, endIndex); |
2612 } | 3018 } |
2613 | 3019 |
2614 int SkOpSegment::updateWinding(int index, int endIndex) const { | 3020 int SkOpSegment::updateWinding(int index, int endIndex) const { |
2615 int lesser = SkMin32(index, endIndex); | 3021 int lesser = SkMin32(index, endIndex); |
2616 int winding = windSum(lesser); | 3022 int winding = windSum(lesser); |
2617 int spanWinding = spanSign(index, endIndex); | 3023 int spanWinding = spanSign(index, endIndex); |
2618 if (winding && UseInnerWinding(winding - spanWinding, winding) && winding !=
SK_MaxS32) { | 3024 if (winding && UseInnerWinding(winding - spanWinding, winding) |
| 3025 && winding != SK_MaxS32) { |
2619 winding -= spanWinding; | 3026 winding -= spanWinding; |
2620 } | 3027 } |
2621 return winding; | 3028 return winding; |
2622 } | 3029 } |
2623 | 3030 |
2624 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { | 3031 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { |
2625 int startIndex = angle->start(); | 3032 int startIndex = angle->start(); |
2626 int endIndex = angle->end(); | 3033 int endIndex = angle->end(); |
2627 return updateWinding(endIndex, startIndex); | 3034 return updateWinding(endIndex, startIndex); |
2628 } | 3035 } |
2629 | 3036 |
| 3037 int SkOpSegment::updateWindingReverse(int index, int endIndex) const { |
| 3038 int lesser = SkMin32(index, endIndex); |
| 3039 int winding = windSum(lesser); |
| 3040 int spanWinding = spanSign(endIndex, index); |
| 3041 if (winding && UseInnerWindingReverse(winding - spanWinding, winding) |
| 3042 && winding != SK_MaxS32) { |
| 3043 winding -= spanWinding; |
| 3044 } |
| 3045 return winding; |
| 3046 } |
| 3047 |
2630 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { | 3048 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { |
2631 int startIndex = angle->start(); | 3049 int startIndex = angle->start(); |
2632 int endIndex = angle->end(); | 3050 int endIndex = angle->end(); |
2633 return updateWinding(startIndex, endIndex); | 3051 return updateWindingReverse(endIndex, startIndex); |
| 3052 } |
| 3053 |
| 3054 // OPTIMIZATION: does the following also work, and is it any faster? |
| 3055 // return outerWinding * innerWinding > 0 |
| 3056 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) <
0))) |
| 3057 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { |
| 3058 SkASSERT(outerWinding != SK_MaxS32); |
| 3059 SkASSERT(innerWinding != SK_MaxS32); |
| 3060 int absOut = abs(outerWinding); |
| 3061 int absIn = abs(innerWinding); |
| 3062 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; |
| 3063 return result; |
| 3064 } |
| 3065 |
| 3066 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) { |
| 3067 SkASSERT(outerWinding != SK_MaxS32); |
| 3068 SkASSERT(innerWinding != SK_MaxS32); |
| 3069 int absOut = abs(outerWinding); |
| 3070 int absIn = abs(innerWinding); |
| 3071 bool result = absOut == absIn ? true : absOut < absIn; |
| 3072 return result; |
2634 } | 3073 } |
2635 | 3074 |
2636 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx
) const { | 3075 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx
) const { |
2637 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span,
disregard | 3076 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span,
disregard |
2638 return SK_MinS32; | 3077 return SK_MinS32; |
2639 } | 3078 } |
2640 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); | 3079 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); |
2641 SkASSERT(winding != SK_MinS32); | 3080 SkASSERT(winding != SK_MinS32); |
2642 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); | 3081 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); |
2643 #if DEBUG_WINDING_AT_T | 3082 #if DEBUG_WINDING_AT_T |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2854 SkDebugf("%d", span.fWindSum); | 3293 SkDebugf("%d", span.fWindSum); |
2855 } | 3294 } |
2856 SkDebugf(" windValue=%d\n", span.fWindValue); | 3295 SkDebugf(" windValue=%d\n", span.fWindValue); |
2857 } | 3296 } |
2858 #endif | 3297 #endif |
2859 | 3298 |
2860 #if DEBUG_SORT || DEBUG_SWAP_TOP | 3299 #if DEBUG_SORT || DEBUG_SWAP_TOP |
2861 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, | 3300 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, |
2862 int first, const int contourWinding, | 3301 int first, const int contourWinding, |
2863 const int oppContourWinding, bool sortable) cons
t { | 3302 const int oppContourWinding, bool sortable) cons
t { |
2864 if (--gDebugSortCount < 0) { | 3303 if (--SkPathOpsDebug::gSortCount < 0) { |
2865 return; | 3304 return; |
2866 } | 3305 } |
| 3306 if (!sortable) { |
| 3307 if (angles.count() == 0) { |
| 3308 return; |
| 3309 } |
| 3310 if (first < 0) { |
| 3311 first = 0; |
| 3312 } |
| 3313 } |
2867 SkASSERT(angles[first]->segment() == this); | 3314 SkASSERT(angles[first]->segment() == this); |
2868 SkASSERT(!sortable || angles.count() > 1); | 3315 SkASSERT(!sortable || angles.count() > 1); |
2869 int lastSum = contourWinding; | 3316 int lastSum = contourWinding; |
2870 int oppLastSum = oppContourWinding; | 3317 int oppLastSum = oppContourWinding; |
2871 const SkOpAngle* firstAngle = angles[first]; | 3318 const SkOpAngle* firstAngle = angles[first]; |
2872 int windSum = lastSum - spanSign(firstAngle); | 3319 int windSum = lastSum - spanSign(firstAngle); |
2873 int oppoSign = oppSign(firstAngle); | 3320 int oppoSign = oppSign(firstAngle); |
2874 int oppWindSum = oppLastSum - oppoSign; | 3321 int oppWindSum = oppLastSum - oppoSign; |
2875 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str
, "?"); \ | 3322 #define WIND_AS_STRING(x) char x##Str[12]; \ |
2876 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x) | 3323 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \ |
| 3324 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x) |
2877 WIND_AS_STRING(contourWinding); | 3325 WIND_AS_STRING(contourWinding); |
2878 WIND_AS_STRING(oppContourWinding); | 3326 WIND_AS_STRING(oppContourWinding); |
2879 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FU
NCTION__, | 3327 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FU
NCTION__, |
2880 contourWindingStr, oppContourWindingStr, spanSign(angles[first])); | 3328 contourWindingStr, oppContourWindingStr, spanSign(angles[first])); |
2881 int index = first; | 3329 int index = first; |
2882 bool firstTime = true; | 3330 bool firstTime = true; |
2883 do { | 3331 do { |
2884 const SkOpAngle& angle = *angles[index]; | 3332 const SkOpAngle& angle = *angles[index]; |
2885 const SkOpSegment& segment = *angle.segment(); | 3333 const SkOpSegment& segment = *angle.segment(); |
2886 int start = angle.start(); | 3334 int start = angle.start(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2924 break; | 3372 break; |
2925 case SkPath::kCubic_Verb: | 3373 case SkPath::kCubic_Verb: |
2926 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts)); | 3374 SkDebugf(CUBIC_DEBUG_STR, CUBIC_DEBUG_DATA(segment.fPts)); |
2927 break; | 3375 break; |
2928 default: | 3376 default: |
2929 SkASSERT(0); | 3377 SkASSERT(0); |
2930 } | 3378 } |
2931 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT); | 3379 SkDebugf(" tStart=%1.9g tEnd=%1.9g", sSpan.fT, eSpan.fT); |
2932 #endif | 3380 #endif |
2933 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValu
e); | 3381 SkDebugf(" sign=%d windValue=%d windSum=", angle.sign(), mSpan.fWindValu
e); |
2934 winding_printf(mSpan.fWindSum); | 3382 SkPathOpsDebug::WindingPrintf(mSpan.fWindSum); |
2935 int last, wind; | 3383 int last, wind; |
2936 if (opp) { | 3384 if (opp) { |
2937 last = oppLastSum; | 3385 last = oppLastSum; |
2938 wind = oppWindSum; | 3386 wind = oppWindSum; |
2939 } else { | 3387 } else { |
2940 last = lastSum; | 3388 last = lastSum; |
2941 wind = windSum; | 3389 wind = windSum; |
2942 } | 3390 } |
2943 bool useInner = valid_wind(last) && valid_wind(wind) && UseInnerWinding(
last, wind); | 3391 bool useInner = SkPathOpsDebug::ValidWind(last) && SkPathOpsDebug::Valid
Wind(wind) |
| 3392 && UseInnerWinding(last, wind); |
2944 WIND_AS_STRING(last); | 3393 WIND_AS_STRING(last); |
2945 WIND_AS_STRING(wind); | 3394 WIND_AS_STRING(wind); |
2946 WIND_AS_STRING(lastSum); | 3395 WIND_AS_STRING(lastSum); |
2947 WIND_AS_STRING(oppLastSum); | 3396 WIND_AS_STRING(oppLastSum); |
2948 WIND_AS_STRING(windSum); | 3397 WIND_AS_STRING(windSum); |
2949 WIND_AS_STRING(oppWindSum); | 3398 WIND_AS_STRING(oppWindSum); |
2950 #undef WIND_AS_STRING | 3399 #undef WIND_AS_STRING |
2951 if (!oppoSign) { | 3400 if (!oppoSign) { |
2952 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr :
lastStr); | 3401 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr :
lastStr); |
2953 } else { | 3402 } else { |
2954 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : op
pLastSumStr, | 3403 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : op
pLastSumStr, |
2955 opp ? windSumStr : oppWindSumStr); | 3404 opp ? windSumStr : oppWindSumStr); |
2956 } | 3405 } |
2957 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp); | 3406 SkDebugf(" done=%d unord=%d small=%d tiny=%d opp=%d\n", |
2958 #if 0 && DEBUG_ANGLE | 3407 mSpan.fDone, angle.unorderable(), mSpan.fSmall, mSpan.fTiny, opp
); |
2959 angle.debugShow(segment.xyAtT(&sSpan)); | |
2960 #endif | |
2961 ++index; | 3408 ++index; |
2962 if (index == angles.count()) { | 3409 if (index == angles.count()) { |
2963 index = 0; | 3410 index = 0; |
2964 } | 3411 } |
2965 if (firstTime) { | 3412 if (firstTime) { |
2966 firstTime = false; | 3413 firstTime = false; |
2967 } | 3414 } |
2968 } while (index != first); | 3415 } while (index != first); |
2969 } | 3416 } |
2970 | 3417 |
2971 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, | 3418 void SkOpSegment::debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true
>& angles, |
2972 int first, bool sortable) { | 3419 int first, bool sortable) { |
| 3420 if (!sortable) { |
| 3421 if (angles.count() == 0) { |
| 3422 return; |
| 3423 } |
| 3424 if (first < 0) { |
| 3425 first = 0; |
| 3426 } |
| 3427 } |
2973 const SkOpAngle* firstAngle = angles[first]; | 3428 const SkOpAngle* firstAngle = angles[first]; |
2974 const SkOpSegment* segment = firstAngle->segment(); | 3429 const SkOpSegment* segment = firstAngle->segment(); |
2975 int winding = segment->updateWinding(firstAngle); | 3430 int winding = segment->updateWinding(firstAngle); |
2976 int oppWinding = segment->updateOppWinding(firstAngle); | 3431 int oppWinding = segment->updateOppWinding(firstAngle); |
2977 debugShowSort(fun, angles, first, winding, oppWinding, sortable); | 3432 debugShowSort(fun, angles, first, winding, oppWinding, sortable); |
2978 } | 3433 } |
2979 | 3434 |
2980 #endif | 3435 #endif |
2981 | 3436 |
2982 #if DEBUG_SHOW_WINDING | 3437 #if DEBUG_SHOW_WINDING |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3018 const SkOpSegment* other = span.fOther; | 3473 const SkOpSegment* other = span.fOther; |
3019 const SkOpSpan& otherSpan = other->fTs[otherIndex]; | 3474 const SkOpSpan& otherSpan = other->fTs[otherIndex]; |
3020 SkASSERT(otherSpan.fPt == span.fPt); | 3475 SkASSERT(otherSpan.fPt == span.fPt); |
3021 SkASSERT(otherSpan.fOtherT == t); | 3476 SkASSERT(otherSpan.fOtherT == t); |
3022 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]); | 3477 SkASSERT(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex]); |
3023 done += span.fDone; | 3478 done += span.fDone; |
3024 } | 3479 } |
3025 SkASSERT(done == fDoneSpans); | 3480 SkASSERT(done == fDoneSpans); |
3026 #endif | 3481 #endif |
3027 } | 3482 } |
| 3483 |
| 3484 #ifdef SK_DEBUG |
| 3485 void SkOpSegment::dumpPts() const { |
| 3486 int last = SkPathOpsVerbToPoints(fVerb); |
| 3487 SkDebugf("{{"); |
| 3488 int index = 0; |
| 3489 do { |
| 3490 SkDPoint::DumpSkPoint(fPts[index]); |
| 3491 SkDebugf(", "); |
| 3492 } while (++index < last); |
| 3493 SkDPoint::DumpSkPoint(fPts[index]); |
| 3494 SkDebugf("}}\n"); |
| 3495 } |
| 3496 |
| 3497 void SkOpSegment::dumpDPts() const { |
| 3498 int count = SkPathOpsVerbToPoints(fVerb); |
| 3499 SkDebugf("{{"); |
| 3500 int index = 0; |
| 3501 do { |
| 3502 SkDPoint dPt = {fPts[index].fX, fPts[index].fY}; |
| 3503 dPt.dump(); |
| 3504 if (index != count) { |
| 3505 SkDebugf(", "); |
| 3506 } |
| 3507 } while (++index <= count); |
| 3508 SkDebugf("}}\n"); |
| 3509 } |
| 3510 |
| 3511 void SkOpSegment::dumpSpans() const { |
| 3512 int count = this->count(); |
| 3513 for (int index = 0; index < count; ++index) { |
| 3514 const SkOpSpan& span = this->span(index); |
| 3515 SkDebugf("[%d] ", index); |
| 3516 span.dump(); |
| 3517 } |
| 3518 } |
| 3519 #endif |
OLD | NEW |