SkOpSegment.cpp revision 27c8eb8ffd7e221693d840c2b9279d53fe6f03d4
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "SkOpCoincidence.h"
8#include "SkOpContour.h"
9#include "SkOpSegment.h"
10#include "SkPathWriter.h"
11
12/*
13After computing raw intersections, post process all segments to:
14- find small collections of points that can be collapsed to a single point
15- find missing intersections to resolve differences caused by different algorithms
16
17Consider segments containing tiny or small intervals. Consider coincident segments
18because coincidence finds intersections through distance measurement that non-coincident
19intersection tests cannot.
20 */
21
22#define F (false)      // discard the edge
23#define T (true)       // keep the edge
24
25static const bool gUnaryActiveEdge[2][2] = {
26//  from=0  from=1
27//  to=0,1  to=0,1
28    {F, T}, {T, F},
29};
30
31static const bool gActiveEdge[kXOR_SkPathOp + 1][2][2][2][2] = {
32//                 miFrom=0                              miFrom=1
33//         miTo=0             miTo=1             miTo=0             miTo=1
34//     suFrom=0    1      suFrom=0    1      suFrom=0    1      suFrom=0    1
35//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
36    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}},  // mi - su
37    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}},  // mi & su
38    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}},  // mi | su
39    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}},  // mi ^ su
40};
41
42#undef F
43#undef T
44
45SkOpAngle* SkOpSegment::activeAngle(SkOpSpanBase* start, SkOpSpanBase** startPtr,
46        SkOpSpanBase** endPtr, bool* done) {
47    if (SkOpAngle* result = activeAngleInner(start, startPtr, endPtr, done)) {
48        return result;
49    }
50    if (SkOpAngle* result = activeAngleOther(start, startPtr, endPtr, done)) {
51        return result;
52    }
53    return NULL;
54}
55
56SkOpAngle* SkOpSegment::activeAngleInner(SkOpSpanBase* start, SkOpSpanBase** startPtr,
57        SkOpSpanBase** endPtr, bool* done) {
58    SkOpSpan* upSpan = start->upCastable();
59    if (upSpan) {
60        if (upSpan->windValue() || upSpan->oppValue()) {
61            SkOpSpanBase* next = upSpan->next();
62            if (!*endPtr) {
63                *startPtr = start;
64                *endPtr = next;
65            }
66            if (!upSpan->done()) {
67                if (upSpan->windSum() != SK_MinS32) {
68                    return spanToAngle(start, next);
69                }
70                *done = false;
71            }
72        } else {
73            SkASSERT(upSpan->done());
74        }
75    }
76    SkOpSpan* downSpan = start->prev();
77    // edge leading into junction
78    if (downSpan) {
79        if (downSpan->windValue() || downSpan->oppValue()) {
80            if (!*endPtr) {
81                *startPtr = start;
82                *endPtr = downSpan;
83            }
84            if (!downSpan->done()) {
85                if (downSpan->windSum() != SK_MinS32) {
86                    return spanToAngle(start, downSpan);
87                }
88                *done = false;
89            }
90        } else {
91            SkASSERT(downSpan->done());
92        }
93    }
94    return NULL;
95}
96
97SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** startPtr,
98        SkOpSpanBase** endPtr, bool* done) {
99    SkOpPtT* oPtT = start->ptT()->next();
100    SkOpSegment* other = oPtT->segment();
101    SkOpSpanBase* oSpan = oPtT->span();
102    return other->activeAngleInner(oSpan, startPtr, endPtr, done);
103}
104
105bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
106        SkPathOp op) {
107    int sumMiWinding = this->updateWinding(end, start);
108    int sumSuWinding = this->updateOppWinding(end, start);
109#if DEBUG_LIMIT_WIND_SUM
110    SkASSERT(abs(sumMiWinding) <= DEBUG_LIMIT_WIND_SUM);
111    SkASSERT(abs(sumSuWinding) <= DEBUG_LIMIT_WIND_SUM);
112#endif
113    if (this->operand()) {
114        SkTSwap<int>(sumMiWinding, sumSuWinding);
115    }
116    return this->activeOp(xorMiMask, xorSuMask, start, end, op, &sumMiWinding, &sumSuWinding);
117}
118
119bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end,
120        SkPathOp op, int* sumMiWinding, int* sumSuWinding) {
121    int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
122    this->setUpWindings(start, end, sumMiWinding, sumSuWinding,
123            &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
124    bool miFrom;
125    bool miTo;
126    bool suFrom;
127    bool suTo;
128    if (operand()) {
129        miFrom = (oppMaxWinding & xorMiMask) != 0;
130        miTo = (oppSumWinding & xorMiMask) != 0;
131        suFrom = (maxWinding & xorSuMask) != 0;
132        suTo = (sumWinding & xorSuMask) != 0;
133    } else {
134        miFrom = (maxWinding & xorMiMask) != 0;
135        miTo = (sumWinding & xorMiMask) != 0;
136        suFrom = (oppMaxWinding & xorSuMask) != 0;
137        suTo = (oppSumWinding & xorSuMask) != 0;
138    }
139    bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
140#if DEBUG_ACTIVE_OP
141    SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
142            __FUNCTION__, debugID(), start->t(), end->t(),
143            SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
144#endif
145    return result;
146}
147
148bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
149    int sumWinding = updateWinding(end, start);
150    return activeWinding(start, end, &sumWinding);
151}
152
153bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding) {
154    int maxWinding;
155    setUpWinding(start, end, &maxWinding, sumWinding);
156    bool from = maxWinding != 0;
157    bool to = *sumWinding  != 0;
158    bool result = gUnaryActiveEdge[from][to];
159    return result;
160}
161
162void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt,
163        SkOpContourHead* contourList, SkChunkAlloc* allocator) {
164    const SkPoint& newPt = endPtT.fPt;
165    if (newPt == oldPt) {
166        return;
167    }
168    SkPoint line[2] = { newPt, oldPt };
169    SkPathOpsBounds lineBounds;
170    lineBounds.setBounds(line, 2);
171    SkDLine aLine;
172    aLine.set(line);
173    SkOpContour* current = contourList;
174    do {
175        if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) {
176            continue;
177        }
178        SkOpSegment* segment = current->first();
179        do {
180            if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) {
181                continue;
182            }
183            if (newPt == segment->fPts[0]) {
184                continue;
185            }
186            if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
187                continue;
188            }
189            if (oldPt == segment->fPts[0]) {
190                continue;
191            }
192            if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
193                continue;
194            }
195            if (endPtT.contains(segment)) {
196                continue;
197            }
198            SkIntersections i;
199            switch (segment->fVerb) {
200                case SkPath::kLine_Verb: {
201                    SkDLine bLine;
202                    bLine.set(segment->fPts);
203                    i.intersect(bLine, aLine);
204                    } break;
205                case SkPath::kQuad_Verb: {
206                    SkDQuad bQuad;
207                    bQuad.set(segment->fPts);
208                    i.intersect(bQuad, aLine);
209                    } break;
210                case SkPath::kConic_Verb: {
211                    SkDConic bConic;
212                    bConic.set(segment->fPts, segment->fWeight);
213                    i.intersect(bConic, aLine);
214                    } break;
215                case SkPath::kCubic_Verb: {
216                    SkDCubic bCubic;
217                    bCubic.set(segment->fPts);
218                    i.intersect(bCubic, aLine);
219                    } break;
220                default:
221                    SkASSERT(0);
222            }
223            if (i.used()) {
224                SkASSERT(i.used() == 1);
225                SkASSERT(!zero_or_one(i[0][0]));
226                SkOpSpanBase* checkSpan = fHead.next();
227                while (!checkSpan->final()) {
228                    if (checkSpan->contains(segment)) {
229                        goto nextSegment;
230                    }
231                    checkSpan = checkSpan->upCast()->next();
232                }
233                SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias, allocator);
234                ptT->fPt = newPt;
235                endPtT.addOpp(ptT);
236            }
237    nextSegment:
238            ;
239        } while ((segment = segment->next()));
240    } while ((current = current->next()));
241}
242
243void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
244        SkPathWriter* path, bool active) const {
245    SkOpCurve edge;
246    const SkPoint* ePtr;
247    SkScalar eWeight;
248    if ((start == &fHead && end == &fTail) || (start == &fTail && end == &fHead)) {
249        ePtr = fPts;
250        eWeight = fWeight;
251    } else {
252    // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
253        subDivide(start, end, &edge);
254        ePtr = edge.fPts;
255        eWeight = edge.fWeight;
256    }
257    if (active) {
258        bool reverse = ePtr == fPts && start != &fHead;
259        if (reverse) {
260            path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
261            switch (fVerb) {
262                case SkPath::kLine_Verb:
263                    path->deferredLine(ePtr[0]);
264                    break;
265                case SkPath::kQuad_Verb:
266                    path->quadTo(ePtr[1], ePtr[0]);
267                    break;
268                case SkPath::kConic_Verb:
269                    path->conicTo(ePtr[1], ePtr[0], eWeight);
270                    break;
271                case SkPath::kCubic_Verb:
272                    path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
273                    break;
274                default:
275                    SkASSERT(0);
276            }
277       } else {
278            path->deferredMoveLine(ePtr[0]);
279            switch (fVerb) {
280                case SkPath::kLine_Verb:
281                    path->deferredLine(ePtr[1]);
282                    break;
283                case SkPath::kQuad_Verb:
284                    path->quadTo(ePtr[1], ePtr[2]);
285                    break;
286                case SkPath::kConic_Verb:
287                    path->conicTo(ePtr[1], ePtr[2], eWeight);
288                    break;
289                case SkPath::kCubic_Verb:
290                    path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
291                    break;
292                default:
293                    SkASSERT(0);
294            }
295        }
296    }
297}
298
299SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* allocator) {
300    SkOpSpanBase* existing = NULL;
301    SkOpSpanBase* test = &fHead;
302    double testT;
303    do {
304        if ((testT = test->ptT()->fT) >= t) {
305            if (testT == t) {
306                existing = test;
307            }
308            break;
309        }
310    } while ((test = test->upCast()->next()));
311    SkOpPtT* result;
312    if (existing && existing->contains(opp)) {
313        result = existing->ptT();
314    } else {
315        result = this->addT(t, SkOpSegment::kNoAlias, allocator);
316    }
317    SkASSERT(result);
318    return result;
319}
320
321SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* allocator) {
322    debugValidate();
323    SkPoint pt = this->ptAtT(t);
324    SkOpSpanBase* span = &fHead;
325    do {
326        SkOpPtT* result = span->ptT();
327        SkOpPtT* loop;
328        bool duplicatePt;
329        if (t == result->fT) {
330            goto bumpSpan;
331        }
332        if (this->match(result, this, t, pt)) {
333            // see if any existing alias matches segment, pt, and t
334           loop = result->next();
335            duplicatePt = false;
336            while (loop != result) {
337                bool ptMatch = loop->fPt == pt;
338                if (loop->segment() == this && loop->fT == t && ptMatch) {
339                    goto bumpSpan;
340                }
341                duplicatePt |= ptMatch;
342                loop = loop->next();
343            }
344            if (kNoAlias == allowAlias) {
345    bumpSpan:
346                span->bumpSpanAdds();
347                return result;
348            }
349            SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
350            alias->init(result->span(), t, pt, duplicatePt);
351            result->insert(alias);
352            result->span()->unaligned();
353            this->debugValidate();
354#if DEBUG_ADD_T
355            SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n",  __FUNCTION__, t,
356                    alias->segment()->debugID(), alias->span()->debugID());
357#endif
358            span->bumpSpanAdds();
359            return alias;
360        }
361        if (t < result->fT) {
362            SkOpSpan* prev = result->span()->prev();
363            SkOpSpan* span = insert(prev, allocator);
364            span->init(this, prev, t, pt);
365            this->debugValidate();
366#if DEBUG_ADD_T
367            SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
368                    span->segment()->debugID(), span->debugID());
369#endif
370            span->bumpSpanAdds();
371            return span->ptT();
372        }
373        SkASSERT(span != &fTail);
374    } while ((span = span->upCast()->next()));
375    SkASSERT(0);
376    return NULL;
377}
378
379// choose a solitary t and pt value; remove aliases; align the opposite ends
380void SkOpSegment::align() {
381    debugValidate();
382    SkOpSpanBase* span = &fHead;
383    if (!span->aligned()) {
384        span->alignEnd(0, fPts[0]);
385    }
386    while ((span = span->upCast()->next())) {
387        if (span == &fTail) {
388            break;
389        }
390        span->align();
391    }
392    if (!span->aligned()) {
393        span->alignEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
394    }
395    if (this->collapsed()) {
396        SkOpSpan* span = &fHead;
397        do {
398            span->setWindValue(0);
399            span->setOppValue(0);
400            this->markDone(span);
401        } while ((span = span->next()->upCastable()));
402    }
403    debugValidate();
404}
405
406void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
407    bool activePrior = !fHead.isCanceled();
408    if (activePrior && !fHead.simple()) {
409        addStartSpan(allocator);
410    }
411    SkOpSpan* prior = &fHead;
412    SkOpSpanBase* spanBase = fHead.next();
413    while (spanBase != &fTail) {
414        if (activePrior) {
415            SkOpAngle* priorAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
416            priorAngle->set(spanBase, prior);
417            spanBase->setFromAngle(priorAngle);
418        }
419        SkOpSpan* span = spanBase->upCast();
420        bool active = !span->isCanceled();
421        SkOpSpanBase* next = span->next();
422        if (active) {
423            SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
424            angle->set(span, next);
425            span->setToAngle(angle);
426        }
427        activePrior = active;
428        prior = span;
429        spanBase = next;
430    }
431    if (activePrior && !fTail.simple()) {
432        addEndSpan(allocator);
433    }
434}
435
436void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
437    SkOpSpanBase* base = &fHead;
438    SkOpSpan* span;
439    do {
440        SkOpAngle* angle = base->fromAngle();
441        if (angle && angle->fCheckCoincidence) {
442            angle->checkNearCoincidence();
443        }
444        if (base->final()) {
445             break;
446        }
447        span = base->upCast();
448        angle = span->toAngle();
449        if (angle && angle->fCheckCoincidence) {
450            angle->checkNearCoincidence();
451        }
452    } while ((base = span->next()));
453}
454
455bool SkOpSegment::collapsed() const {
456    return fVerb == SkPath::kLine_Verb && fHead.pt() == fTail.pt();
457}
458
459void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
460        SkOpAngle::IncludeType includeType) {
461    SkOpSegment* baseSegment = baseAngle->segment();
462    int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
463    int sumSuWinding;
464    bool binary = includeType >= SkOpAngle::kBinarySingle;
465    if (binary) {
466        sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
467        if (baseSegment->operand()) {
468            SkTSwap<int>(sumMiWinding, sumSuWinding);
469        }
470    }
471    SkOpSegment* nextSegment = nextAngle->segment();
472    int maxWinding, sumWinding;
473    SkOpSpanBase* last;
474    if (binary) {
475        int oppMaxWinding, oppSumWinding;
476        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
477                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
478        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
479                nextAngle);
480    } else {
481        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
482                &maxWinding, &sumWinding);
483        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
484    }
485    nextAngle->setLastMarked(last);
486}
487
488void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
489        SkOpAngle::IncludeType includeType) {
490    SkOpSegment* baseSegment = baseAngle->segment();
491    int sumMiWinding = baseSegment->updateWinding(baseAngle);
492    int sumSuWinding;
493    bool binary = includeType >= SkOpAngle::kBinarySingle;
494    if (binary) {
495        sumSuWinding = baseSegment->updateOppWinding(baseAngle);
496        if (baseSegment->operand()) {
497            SkTSwap<int>(sumMiWinding, sumSuWinding);
498        }
499    }
500    SkOpSegment* nextSegment = nextAngle->segment();
501    int maxWinding, sumWinding;
502    SkOpSpanBase* last;
503    if (binary) {
504        int oppMaxWinding, oppSumWinding;
505        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
506                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
507        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
508                nextAngle);
509    } else {
510        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
511                &maxWinding, &sumWinding);
512        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
513    }
514    nextAngle->setLastMarked(last);
515}
516
517// at this point, the span is already ordered, or unorderable
518int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
519        SkOpAngle::IncludeType includeType) {
520    SkASSERT(includeType != SkOpAngle::kUnaryXor);
521    SkOpAngle* firstAngle = this->spanToAngle(end, start);
522    if (NULL == firstAngle || NULL == firstAngle->next()) {
523        return SK_NaN32;
524    }
525    // if all angles have a computed winding,
526    //  or if no adjacent angles are orderable,
527    //  or if adjacent orderable angles have no computed winding,
528    //  there's nothing to do
529    // if two orderable angles are adjacent, and both are next to orderable angles,
530    //  and one has winding computed, transfer to the other
531    SkOpAngle* baseAngle = NULL;
532    bool tryReverse = false;
533    // look for counterclockwise transfers
534    SkOpAngle* angle = firstAngle->previous();
535    SkOpAngle* next = angle->next();
536    firstAngle = next;
537    do {
538        SkOpAngle* prior = angle;
539        angle = next;
540        next = angle->next();
541        SkASSERT(prior->next() == angle);
542        SkASSERT(angle->next() == next);
543        if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
544            baseAngle = NULL;
545            continue;
546        }
547        int testWinding = angle->starter()->windSum();
548        if (SK_MinS32 != testWinding) {
549            baseAngle = angle;
550            tryReverse = true;
551            continue;
552        }
553        if (baseAngle) {
554            ComputeOneSum(baseAngle, angle, includeType);
555            baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
556        }
557    } while (next != firstAngle);
558    if (baseAngle && SK_MinS32 == firstAngle->starter()->windSum()) {
559        firstAngle = baseAngle;
560        tryReverse = true;
561    }
562    if (tryReverse) {
563        baseAngle = NULL;
564        SkOpAngle* prior = firstAngle;
565        do {
566            angle = prior;
567            prior = angle->previous();
568            SkASSERT(prior->next() == angle);
569            next = angle->next();
570            if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
571                baseAngle = NULL;
572                continue;
573            }
574            int testWinding = angle->starter()->windSum();
575            if (SK_MinS32 != testWinding) {
576                baseAngle = angle;
577                continue;
578            }
579            if (baseAngle) {
580                ComputeOneSumReverse(baseAngle, angle, includeType);
581                baseAngle = SK_MinS32 != angle->starter()->windSum() ? angle : NULL;
582            }
583        } while (prior != firstAngle);
584    }
585    return start->starter(end)->windSum();
586}
587
588void SkOpSegment::detach(const SkOpSpan* span) {
589    if (span->done()) {
590        --fDoneCount;
591    }
592    --fCount;
593    SkASSERT(fCount >= fDoneCount);
594}
595
596double SkOpSegment::distSq(double t, SkOpAngle* oppAngle) {
597    SkDPoint testPt = this->dPtAtT(t);
598    SkDLine testPerp = {{ testPt, testPt }};
599    SkDVector slope = this->dSlopeAtT(t);
600    testPerp[1].fX += slope.fY;
601    testPerp[1].fY -= slope.fX;
602    SkIntersections i;
603    SkOpSegment* oppSegment = oppAngle->segment();
604    (*CurveIntersectRay[oppSegment->verb()])(oppSegment->pts(), oppSegment->weight(), testPerp, &i);
605    double closestDistSq = SK_ScalarInfinity;
606    for (int index = 0; index < i.used(); ++index) {
607        if (!between(oppAngle->start()->t(), i[0][index], oppAngle->end()->t())) {
608            continue;
609        }
610        double testDistSq = testPt.distanceSquared(i.pt(index));
611        if (closestDistSq > testDistSq) {
612            closestDistSq = testDistSq;
613        }
614    }
615    return closestDistSq;
616}
617
618/*
619 The M and S variable name parts stand for the operators.
620   Mi stands for Minuend (see wiki subtraction, analogous to difference)
621   Su stands for Subtrahend
622 The Opp variable name part designates that the value is for the Opposite operator.
623 Opposite values result from combining coincident spans.
624 */
625SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
626        SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask) {
627    SkOpSpanBase* start = *nextStart;
628    SkOpSpanBase* end = *nextEnd;
629    SkASSERT(start != end);
630    int step = start->step(end);
631    SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
632    if (other) {
633    // mark the smaller of startIndex, endIndex done, and all adjacent
634    // spans with the same T value (but not 'other' spans)
635#if DEBUG_WINDING
636        SkDebugf("%s simple\n", __FUNCTION__);
637#endif
638        SkOpSpan* startSpan = start->starter(end);
639        if (startSpan->done()) {
640            return NULL;
641        }
642        markDone(startSpan);
643        *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
644        return other;
645    }
646    SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
647    SkASSERT(endNear == end);  // is this ever not end?
648    SkASSERT(endNear);
649    SkASSERT(start != endNear);
650    SkASSERT((start->t() < endNear->t()) ^ (step < 0));
651    // more than one viable candidate -- measure angles to find best
652    int calcWinding = computeSum(start, endNear, SkOpAngle::kBinaryOpp);
653    bool sortable = calcWinding != SK_NaN32;
654    if (!sortable) {
655        *unsortable = true;
656        markDone(start->starter(end));
657        return NULL;
658    }
659    SkOpAngle* angle = this->spanToAngle(end, start);
660    if (angle->unorderable()) {
661        *unsortable = true;
662        markDone(start->starter(end));
663        return NULL;
664    }
665#if DEBUG_SORT
666    SkDebugf("%s\n", __FUNCTION__);
667    angle->debugLoop();
668#endif
669    int sumMiWinding = updateWinding(end, start);
670    if (sumMiWinding == SK_MinS32) {
671        *unsortable = true;
672        markDone(start->starter(end));
673        return NULL;
674    }
675    int sumSuWinding = updateOppWinding(end, start);
676    if (operand()) {
677        SkTSwap<int>(sumMiWinding, sumSuWinding);
678    }
679    SkOpAngle* nextAngle = angle->next();
680    const SkOpAngle* foundAngle = NULL;
681    bool foundDone = false;
682    // iterate through the angle, and compute everyone's winding
683    SkOpSegment* nextSegment;
684    int activeCount = 0;
685    do {
686        nextSegment = nextAngle->segment();
687        bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
688                nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
689        if (activeAngle) {
690            ++activeCount;
691            if (!foundAngle || (foundDone && activeCount & 1)) {
692                foundAngle = nextAngle;
693                foundDone = nextSegment->done(nextAngle);
694            }
695        }
696        if (nextSegment->done()) {
697            continue;
698        }
699        if (!activeAngle) {
700            (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
701        }
702        SkOpSpanBase* last = nextAngle->lastMarked();
703        if (last) {
704            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
705            *chase->append() = last;
706#if DEBUG_WINDING
707            SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
708                    last->segment()->debugID(), last->debugID());
709            if (!last->final()) {
710                SkDebugf(" windSum=%d", last->upCast()->windSum());
711            }
712            SkDebugf("\n");
713#endif
714        }
715    } while ((nextAngle = nextAngle->next()) != angle);
716    start->segment()->markDone(start->starter(end));
717    if (!foundAngle) {
718        return NULL;
719    }
720    *nextStart = foundAngle->start();
721    *nextEnd = foundAngle->end();
722    nextSegment = foundAngle->segment();
723#if DEBUG_WINDING
724    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
725            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
726 #endif
727    return nextSegment;
728}
729
730SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpanBase*>* chase,
731        SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable) {
732    SkOpSpanBase* start = *nextStart;
733    SkOpSpanBase* end = *nextEnd;
734    SkASSERT(start != end);
735    int step = start->step(end);
736    SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
737    if (other) {
738    // mark the smaller of startIndex, endIndex done, and all adjacent
739    // spans with the same T value (but not 'other' spans)
740#if DEBUG_WINDING
741        SkDebugf("%s simple\n", __FUNCTION__);
742#endif
743        SkOpSpan* startSpan = start->starter(end);
744        if (startSpan->done()) {
745            return NULL;
746        }
747        markDone(startSpan);
748        *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
749        return other;
750    }
751    SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
752    SkASSERT(endNear == end);  // is this ever not end?
753    SkASSERT(endNear);
754    SkASSERT(start != endNear);
755    SkASSERT((start->t() < endNear->t()) ^ (step < 0));
756    // more than one viable candidate -- measure angles to find best
757    int calcWinding = computeSum(start, endNear, SkOpAngle::kUnaryWinding);
758    bool sortable = calcWinding != SK_NaN32;
759    if (!sortable) {
760        *unsortable = true;
761        markDone(start->starter(end));
762        return NULL;
763    }
764    SkOpAngle* angle = this->spanToAngle(end, start);
765    if (angle->unorderable()) {
766        *unsortable = true;
767        markDone(start->starter(end));
768        return NULL;
769    }
770#if DEBUG_SORT
771    SkDebugf("%s\n", __FUNCTION__);
772    angle->debugLoop();
773#endif
774    int sumWinding = updateWinding(end, start);
775    SkOpAngle* nextAngle = angle->next();
776    const SkOpAngle* foundAngle = NULL;
777    bool foundDone = false;
778    // iterate through the angle, and compute everyone's winding
779    SkOpSegment* nextSegment;
780    int activeCount = 0;
781    do {
782        nextSegment = nextAngle->segment();
783        bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
784                &sumWinding);
785        if (activeAngle) {
786            ++activeCount;
787            if (!foundAngle || (foundDone && activeCount & 1)) {
788                foundAngle = nextAngle;
789                foundDone = nextSegment->done(nextAngle);
790            }
791        }
792        if (nextSegment->done()) {
793            continue;
794        }
795        if (!activeAngle) {
796            (void) nextSegment->markAndChaseDone(nextAngle->start(), nextAngle->end());
797        }
798        SkOpSpanBase* last = nextAngle->lastMarked();
799        if (last) {
800            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
801            *chase->append() = last;
802#if DEBUG_WINDING
803            SkDebugf("%s chase.append segment=%d span=%d", __FUNCTION__,
804                    last->segment()->debugID(), last->debugID());
805            if (!last->final()) {
806                SkDebugf(" windSum=%d", last->upCast()->windSum());
807            }
808            SkDebugf("\n");
809#endif
810        }
811    } while ((nextAngle = nextAngle->next()) != angle);
812    start->segment()->markDone(start->starter(end));
813    if (!foundAngle) {
814        return NULL;
815    }
816    *nextStart = foundAngle->start();
817    *nextEnd = foundAngle->end();
818    nextSegment = foundAngle->segment();
819#if DEBUG_WINDING
820    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
821            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
822 #endif
823    return nextSegment;
824}
825
826SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd,
827        bool* unsortable) {
828    SkOpSpanBase* start = *nextStart;
829    SkOpSpanBase* end = *nextEnd;
830    SkASSERT(start != end);
831    int step = start->step(end);
832    SkOpSegment* other = this->isSimple(nextStart, &step);  // advances nextStart
833    if (other) {
834    // mark the smaller of startIndex, endIndex done, and all adjacent
835    // spans with the same T value (but not 'other' spans)
836#if DEBUG_WINDING
837        SkDebugf("%s simple\n", __FUNCTION__);
838#endif
839        SkOpSpan* startSpan = start->starter(end);
840        if (startSpan->done()) {
841            return NULL;
842        }
843        markDone(startSpan);
844        *nextEnd = step > 0 ? (*nextStart)->upCast()->next() : (*nextStart)->prev();
845        return other;
846    }
847    SkDEBUGCODE(SkOpSpanBase* endNear = step > 0 ? (*nextStart)->upCast()->next() \
848            : (*nextStart)->prev());
849    SkASSERT(endNear == end);  // is this ever not end?
850    SkASSERT(endNear);
851    SkASSERT(start != endNear);
852    SkASSERT((start->t() < endNear->t()) ^ (step < 0));
853    SkOpAngle* angle = this->spanToAngle(end, start);
854    if (!angle || angle->unorderable()) {
855        *unsortable = true;
856        markDone(start->starter(end));
857        return NULL;
858    }
859#if DEBUG_SORT
860    SkDebugf("%s\n", __FUNCTION__);
861    angle->debugLoop();
862#endif
863    SkOpAngle* nextAngle = angle->next();
864    const SkOpAngle* foundAngle = NULL;
865    bool foundDone = false;
866    // iterate through the angle, and compute everyone's winding
867    SkOpSegment* nextSegment;
868    int activeCount = 0;
869    do {
870        nextSegment = nextAngle->segment();
871        ++activeCount;
872        if (!foundAngle || (foundDone && activeCount & 1)) {
873            foundAngle = nextAngle;
874            if (!(foundDone = nextSegment->done(nextAngle))) {
875                break;
876            }
877        }
878        nextAngle = nextAngle->next();
879    } while (nextAngle != angle);
880    start->segment()->markDone(start->starter(end));
881    if (!foundAngle) {
882        return NULL;
883    }
884    *nextStart = foundAngle->start();
885    *nextEnd = foundAngle->end();
886    nextSegment = foundAngle->segment();
887#if DEBUG_WINDING
888    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
889            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
890 #endif
891    return nextSegment;
892}
893
894SkOpGlobalState* SkOpSegment::globalState() const {
895    return contour()->globalState();
896}
897
898void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
899    fContour = contour;
900    fNext = NULL;
901    fOriginal[0] = pts[0];
902    fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)];
903    fPts = pts;
904    fWeight = weight;
905    fVerb = verb;
906    fCubicType = SkDCubic::kUnsplit_SkDCubicType;
907    fCount = 0;
908    fDoneCount = 0;
909    fTopsFound = false;
910    fVisited = false;
911    SkOpSpan* zeroSpan = &fHead;
912    zeroSpan->init(this, NULL, 0, fPts[0]);
913    SkOpSpanBase* oneSpan = &fTail;
914    zeroSpan->setNext(oneSpan);
915    oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]);
916    SkDEBUGCODE(fID = globalState()->nextSegmentID());
917}
918
919bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
920    SkDPoint cPt = this->dPtAtT(t);
921    SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
922    SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }};
923    SkIntersections i;
924    (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), perp, &i);
925    int used = i.used();
926    for (int index = 0; index < used; ++index) {
927        if (cPt.roughlyEqual(i.pt(index))) {
928            return true;
929        }
930    }
931    return false;
932}
933
934bool SkOpSegment::isXor() const {
935    return fContour->isXor();
936}
937
938void SkOpSegment::markAllDone() {
939    SkOpSpan* span = this->head();
940    do {
941        this->markDone(span);
942    } while ((span = span->next()->upCastable()));
943}
944
945SkOpSpanBase* SkOpSegment::markAndChaseDone(SkOpSpanBase* start, SkOpSpanBase* end) {
946    int step = start->step(end);
947    SkOpSpan* minSpan = start->starter(end);
948    markDone(minSpan);
949    SkOpSpanBase* last = NULL;
950    SkOpSegment* other = this;
951    while ((other = other->nextChase(&start, &step, &minSpan, &last))) {
952        if (other->done()) {
953            SkASSERT(!last);
954            break;
955        }
956        other->markDone(minSpan);
957    }
958    return last;
959}
960
961bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
962        SkOpSpanBase** lastPtr) {
963    SkOpSpan* spanStart = start->starter(end);
964    int step = start->step(end);
965    bool success = markWinding(spanStart, winding);
966    SkOpSpanBase* last = NULL;
967    SkOpSegment* other = this;
968    while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
969        if (spanStart->windSum() != SK_MinS32) {
970            SkASSERT(spanStart->windSum() == winding);
971            SkASSERT(!last);
972            break;
973        }
974        (void) other->markWinding(spanStart, winding);
975    }
976    if (lastPtr) {
977        *lastPtr = last;
978    }
979    return success;
980}
981
982bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
983        int winding, int oppWinding, SkOpSpanBase** lastPtr) {
984    SkOpSpan* spanStart = start->starter(end);
985    int step = start->step(end);
986    bool success = markWinding(spanStart, winding, oppWinding);
987    SkOpSpanBase* last = NULL;
988    SkOpSegment* other = this;
989    while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
990        if (spanStart->windSum() != SK_MinS32) {
991            if (this->operand() == other->operand()) {
992                if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
993                    this->globalState()->setWindingFailed();
994                    return false;
995                }
996            } else {
997                SkASSERT(spanStart->windSum() == oppWinding);
998                SkASSERT(spanStart->oppSum() == winding);
999            }
1000            SkASSERT(!last);
1001            break;
1002        }
1003        if (this->operand() == other->operand()) {
1004            (void) other->markWinding(spanStart, winding, oppWinding);
1005        } else {
1006            (void) other->markWinding(spanStart, oppWinding, winding);
1007        }
1008    }
1009    if (lastPtr) {
1010        *lastPtr = last;
1011    }
1012    return success;
1013}
1014
1015SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
1016    SkASSERT(angle->segment() == this);
1017    if (UseInnerWinding(maxWinding, sumWinding)) {
1018        maxWinding = sumWinding;
1019    }
1020    SkOpSpanBase* last;
1021    (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last);
1022#if DEBUG_WINDING
1023    if (last) {
1024        SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
1025                last->segment()->debugID(), last->debugID());
1026        if (!last->final()) {
1027            SkDebugf(" windSum=");
1028            SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1029        }
1030        SkDebugf("\n");
1031    }
1032#endif
1033    return last;
1034}
1035
1036SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
1037                                   int oppSumWinding, const SkOpAngle* angle) {
1038    SkASSERT(angle->segment() == this);
1039    if (UseInnerWinding(maxWinding, sumWinding)) {
1040        maxWinding = sumWinding;
1041    }
1042    if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
1043        oppMaxWinding = oppSumWinding;
1044    }
1045    SkOpSpanBase* last = NULL;
1046    // caller doesn't require that this marks anything
1047    (void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last);
1048#if DEBUG_WINDING
1049    if (last) {
1050        SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
1051                last->segment()->debugID(), last->debugID());
1052        if (!last->final()) {
1053            SkDebugf(" windSum=");
1054            SkPathOpsDebug::WindingPrintf(last->upCast()->windSum());
1055        }
1056        SkDebugf(" \n");
1057    }
1058#endif
1059    return last;
1060}
1061
1062void SkOpSegment::markDone(SkOpSpan* span) {
1063    SkASSERT(this == span->segment());
1064    if (span->done()) {
1065        return;
1066    }
1067#if DEBUG_MARK_DONE
1068    debugShowNewWinding(__FUNCTION__, span, span->windSum(), span->oppSum());
1069#endif
1070    span->setDone(true);
1071    ++fDoneCount;
1072    debugValidate();
1073}
1074
1075bool SkOpSegment::markWinding(SkOpSpan* span, int winding) {
1076    SkASSERT(this == span->segment());
1077    SkASSERT(winding);
1078    if (span->done()) {
1079        return false;
1080    }
1081#if DEBUG_MARK_DONE
1082    debugShowNewWinding(__FUNCTION__, span, winding);
1083#endif
1084    span->setWindSum(winding);
1085    debugValidate();
1086    return true;
1087}
1088
1089bool SkOpSegment::markWinding(SkOpSpan* span, int winding, int oppWinding) {
1090    SkASSERT(this == span->segment());
1091    SkASSERT(winding || oppWinding);
1092    if (span->done()) {
1093        return false;
1094    }
1095#if DEBUG_MARK_DONE
1096    debugShowNewWinding(__FUNCTION__, span, winding, oppWinding);
1097#endif
1098    span->setWindSum(winding);
1099    span->setOppSum(oppWinding);
1100    debugValidate();
1101    return true;
1102}
1103
1104bool SkOpSegment::match(const SkOpPtT* base, const SkOpSegment* testParent, double testT,
1105        const SkPoint& testPt) const {
1106    const SkOpSegment* baseParent = base->segment();
1107    if (this == baseParent && this == testParent && precisely_equal(base->fT, testT)) {
1108        return true;
1109    }
1110    if (!SkDPoint::ApproximatelyEqual(testPt, base->fPt)) {
1111        return false;
1112    }
1113    return !this->ptsDisjoint(base->fT, base->fPt, testT, testPt);
1114}
1115
1116static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
1117    if (last) {
1118        *last = endSpan;
1119    }
1120    return NULL;
1121}
1122
1123SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
1124        SkOpSpanBase** last) const {
1125    SkOpSpanBase* origStart = *startPtr;
1126    int step = *stepPtr;
1127    SkOpSpanBase* endSpan = step > 0 ? origStart->upCast()->next() : origStart->prev();
1128    SkASSERT(endSpan);
1129    SkOpAngle* angle = step > 0 ? endSpan->fromAngle() : endSpan->upCast()->toAngle();
1130    SkOpSpanBase* foundSpan;
1131    SkOpSpanBase* otherEnd;
1132    SkOpSegment* other;
1133    if (angle == NULL) {
1134        if (endSpan->t() != 0 && endSpan->t() != 1) {
1135            return NULL;
1136        }
1137        SkOpPtT* otherPtT = endSpan->ptT()->next();
1138        other = otherPtT->segment();
1139        foundSpan = otherPtT->span();
1140        otherEnd = step > 0 ? foundSpan->upCast()->next() : foundSpan->prev();
1141    } else {
1142        int loopCount = angle->loopCount();
1143        if (loopCount > 2) {
1144            return set_last(last, endSpan);
1145        }
1146        const SkOpAngle* next = angle->next();
1147        if (NULL == next) {
1148            return NULL;
1149        }
1150#if DEBUG_WINDING
1151        if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
1152                && !next->segment()->contour()->isXor()) {
1153            SkDebugf("%s mismatched signs\n", __FUNCTION__);
1154        }
1155#endif
1156        other = next->segment();
1157        foundSpan = endSpan = next->start();
1158        otherEnd = next->end();
1159    }
1160    int foundStep = foundSpan->step(otherEnd);
1161    if (*stepPtr != foundStep) {
1162        return set_last(last, endSpan);
1163    }
1164    SkASSERT(*startPtr);
1165    if (!otherEnd) {
1166        return NULL;
1167    }
1168//    SkASSERT(otherEnd >= 0);
1169    SkOpSpan* origMin = step < 0 ? origStart->prev() : origStart->upCast();
1170    SkOpSpan* foundMin = foundSpan->starter(otherEnd);
1171    if (foundMin->windValue() != origMin->windValue()
1172            || foundMin->oppValue() != origMin->oppValue()) {
1173          return set_last(last, endSpan);
1174    }
1175    *startPtr = foundSpan;
1176    *stepPtr = foundStep;
1177    if (minPtr) {
1178        *minPtr = foundMin;
1179    }
1180    return other;
1181}
1182
1183static void clear_visited(SkOpSpanBase* span) {
1184    // reset visited flag back to false
1185    do {
1186        SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1187        while ((ptT = ptT->next()) != stopPtT) {
1188            SkOpSegment* opp = ptT->segment();
1189            opp->resetVisited();
1190        }
1191    } while (!span->final() && (span = span->upCast()->next()));
1192}
1193
1194// look for pairs of undetected coincident curves
1195// assumes that segments going in have visited flag clear
1196// curve/curve intersection should now do a pretty good job of finding coincident runs so
1197// this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
1198// the opp is not a line
1199bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
1200    if (this->verb() != SkPath::kLine_Verb) {
1201        return false;
1202    }
1203    if (this->done()) {
1204        return false;
1205    }
1206    SkOpSpan* prior = NULL;
1207    SkOpSpanBase* spanBase = &fHead;
1208    do {
1209        SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
1210        SkASSERT(ptT->span() == spanBase);
1211        while ((ptT = ptT->next()) != spanStopPtT) {
1212            if (ptT->deleted()) {
1213                continue;
1214            }
1215            SkOpSegment* opp = ptT->span()->segment();
1216            if (opp->verb() == SkPath::kLine_Verb) {
1217                continue;
1218            }
1219            if (opp->done()) {
1220                continue;
1221            }
1222            // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
1223            if (!opp->visited()) {
1224                continue;
1225            }
1226            if (spanBase == &fHead) {
1227                continue;
1228            }
1229            SkOpSpan* span = spanBase->upCastable();
1230            // FIXME?: this assumes that if the opposite segment is coincident then no more
1231            // coincidence needs to be detected. This may not be true.
1232            if (span && span->containsCoincidence(opp)) {
1233                continue;
1234            }
1235            if (spanBase->containsCoinEnd(opp)) {
1236                continue;
1237            }
1238            SkOpPtT* priorPtT = NULL, * priorStopPtT;
1239            // find prior span containing opp segment
1240            SkOpSegment* priorOpp = NULL;
1241            SkOpSpan* priorTest = spanBase->prev();
1242            while (!priorOpp && priorTest) {
1243                priorStopPtT = priorPtT = priorTest->ptT();
1244                while ((priorPtT = priorPtT->next()) != priorStopPtT) {
1245                    if (priorPtT->deleted()) {
1246                        continue;
1247                    }
1248                    SkOpSegment* segment = priorPtT->span()->segment();
1249                    if (segment == opp) {
1250                        prior = priorTest;
1251                        priorOpp = opp;
1252                        break;
1253                    }
1254                }
1255                priorTest = priorTest->prev();
1256            }
1257            if (!priorOpp) {
1258                continue;
1259            }
1260            SkOpPtT* oppStart = prior->ptT();
1261            SkOpPtT* oppEnd = spanBase->ptT();
1262            bool swapped = priorPtT->fT > ptT->fT;
1263            if (swapped) {
1264                SkTSwap(priorPtT, ptT);
1265                SkTSwap(oppStart, oppEnd);
1266            }
1267            bool flipped = oppStart->fT > oppEnd->fT;
1268            bool coincident;
1269            if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
1270                goto swapBack;
1271            }
1272            coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
1273            if (coincident) {
1274            // mark coincidence
1275                if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)
1276                        && !coincidences->extend(oppStart, oppEnd, priorPtT, ptT)) {
1277                    coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
1278                }
1279                clear_visited(&fHead);
1280                return true;
1281            }
1282    swapBack:
1283            if (swapped) {
1284                SkTSwap(priorPtT, ptT);
1285            }
1286        }
1287    } while ((spanBase = spanBase->final() ? NULL : spanBase->upCast()->next()));
1288    clear_visited(&fHead);
1289    return false;
1290}
1291
1292// if a span has more than one intersection, merge the other segments' span as needed
1293void SkOpSegment::moveMultiples() {
1294    debugValidate();
1295    SkOpSpanBase* test = &fHead;
1296    do {
1297        int addCount = test->spanAddsCount();
1298        SkASSERT(addCount >= 1);
1299        if (addCount == 1) {
1300            continue;
1301        }
1302        SkOpPtT* startPtT = test->ptT();
1303        SkOpPtT* testPtT = startPtT;
1304        do {  // iterate through all spans associated with start
1305            SkOpSpanBase* oppSpan = testPtT->span();
1306            if (oppSpan->spanAddsCount() == addCount) {
1307                continue;
1308            }
1309            if (oppSpan->deleted()) {
1310                continue;
1311            }
1312            SkOpSegment* oppSegment = oppSpan->segment();
1313            if (oppSegment == this) {
1314                continue;
1315            }
1316            // find range of spans to consider merging
1317            SkOpSpanBase* oppPrev = oppSpan;
1318            SkOpSpanBase* oppFirst = oppSpan;
1319            while ((oppPrev = oppPrev->prev())) {
1320                if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
1321                    break;
1322                }
1323                if (oppPrev->spanAddsCount() == addCount) {
1324                    continue;
1325                }
1326                if (oppPrev->deleted()) {
1327                    continue;
1328                }
1329                oppFirst = oppPrev;
1330            }
1331            SkOpSpanBase* oppNext = oppSpan;
1332            SkOpSpanBase* oppLast = oppSpan;
1333            while ((oppNext = oppNext->final() ? NULL : oppNext->upCast()->next())) {
1334                if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1335                    break;
1336                }
1337                if (oppNext->spanAddsCount() == addCount) {
1338                    continue;
1339                }
1340                if (oppNext->deleted()) {
1341                    continue;
1342                }
1343                oppLast = oppNext;
1344            }
1345            if (oppFirst == oppLast) {
1346                continue;
1347            }
1348            SkOpSpanBase* oppTest = oppFirst;
1349            do {
1350                if (oppTest == oppSpan) {
1351                    continue;
1352                }
1353                // check to see if the candidate meets specific criteria:
1354                // it contains spans of segments in test's loop but not including 'this'
1355                SkOpPtT* oppStartPtT = oppTest->ptT();
1356                SkOpPtT* oppPtT = oppStartPtT;
1357                while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1358                    SkOpSegment* oppPtTSegment = oppPtT->segment();
1359                    if (oppPtTSegment == this) {
1360                        goto tryNextSpan;
1361                    }
1362                    SkOpPtT* matchPtT = startPtT;
1363                    do {
1364                        if (matchPtT->segment() == oppPtTSegment) {
1365                            goto foundMatch;
1366                        }
1367                    } while ((matchPtT = matchPtT->next()) != startPtT);
1368                    goto tryNextSpan;
1369            foundMatch:  // merge oppTest and oppSpan
1370                    oppSegment->debugValidate();
1371                    if (oppTest == &oppSegment->fTail || oppTest == &oppSegment->fHead) {
1372                        SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
1373                        SkASSERT(oppSpan != &oppSegment->fTail);
1374                        oppTest->merge(oppSpan->upCast());
1375                    } else {
1376                        oppSpan->merge(oppTest->upCast());
1377                    }
1378                    oppSegment->debugValidate();
1379                    goto checkNextSpan;
1380                }
1381        tryNextSpan:
1382                ;
1383            } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1384        } while ((testPtT = testPtT->next()) != startPtT);
1385checkNextSpan:
1386        ;
1387    } while ((test = test->final() ? NULL : test->upCast()->next()));
1388    debugValidate();
1389}
1390
1391// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
1392void SkOpSegment::moveNearby() {
1393    debugValidate();
1394    SkOpSpanBase* spanS = &fHead;
1395    do {
1396        SkOpSpanBase* test = spanS->upCast()->next();
1397        SkOpSpanBase* next;
1398        if (spanS->contains(test)) {
1399            if (!test->final()) {
1400                test->upCast()->detach(spanS->ptT());
1401                continue;
1402            } else if (spanS != &fHead) {
1403                spanS->upCast()->detach(test->ptT());
1404                spanS = test;
1405                continue;
1406            }
1407        }
1408        do {  // iterate through all spans associated with start
1409            SkOpPtT* startBase = spanS->ptT();
1410            next = test->final() ? NULL : test->upCast()->next();
1411            do {
1412                SkOpPtT* testBase = test->ptT();
1413                do {
1414                    if (startBase == testBase) {
1415                        goto checkNextSpan;
1416                    }
1417                    if (testBase->duplicate()) {
1418                        continue;
1419                    }
1420                    if (this->match(startBase, testBase->segment(), testBase->fT, testBase->fPt)) {
1421                        if (test == &this->fTail) {
1422                            if (spanS == &fHead) {
1423                                debugValidate();
1424                                return;  // if this span has collapsed, remove it from parent
1425                            }
1426                            this->fTail.merge(spanS->upCast());
1427                            debugValidate();
1428                            return;
1429                        }
1430                        spanS->merge(test->upCast());
1431                        spanS->upCast()->setNext(next);
1432                        goto checkNextSpan;
1433                    }
1434                } while ((testBase = testBase->next()) != test->ptT());
1435            } while ((startBase = startBase->next()) != spanS->ptT());
1436    checkNextSpan:
1437            ;
1438        } while ((test = next));
1439        spanS = spanS->upCast()->next();
1440    } while (!spanS->final());
1441    debugValidate();
1442}
1443
1444bool SkOpSegment::operand() const {
1445    return fContour->operand();
1446}
1447
1448bool SkOpSegment::oppXor() const {
1449    return fContour->oppXor();
1450}
1451
1452bool SkOpSegment::ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const {
1453    if (fVerb == SkPath::kLine_Verb) {
1454        return false;
1455    }
1456    // quads (and cubics) can loop back to nearly a line so that an opposite curve
1457    // hits in two places with very different t values.
1458    // OPTIMIZATION: curves could be preflighted so that, for example, something like
1459    // 'controls contained by ends' could avoid this check for common curves
1460    // 'ends are extremes in x or y' is cheaper to compute and real-world common
1461    // on the other hand, the below check is relatively inexpensive
1462    double midT = (t1 + t2) / 2;
1463    SkPoint midPt = this->ptAtT(midT);
1464    double seDistSq = SkTMax(pt1.distanceToSqd(pt2) * 2, FLT_EPSILON * 2);
1465    return midPt.distanceToSqd(pt1) > seDistSq || midPt.distanceToSqd(pt2) > seDistSq;
1466}
1467
1468void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1469        int* maxWinding, int* sumWinding) {
1470    int deltaSum = SpanSign(start, end);
1471    *maxWinding = *sumMiWinding;
1472    *sumWinding = *sumMiWinding -= deltaSum;
1473    SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1474}
1475
1476void SkOpSegment::setUpWindings(SkOpSpanBase* start, SkOpSpanBase* end, int* sumMiWinding,
1477        int* sumSuWinding, int* maxWinding, int* sumWinding, int* oppMaxWinding,
1478        int* oppSumWinding) {
1479    int deltaSum = SpanSign(start, end);
1480    int oppDeltaSum = OppSign(start, end);
1481    if (operand()) {
1482        *maxWinding = *sumSuWinding;
1483        *sumWinding = *sumSuWinding -= deltaSum;
1484        *oppMaxWinding = *sumMiWinding;
1485        *oppSumWinding = *sumMiWinding -= oppDeltaSum;
1486    } else {
1487        *maxWinding = *sumMiWinding;
1488        *sumWinding = *sumMiWinding -= deltaSum;
1489        *oppMaxWinding = *sumSuWinding;
1490        *oppSumWinding = *sumSuWinding -= oppDeltaSum;
1491    }
1492    SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
1493    SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
1494}
1495
1496void SkOpSegment::sortAngles() {
1497    SkOpSpanBase* span = &this->fHead;
1498    do {
1499        SkOpAngle* fromAngle = span->fromAngle();
1500        SkOpAngle* toAngle = span->final() ? NULL : span->upCast()->toAngle();
1501        if (!fromAngle && !toAngle) {
1502            continue;
1503        }
1504#if DEBUG_ANGLE
1505        bool wroteAfterHeader = false;
1506#endif
1507        SkOpAngle* baseAngle = fromAngle;
1508        if (fromAngle && toAngle) {
1509#if DEBUG_ANGLE
1510            SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), span->t(),
1511                    span->debugID());
1512            wroteAfterHeader = true;
1513#endif
1514            fromAngle->insert(toAngle);
1515        } else if (!fromAngle) {
1516            baseAngle = toAngle;
1517        }
1518        SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
1519        do {
1520            SkOpSpanBase* oSpan = ptT->span();
1521            if (oSpan == span) {
1522                continue;
1523            }
1524            SkOpAngle* oAngle = oSpan->fromAngle();
1525            if (oAngle) {
1526#if DEBUG_ANGLE
1527                if (!wroteAfterHeader) {
1528                    SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1529                            span->t(), span->debugID());
1530                    wroteAfterHeader = true;
1531                }
1532#endif
1533                if (!oAngle->loopContains(baseAngle)) {
1534                    baseAngle->insert(oAngle);
1535                }
1536            }
1537            if (!oSpan->final()) {
1538                oAngle = oSpan->upCast()->toAngle();
1539                if (oAngle) {
1540#if DEBUG_ANGLE
1541                    if (!wroteAfterHeader) {
1542                        SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(),
1543                                span->t(), span->debugID());
1544                        wroteAfterHeader = true;
1545                    }
1546#endif
1547                    if (!oAngle->loopContains(baseAngle)) {
1548                        baseAngle->insert(oAngle);
1549                    }
1550                }
1551            }
1552        } while ((ptT = ptT->next()) != stopPtT);
1553        if (baseAngle->loopCount() == 1) {
1554            span->setFromAngle(NULL);
1555            if (toAngle) {
1556                span->upCast()->setToAngle(NULL);
1557            }
1558            baseAngle = NULL;
1559        }
1560#if DEBUG_SORT
1561        SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
1562#endif
1563    } while (!span->final() && (span = span->upCast()->next()));
1564}
1565
1566// return true if midpoints were computed
1567bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
1568        SkOpCurve* edge) const {
1569    SkASSERT(start != end);
1570    const SkOpPtT& startPtT = *start->ptT();
1571    const SkOpPtT& endPtT = *end->ptT();
1572    SkDEBUGCODE(edge->fVerb = fVerb);
1573    edge->fPts[0] = startPtT.fPt;
1574    int points = SkPathOpsVerbToPoints(fVerb);
1575    edge->fPts[points] = endPtT.fPt;
1576    edge->fWeight = 1;
1577    if (fVerb == SkPath::kLine_Verb) {
1578        return false;
1579    }
1580    double startT = startPtT.fT;
1581    double endT = endPtT.fT;
1582    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1583        // don't compute midpoints if we already have them
1584        if (fVerb == SkPath::kQuad_Verb) {
1585            edge->fPts[1] = fPts[1];
1586            return false;
1587        }
1588        if (fVerb == SkPath::kConic_Verb) {
1589            edge->fPts[1] = fPts[1];
1590            edge->fWeight = fWeight;
1591            return false;
1592        }
1593        SkASSERT(fVerb == SkPath::kCubic_Verb);
1594        if (start < end) {
1595            edge->fPts[1] = fPts[1];
1596            edge->fPts[2] = fPts[2];
1597            return false;
1598        }
1599        edge->fPts[1] = fPts[2];
1600        edge->fPts[2] = fPts[1];
1601        return false;
1602    }
1603    const SkDPoint sub[2] = {{ edge->fPts[0].fX, edge->fPts[0].fY},
1604            {edge->fPts[points].fX, edge->fPts[points].fY }};
1605    if (fVerb == SkPath::kQuad_Verb) {
1606        edge->fPts[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
1607    } else if (fVerb == SkPath::kConic_Verb) {
1608        edge->fPts[1] = SkDConic::SubDivide(fPts, fWeight, sub[0], sub[1],
1609                startT, endT, &edge->fWeight).asSkPoint();
1610    } else {
1611        SkASSERT(fVerb == SkPath::kCubic_Verb);
1612        SkDPoint ctrl[2];
1613        SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
1614        edge->fPts[1] = ctrl[0].asSkPoint();
1615        edge->fPts[2] = ctrl[1].asSkPoint();
1616    }
1617    return true;
1618}
1619
1620bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
1621        SkDCurve* edge) const {
1622    SkASSERT(start != end);
1623    const SkOpPtT& startPtT = *start->ptT();
1624    const SkOpPtT& endPtT = *end->ptT();
1625    SkDEBUGCODE(edge->fVerb = fVerb);
1626    edge->fCubic[0].set(startPtT.fPt);
1627    int points = SkPathOpsVerbToPoints(fVerb);
1628    edge->fCubic[points].set(endPtT.fPt);
1629    if (fVerb == SkPath::kLine_Verb) {
1630        return false;
1631    }
1632    double startT = startPtT.fT;
1633    double endT = endPtT.fT;
1634    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
1635        // don't compute midpoints if we already have them
1636        if (fVerb == SkPath::kQuad_Verb) {
1637            edge->fLine[1].set(fPts[1]);
1638            return false;
1639        }
1640        if (fVerb == SkPath::kConic_Verb) {
1641            edge->fConic[1].set(fPts[1]);
1642            edge->fConic.fWeight = fWeight;
1643            return false;
1644        }
1645        SkASSERT(fVerb == SkPath::kCubic_Verb);
1646        if (startT == 0) {
1647            edge->fCubic[1].set(fPts[1]);
1648            edge->fCubic[2].set(fPts[2]);
1649            return false;
1650        }
1651        edge->fCubic[1].set(fPts[2]);
1652        edge->fCubic[2].set(fPts[1]);
1653        return false;
1654    }
1655    if (fVerb == SkPath::kQuad_Verb) {
1656        edge->fQuad[1] = SkDQuad::SubDivide(fPts, edge->fQuad[0], edge->fQuad[2], startT, endT);
1657    } else if (fVerb == SkPath::kConic_Verb) {
1658        edge->fConic[1] = SkDConic::SubDivide(fPts, fWeight, edge->fQuad[0], edge->fQuad[2],
1659            startT, endT, &edge->fConic.fWeight);
1660    } else {
1661        SkASSERT(fVerb == SkPath::kCubic_Verb);
1662        SkDCubic::SubDivide(fPts, edge->fCubic[0], edge->fCubic[3], startT, endT, &edge->fCubic[1]);
1663    }
1664    return true;
1665}
1666
1667bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
1668        const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp,
1669        SkScalar flatnessLimit) const {
1670    // average t, find mid pt
1671    double midT = (prior->t() + spanBase->t()) / 2;
1672    SkPoint midPt = this->ptAtT(midT);
1673    bool coincident = true;
1674    // if the mid pt is not near either end pt, project perpendicular through opp seg
1675    if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
1676            && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
1677        coincident = false;
1678        SkIntersections i;
1679        SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
1680        SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
1681        (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
1682        // measure distance and see if it's small enough to denote coincidence
1683        for (int index = 0; index < i.used(); ++index) {
1684            SkDPoint oppPt = i.pt(index);
1685            if (oppPt.approximatelyEqual(midPt)) {
1686                SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
1687                        opp->weight(), i[index][0]);
1688                oppDxdy.normalize();
1689                dxdy.normalize();
1690                SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
1691                coincident |= flatness < flatnessLimit;
1692            }
1693        }
1694    }
1695    return coincident;
1696}
1697
1698void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
1699    SkOpSpan* span = this->head();
1700    do {
1701        if (!span->done()) {
1702            break;
1703        }
1704    } while ((span = span->next()->upCastable()));
1705    SkASSERT(span);
1706    *start = span;
1707    *end = span->next();
1708}
1709
1710int SkOpSegment::updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
1711    const SkOpSpan* lesser = start->starter(end);
1712    int oppWinding = lesser->oppSum();
1713    int oppSpanWinding = SkOpSegment::OppSign(start, end);
1714    if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
1715            && oppWinding != SK_MaxS32) {
1716        oppWinding -= oppSpanWinding;
1717    }
1718    return oppWinding;
1719}
1720
1721int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
1722    const SkOpSpanBase* startSpan = angle->start();
1723    const SkOpSpanBase* endSpan = angle->end();
1724    return updateOppWinding(endSpan, startSpan);
1725}
1726
1727int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
1728    const SkOpSpanBase* startSpan = angle->start();
1729    const SkOpSpanBase* endSpan = angle->end();
1730    return updateOppWinding(startSpan, endSpan);
1731}
1732
1733int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
1734    SkOpSpan* lesser = start->starter(end);
1735    int winding = lesser->windSum();
1736    if (winding == SK_MinS32) {
1737        winding = lesser->computeWindSum();
1738    }
1739    if (winding == SK_MinS32) {
1740        return winding;
1741    }
1742    int spanWinding = SkOpSegment::SpanSign(start, end);
1743    if (winding && UseInnerWinding(winding - spanWinding, winding)
1744            && winding != SK_MaxS32) {
1745        winding -= spanWinding;
1746    }
1747    return winding;
1748}
1749
1750int SkOpSegment::updateWinding(SkOpAngle* angle) {
1751    SkOpSpanBase* startSpan = angle->start();
1752    SkOpSpanBase* endSpan = angle->end();
1753    return updateWinding(endSpan, startSpan);
1754}
1755
1756int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
1757    SkOpSpanBase* startSpan = angle->start();
1758    SkOpSpanBase* endSpan = angle->end();
1759    return updateWinding(startSpan, endSpan);
1760}
1761
1762// OPTIMIZATION: does the following also work, and is it any faster?
1763// return outerWinding * innerWinding > 0
1764//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
1765bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
1766    SkASSERT(outerWinding != SK_MaxS32);
1767    SkASSERT(innerWinding != SK_MaxS32);
1768    int absOut = abs(outerWinding);
1769    int absIn = abs(innerWinding);
1770    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
1771    return result;
1772}
1773
1774int SkOpSegment::windSum(const SkOpAngle* angle) const {
1775    const SkOpSpan* minSpan = angle->start()->starter(angle->end());
1776    return minSpan->windSum();
1777}
1778