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

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

Issue 21359002: path ops work in progress (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: remove space Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #include "SkIntersections.h" 7 #include "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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkOpSpan.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698